The correct way to profile DbContext using MiniProfiler and EF 5 and Autofac

The MiniProfiler website provides the following code for creating the Entity Framework ObjectContext :

 public static MyModel Get() { var conn = new StackExchange.Profiling.Data.EFProfiledDbConnection(GetConnection(), MiniProfiler.Current); return ObjectContextUtils.CreateObjectContext<MyModel>(conn); // resides in the MiniProfiler.EF nuget pack } 

However, using Entity Framework 5, I am not using ObjectContext - rather, I am using DbContext . I cannot include the model name here, since the CreateObjectContext<T>() method expects T to be of type ObjectContext . (For the same reason, the code provided in this answer also does not work).

In addition, I use autofac to initialize my Db connections. This is logged as follows ( MyData = name of my EF DataContext):

 Builder.RegisterType<MyData>().As<DbContext>().InstancePerHttpRequest(); 

So combining two parts: how can I use autofac to initialize my DbContext associated with MiniProfiler.EF? And if that is not possible, at least how can I do the first part (create factory method for MiniProfiler.EF to return DbContext )?

+6
source share
2 answers

There is a constructor for the DbContext class that accepts an existing DbConnection

So you need a new contructor on your MyData that just calls the base

 public class MyData : DbContext { public MyData(DbConnection existingConnection, bool contextOwnsConnection) : base(existingConnection, contextOwnsConnection) { } //.. } 

Then you register your MyData using Register :

 builder.Register(c => { var conn = new EFProfiledDbConnection(GetConnection(), MiniProfiler.Current); return new MyData(conn, true); }).As<DbContext>().InstancePerHttpRequest(); 
+6
source

I just got this job:

 public static class DbContextUtils { private const BindingFlags PrivateInstance = BindingFlags.NonPublic | BindingFlags.Instance; public static T CreateDbContext<T>() where T : DbContext { return CreateDbContext<T>(GetProfiledConnection<T>()); } public static T CreateDbContext<T>(this DbConnection connection) where T : DbContext { var workspace = new MetadataWorkspace(new[] { "res://*/" }, new[] { typeof(T).Assembly }); var factory = DbProviderServices.GetProviderFactory(connection); var itemCollection = workspace.GetItemCollection(DataSpace.SSpace); var providerFactoryField = itemCollection.GetType().GetField("_providerFactory", PrivateInstance); if (providerFactoryField != null) providerFactoryField.SetValue(itemCollection, factory); var ec = new EntityConnection(workspace, connection); return CtorCache<T, DbConnection>.Ctor(ec); } public static DbConnection GetProfiledConnection<T>() where T : DbContext { var dbConnection = ObjectContextUtils.GetStoreConnection("name=" + typeof(T).Name); return new EFProfiledDbConnection(dbConnection, MiniProfiler.Current); } internal static class CtorCache<TType, TArg> where TType : class { public static readonly Func<TArg, TType> Ctor; static CtorCache() { var argTypes = new[] { typeof(TArg) }; var ctor = typeof(TType).GetConstructor(argTypes); if (ctor == null) { Ctor = x => { throw new InvalidOperationException("No suitable constructor defined"); }; } else { var dm = new DynamicMethod("ctor", typeof(TType), argTypes); var il = dm.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Newobj, ctor); il.Emit(OpCodes.Ret); Ctor = (Func<TArg, TType>)dm.CreateDelegate(typeof(Func<TArg, TType>)); } } } } 

It is based on code in MiniProfiler ObjectContextUtils .

You use it as follows:

 builder.Register(c => DbContextUtils.CreateDbContext<MyData>()).As<DbContext>().InstancePerHttpRequest(); 

This solution DbContext your DbContext in order to have a constructor that takes a DbConnection and passes it to the base, for example:

 public MyData(DbConnection connection) : base(connection, true) { } 
+11
source

All Articles