实体框架 – EF Code First,IoC和DbConnection

我正在使用Entity Framework Code First.我希望能够在实例化从System.Data.Entity.DbContext派生的上下文时注入System.Data.Common.DbConnection对象.这样我就可以根据运行代码的环境传递不同类型的连接,即在开发时使用System.Data.SqlClient(SQL Server),在生产时使用System.Data.SQLite进行单元测试. 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; }
}

这给了我以下错误:目标上下文’Services.Persistence.Context’不可构造.添加默认构造函数或提供IDbContextFactory的实现.我认为这发生在模型初始化期间,当Entity Framework明显感觉它需要新建它自己的Context时,独立于我想要实现的IoC模式.缺少默认构造函数是设计使然. IDbContextFactory接口同样没用 – 它也必须有一个默认的构造函数.

实体框架代码首先完全坚持通过从配置文件中读取连接字符串来设置配置的想法(或者直接传递连接字符串)或者可以解决这个问题吗?

更新,这是Windsor配置:

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

最佳答案 我很确定你的问题与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不会尝试使用上下文创建任何funkiness(因为非空构造函数对我来说很好).

从你的Windsor配置我希望你需要做类似下面的事情但是我不太确定确切的语法:

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);
点赞