EF Code First, IoC and DbConnection

I am using Entity Framework Code First. I want to be able to insert a System.Data.Common.DbConnection object when creating a context instance that derives from System.Data.Entity.DbContext . This means that I can transfer different types of connections depending on the environment in which the code works, i.e. Use System.Data.SqlClient (SQL Server) in development, System.Data.SQLite for unit testing and something else in the production process. The relevant parts of the Context are as follows:

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

This gives me the following error: The target context 'Services.Persistence.Context' is not constructible. Add a default constructor or provide an implementation of IDbContextFactory. The target context 'Services.Persistence.Context' is not constructible. Add a default constructor or provide an implementation of IDbContextFactory. I think this happens during model initialization, when the Entity Framework seems to feel that it needs a new native Context , regardless of the IoC pattern I'm trying to achieve. The lack of a default constructor is by design. The IDbContextFactory interface is also useless - it should also have a default constructor.

Is the Entity Framework Code the first completely attached to the idea of โ€‹โ€‹setting up its configuration by reading the connection string from the configuration file (or, alternatively, passing the connection string directly), or can I get around this?

UPDATE, here's the Windsor configuration:

 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
source share
1 answer

I'm sure your problem has nothing to do with EF, but I am not a Windsor user, so I canโ€™t say exactly what your configuration problem is. What I did was to reproduce a similar configuration with ninject, which works exactly as you expected, see below:

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

This means that EF is not trying to do any fun with creating context (since a non-empty constructor works fine for me).

From the Windsor configuration, I would expect you to do something like the following, but I'm not too sure about the exact syntax:

 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); 
+2
source

Source: https://habr.com/ru/post/1437075/


All Articles