EF6 DbContext IOC Dependency

I am using EF6 in the Windows Service / Console Application. I have successfully implemented IOC / DI for my business layer and implementation interfaces. Using constructor injection. I also use Object Database, Task Parallel Library. for better performance, and I'm happy with that.

Also using System.IO.Abstractions to make my code more testable.

EF6 creates POCO clusters for all domain objects using .tt files, which are quite convenient. To execute database queries, I write every time

using(var db = new MyContext()) { // code reading from/writing to database ... ... } 

I know this is a bad practice and makes noise in my code in different places. I want him to be loosely connected. Now for my database operations - I am confused how to go forward to make it more verifiable and loosely coupled. Can someone point me to a good example, an article that can be referenced.

The 2 main things I want to achieve is to have more control over the Connection string configuration (for deploying various servers) and have a DbContext very loosely coupled inside my code.

+6
source share
1 answer

To eliminate the decoupling (and testing), you can create your own interface for your DbContext ( IMyDbContext ) and re-parse all the typed objects of DbSets , SaveChanges() and, possibly, several other methods, you should also make this interface Disposable .

 public interface IMyDbContext : IDisposable { IDbSet<Foo> Foos { get; set; } IDbSet<Bar> Bars { get; set; } int SaveChanges(); DbEntityEntry<T> Entry<T>(T entity) where T : class; } 

(You can also consider reading and reading and writing versions of the interface)

Then modify your specific DbContext to implement this interface. You are now reasonably separate from DbContext (for Unit Testing, etc.), but you still have access to the IQueryable utility, an integral unit of work and caching offered by DbContext .

Then here are two options for IMyDbContext into your business / service classes

  • Enter IDbContext constructor

OR

  1. Create a Factory method and a Factory interface to create specific DbContext s, and then embed the IMyDbContextFactory Factory interface IMyDbContextFactory (you will need an interface, not a specific factory, again for testing Mocking).

The choice here depends on what you need to do with your DbContext . # 1 can be difficult to configure in an IoC container, since you need to pass lifetime control to the container. But it can be useful in web applications if it can be configured on a new instance for the request, so if the request (the supposed single stream) can use it as a cache.

Personally, I prefer # 2, as it allows direct context control:

 using(var db = _myContextFactory.CreateDB()) { db.SaveChanges(); } 

But, obviously, we are losing any potential advantage of long-term contexts such as caching. But there are many other alternative technologies for caching, if necessary.

One caveat: DbContext not a completely safe thread - if you use TPL, make sure that each task gets its own instance of DbContext - for example. use localinit overload Parallel.For / ForEach to create an instance when using this.

+10
source

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


All Articles