4

Entity Framework Code First を使用しています。System.Data.Common.DbConnectionから派生したコンテキストをインスタンス化するときに、オブジェクトを注入できるようにしたいと考えていますSystem.Data.Entity.DbContext。これは、コードが実行されている環境に応じて、さまざまな種類の接続を渡すことができるようにするためです。つまりSystem.Data.SqlClient、開発では (SQL Server) を使用し、System.Data.SQLite単体テストでは (SQL Server を) 使用し、本番環境では何か他のものを使用します。の関連部分はContext次のようになります。

public class Context : DbContext
{
    public Context(DbConnection dbConnection)
        : base(dbConnection, true)
    {
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        Database.SetInitializer(new MigrateDatabaseToLatestVersion<Context, Configuration>());

        base.OnModelCreating(modelBuilder);
    }

    public DbSet<Test> Tests { get; set; }
}

それは私に次のエラーを与えます:私が達成しようとしているIoCパターンとは無関係に、The target context 'Services.Persistence.Context' is not constructible. Add a default constructor or provide an implementation of IDbContextFactory.モデルの初期化中にEntity Frameworkが明らかにそれ自身のものを新しくする必要があると感じたときにこれが起こると思います。Context既定のコンストラクターがないのは、設計によるものです。IDbContextFactoryインターフェースも同様に役に立たない - デフォルトのコンストラクターも必要です。

Entity Framework Code First は、構成ファイルから接続文字列を読み取る (または、接続文字列を直接渡す) ことによってその構成を設定するという考えに完全に固執していますか、それともこれを回避できますか?

UPDATE、ここにウィンザーの設定があります:

container.Register(Component
    .For<DbConnection>()
    .UsingFactoryMethod(() =>
        new SqlConnection("Data Source=(localdb)\\v11.0;Database=ThatProject;MultipleActiveResultSets=true"))
    .LifeStyle.Transient);

container.Register(Component
    .For<Context>()
    .UsingFactoryMethod(k => new Context(k.Resolve<DbConnection>()))
    .LifeStyle.PerWebRequest);

container.Register(Component
    .For<IRepository>()
    .UsingFactoryMethod(k => new Repository(k.Resolve<Context>()))
    .LifeStyle.PerWebRequest);
4

1 に答える 1

2

あなたの問題はEFとは何の関係もないと確信していますが、私はWindsorのユーザーではないので、構成の問題が何であるかを確実に伝えることはできません. 私が行ったことは、あなたが期待したとおりに動作する ninject で同様の構成を再現することです。以下を参照してください。

class Program
    {
        static void Main(string[] args)
        {
            IKernel kernel = new StandardKernel();
            kernel.Bind<DbConnection>().ToMethod((ctx) =>{return new SqlConnection("Data Source=(localdb)\\v11.0;Database=ThatProject;MultipleActiveResultSets=true");});
            kernel.Bind<Context>().ToSelf();//not really needed
            kernel.Bind<TestRepository>().ToSelf();//not really needed
            kernel.Get<TestRepository>();
        }
    }
    public class Context : DbContext
    {
        public Context(DbConnection dbConnection)
            : base(dbConnection, true){}

        public DbSet<Test> Tests { get; set; }
    }
    public class TestRepository
    {
        public TestRepository(Context c)
        {
            c.Tests.Add(new Test());
            c.SaveChanges();

            var all = c.Tests;
        }
    }
    public class Test
    {
        public int Id { get; set; }
    }

これは、EF がコンテキスト作成でファンキーさを試みていないことを意味します (空でないコンストラクターは私にとってはうまく機能するため)。

あなたのウィンザー設定から、次のようなことをする必要があると思いますが、正確な構文はよくわかりません:

container.Register(Component
    .For<DbConnection>()
    .UsingFactoryMethod(() =>
        new SqlConnection("Data Source=(localdb)\\v11.0;Database=ThatProject;MultipleActiveResultSets=true"))
    .LifeStyle.Transient);

container.Register(Component
    .For<Context>()
    .ImplementedBySelf()//this probably isn't the correct syntax
    .LifeStyle.PerWebRequest);//per request is good, i have some details around why this is good practice if you are interested

container.Register(Component
    .For<IRepository>()
    .ImplementedBy<ConcreteRepository>()//you arent really calling a method and creating the object yourself you are letting Windsor create the object and sort out the dependancy tree
    .LifeStyle.PerWebRequest);
于 2012-10-01T05:50:28.070 に答える