6

MiniProfilerサイトは、 EntityFrameworkを生成するための次のコードを提供します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
}

ただし、Entity Framework 5を使用しているので、ObjectContext-を使用していません。むしろ。を使用していDbContextます。メソッドはタイプをCreateObjectContext<T>()想定しているため、ここにモデル名をプラグインすることはできません。(同じ理由で、この回答に示されているコードも機能しません)。TObjectContext

さらに、autofacを使用してDb接続を初期化しています。これは次のように登録されています(MyData=私のEF DataContextの名前):

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

したがって、2つの部分を組み合わせる:autofacを使用してMiniProfiler.EFに関連付けられたDbContextを初期化するにはどうすればよいですか?そしてそれが不可能な場合、少なくとも最初の部分をどのように行うことができますか(MiniProfiler.EFが返すファクトリメソッドを作成しますDbContext)?

4

2 に答える 2

11

私はこれを機能させました:

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>));
            }
        }
    }
}

これは、 MiniProfilerのObjectContextUtilsコードに基づいています。

次のように使用します。

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

このソリューションでは、次のように、を取得してベースに渡すDbContextコンストラクターが必要です。DbConnection

public MyData(DbConnection connection)
    : base(connection, true)
{
}
于 2012-11-21T17:05:59.523 に答える
6

既存のものを取るクラスのコンストラクタがありますDbContextDbConnection

だからあなたはMyDataただベースを呼ぶあなたの新しい建設業者が必要です

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

    //..
}

MyData次に、に登録しますRegister

builder.Register(c => 
{
   var conn =  new EFProfiledDbConnection(GetConnection(), MiniProfiler.Current);
   return new MyData(conn, true);
}).As<DbContext>().InstancePerHttpRequest();
于 2012-11-21T16:31:20.717 に答える