c# - EF - Best way to manage DbContext? -


i know there alot of articles regarding topic, wherever looked, either complicated or unclear me.

my team develops web application uses entity framework code first. use autofac dependency injection.

currently, data access looks follows:

the api supplied projects not contain ef:

public class dataservice {    private idbcontextfactory<mycontext> _factory;    private idataserviceexecutor _dataserviceexecutor;     public dataservice(idbcontextfactory<mycontext> factory, idataserviceexecutor executor)    {        _factory = factory;        _dataserviceexecutor = executor;    }     public void additem(product prod)    {        using (var context = _factory.create())        {            if (_dataserviceexecutor.additem(context, prod))                context.savechanges();        }    } } 

my dataserviceexecutor:

public class dataserviceexecutor {     private irepository<product> _products;      public dataservice(irepository<product> products...more repositories)     {        _products = products;     }      public bool additem(dbcontext context, prouduct prod)     {         try         {             _products.additem(context, prod);              return true;         }         catch(exception ex)         {              log(..)              return false;         }     } } 

all repositories inherit abstract repository:

public abstract class efrepository<t> : irepository<t> {     public void additem<t>(dbcontext context, t item)     {         context.set<t>().add(item);     }      .     .     . } 

the thing context used per transaction way.

the bad thing both service methods , repositories methods take context directly. application not big, method injection of context fine, become bigger , context injection @ it's current state problematic in opinion. , looks bad.

maybe there more pros , cons i'm not aware of..

is there way i'm not familiar make data access better?

classes dataserviceexecutor (essentially verb) spell design flaws. it's method (execute...) disguised class. responsibilities of such classes aren't clear because functions inevitably belong other classes.

the problem in great pattern inversion of control ioc container can used inject any dependency. allow create tangle of dependencies , scattered responsibilities , still decent job managing life cycles. may obscure life cycle problems you'd have otherwise.

so let's ignore ioc moment , see code simple object creation if call dataserviceexecutor.additem.

var product = new product(); var factory = new dbcontextfactory<mycontext>(); // dependencies unknown var productrepository = new repository<product>(context); var executor = new dataserviceexecutor(productrepository); var dataservice = new dataservice(factory, executor); 

inside dataserviceadditem method have:

using (var context = _factory.create()) {     executor.additem(context, product);     context.savechanges(); } 

if dataservice receive productrepository instead of executor boil down to:

productrepository.additem(context, product); context.savechanges(); 

the executor can taken out easily. role seems error logging. done dataservice well.

but we're not done yet. indicated yourself, these methods taking context parameter bit awkward. dataserviceexecutor out of picture, it's far more natural do:

var product = new product(); var factory = new dbcontextfactory<mycontext>(); using (var context = _factory.create()) {     var productrepository = new repository<product>(context);     productrepository.additem(product);      // , example     var orderrepository = new repository<order>(context);     orderrepository.additem(order);      // 1 savechanges call!     context.savechanges(); } 

and dataservice gone too.

now efrepository stores context member variable, , additem looks this:

public void additem<t>(t item) {     _context.set<t>().add(item); } 

and ioc.

in light of ioc, main problem of code inside dataservice.additem:

using (var context = _factory.create()) 

you create context not managed ioc container. it's lifespan scoped additem method. therefore have pass around on place make sure within business transaction uses 1 instance. bringing repository's dependency (to context) constructor injection, it's easier let ioc container manage context's lifespan.

by way, dataservice part of "the api supplied projects not contain ef". refer mycontext in generic parameter. maybe mycontext abstraction too, don't know. anyhow, supply instances of abstraction ioc well.


Comments

Popular posts from this blog

javascript - jQuery: Add class depending on URL in the best way -

caching - How to check if a url path exists in the service worker cache -

Redirect to a HTTPS version using .htaccess -