4

我使用實體框架代碼第一。在實例化從System.Data.Entity.DbContext派生的上下文時,我希望能夠注入一個System.Data.Common.DbConnection對象。這樣我就可以通過不同類型的連接,具體取決於代碼運行的環境,即在開發中使用System.Data.SqlClient(SQL Server),在單元測試和其他生產環境中使用System.Data.SQLite。的Context的相關部分看起來是這樣的:EF代碼第一,IoC和DbConnection

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

這給了我以下錯誤:The target context 'Services.Persistence.Context' is not constructible. Add a default constructor or provide an implementation of IDbContextFactory.我認爲模型初始化過程中發生這種情況時,實體框架顯然認爲它需要新的了它自己的Context,獨立於IOC模式我正在努力實現。缺少默認的構造函數是由設計決定的。 IDbContextFactory接口也是沒用的 - 它也必須有一個默認的構造函數。

實體框架代碼首先完全通過從配置文件中讀取連接字符串(或者直接傳遞連接字符串)來設置它的配置,或者可以解決這個問題?

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); 
+0

哪些IoC容器您使用的?這種類型的配置是什麼? –

+0

Windsor,'Context'應該最好是PerWebRequest。 – friism

+0

我的意思是,你使用的實際配置是什麼?你如何配置DbConnection傳入? –

回答

2

我敢肯定你的問題是無關的EF,但我真的不溫莎的用戶,所以我不能告訴你肯定你的配置問題是什麼。我所做的就是重現與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是不是想用做上下文創建任何funkiness(如非空的構造函數適合我)。

從你的溫莎配置我希望你需要做類似下面的即時但是不太知道確切的語法:

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); 
+1

事實證明,只有啓用自動遷移時纔會出現問題,我已將其添加到代碼示例中。 – friism