entity framework - Multiple dbcontexts with Repository, UnitOfWork and Ninject -


i getting grips ef, repository, unitofwork , ninject , have included implementation far (see below).

the purpose of data layer provide ability read data existing hr system has oracle end, , provide addition functionality consuming data. application building use sql backend, have created tables in hr systems oracle dbm want keep separate , hook in features such sql dependency , service broker.

my data layer abstracted application(s) , split in data, data.contracts , models. have been using code first approach own tables , have used devart's dotconnect oracle map oracle database , generate models me.

finally have business layer inject unitofwork , keep business logic, business layer injected in presentation layer. replaced service layer data can maintained in single place our systems, i'm not quite there yet.

i appreciate if can review code far , show me how can introduce multiple dbcontexts (sql & oracle) can used seamlessly same unitofwork.

finally struggling work out how can have generic repository pattern can assign models, create model specific repositories or additional generic repository methods assigned specific models. e.g. may want provide methods read models, may want have ability add, edit, delete on models.

many thanks,

andy

using system; using system.data.entity; using data.contracts;  namespace data.helpers { /// <summary> /// interface class can provide repositories type. /// class may create repositories dynamically if unable /// find 1 in cache of repositories. /// </summary> /// <remarks> /// repositories created provider tend require <see cref="dbcontext"/> /// retrieve data. /// </remarks> public interface irepositoryprovider {     /// <summary>     /// , set <see cref="dbcontext"/> initialize repository     /// if 1 must created.     /// </summary>     dbcontext dbcontext { get; set; }      /// <summary>     /// <see cref="irepository{t}"/> entity type, t.     /// </summary>     /// <typeparam name="t">     /// root entity type of <see cref="irepository{t}"/>.     /// </typeparam>     irepository<t> getrepositoryforentitytype<t>() t : class;      /// <summary>     /// repository of type t.     /// </summary>     /// <typeparam name="t">     /// type of repository, typically custom repository interface.     /// </typeparam>     /// <param name="factory">     /// optional repository creation function takes <see cref="dbcontext"/>     /// , returns repository of t. used if repository must created.     /// </param>     /// <remarks>     /// looks requested repository in cache, returning if found.     /// if not found, tries make 1 factory, fallingback      /// default factory if factory parameter null.     /// </remarks>     t getrepository<t>(func<dbcontext, object> factory = null) t : class;       /// <summary>     /// set repository return provider.     /// </summary>     /// <remarks>     /// set repository if don't want provider create one.     /// useful in testing , when developing without backend     /// implementation of object returned repository of type t.     /// </remarks>     void setrepository<t>(t repository);     } }  using system; using system.collections.generic; using system.data.entity; using data.contracts;  namespace data.helpers { /// <summary> /// maker of repositories. /// </summary> /// <remarks> /// instance of class contains repository factory functions different types. /// each factory function takes ef <see cref="dbcontext"/> , returns /// repository bound dbcontext. /// <para> /// designed "singleton", configured @ web application start /// of factory functions needed create type of repository. /// should thread-safe use because configured @ app start, /// before request factory, , should immutable thereafter. /// </para> /// </remarks> public class repositoryfactories {     /// <summary>     /// return runtime repository factory functions,     /// each 1 factory repository of particular type.     /// </summary>     /// <remarks>     /// modify method add custom factory functions     /// </remarks>     private idictionary<type, func<dbcontext, object>> getfactories()     {         return new dictionary<type, func<dbcontext, object>>             {                //{typeof(iarticlerepository), dbcontext => new articlerepository(dbcontext)},                //{typeof(iurlrepository), dbcontext => new urlrepository(dbcontext)},             };     }      /// <summary>     /// constructor initializes runtime repository factories     /// </summary>     public repositoryfactories()     {         _repositoryfactories = getfactories();     }      /// <summary>     /// constructor initializes arbitrary collection of factories     /// </summary>     /// <param name="factories">     /// repository factory functions instance.      /// </param>     /// <remarks>     /// ctor useful testing class     /// </remarks>     public repositoryfactories(idictionary<type, func<dbcontext, object>> factories)     {         _repositoryfactories = factories;     }      /// <summary>     /// repository factory function type.     /// </summary>     /// <typeparam name="t">type serving repository factory lookup key.</typeparam>     /// <returns>the repository function if found, else null.</returns>     /// <remarks>     /// type parameter, t, typically repository type      /// type (e.g., entity type)     /// </remarks>     public func<dbcontext, object> getrepositoryfactory<t>()     {          func<dbcontext, object> factory;         _repositoryfactories.trygetvalue(typeof(t), out factory);         return factory;     }      /// <summary>     /// factory <see cref="irepository{t}"/> t entity type.     /// </summary>     /// <typeparam name="t">the root type of repository, typically entity type.</typeparam>     /// <returns>     /// factory creates <see cref="irepository{t}"/>, given ef <see cref="dbcontext"/>.     /// </returns>     /// <remarks>     /// looks first custom factory in <see cref="_repositoryfactories"/>.     /// if not, falls <see cref="defaultentityrepositoryfactory{t}"/>.     /// can substitute alternative factory default 1 adding     /// repository factory type "t" <see cref="_repositoryfactories"/>.     /// </remarks>     public func<dbcontext, object> getrepositoryfactoryforentitytype<t>() t : class     {         return getrepositoryfactory<t>() ?? defaultentityrepositoryfactory<t>();     }      /// <summary>     /// default factory <see cref="irepository{t}"/> t entity.     /// </summary>     /// <typeparam name="t">type of repository's root entity</typeparam>     protected virtual func<dbcontext, object> defaultentityrepositoryfactory<t>() t : class     {         return dbcontext => new efrepository<t>(dbcontext);     }      /// <summary>     /// dictionary of repository factory functions.     /// </summary>     /// <remarks>     /// dictionary key system.type, typically repository type.     /// value repository factory function     /// takes <see cref="dbcontext"/> argument , returns     /// repository object. caller must know how cast it.     /// </remarks>     private readonly idictionary<type, func<dbcontext, object>> _repositoryfactories;     } }   using system; using system.collections.generic; using system.data.entity; using data.contracts;  namespace data.helpers { /// <summary> /// provides <see cref="irepository{t}"/> client request. /// </summary> /// <remarks> /// caches repositories of given type repositories created once per provider. /// create new provider per client request. /// </remarks> public class repositoryprovider : irepositoryprovider {     public repositoryprovider(repositoryfactories repositoryfactories)     {         _repositoryfactories = repositoryfactories;         repositories = new dictionary<type, object>();     }      /// <summary>     /// , set <see cref="dbcontext"/> initialize repository     /// if 1 must created.     /// </summary>     public dbcontext dbcontext { get; set; }      /// <summary>     /// or create-and-cache default <see cref="irepository{t}"/> entity of type t.     /// </summary>     /// <typeparam name="t">     /// root entity type of <see cref="irepository{t}"/>.     /// </typeparam>     /// <remarks>     /// if can't find repository in cache, use factory create one.     /// </remarks>     public irepository<t> getrepositoryforentitytype<t>() t : class     {         return getrepository<irepository<t>>(             _repositoryfactories.getrepositoryfactoryforentitytype<t>());     }      /// <summary>     /// or create-and-cache repository of type t.     /// </summary>     /// <typeparam name="t">     /// type of repository, typically custom repository interface.     /// </typeparam>     /// <param name="factory">     /// optional repository creation function takes dbcontext argument     /// , returns repository of t. used if repository must created ,     /// caller wants specify specific factory use rather 1     /// of injected <see cref="repositoryfactories"/>.     /// </param>     /// <remarks>     /// looks requested repository in cache, returning if found.     /// if not found, tries make 1 using <see cref="makerepository{t}"/>.     /// </remarks>     public virtual t getrepository<t>(func<dbcontext, object> factory = null) t : class     {         // t dictionary cache under typeof(t).         object repoobj;         repositories.trygetvalue(typeof(t), out repoobj);         if (repoobj != null)         {             return (t)repoobj;         }          // not found or null; make one, add dictionary cache, , return it.         return makerepository<t>(factory, dbcontext);     }      /// <summary>     /// dictionary of repository objects, keyed repository type.     /// </summary>     /// <remarks>     /// caller must know how cast repository object useful type.     /// <p>this extension point. can register made repositories here     /// , used instead of ones provider otherwise create.</p>     /// </remarks>     protected dictionary<type, object> repositories { get; private set; }      /// <summary>make repository of type t.</summary>     /// <typeparam name="t">type of repository make.</typeparam>     /// <param name="dbcontext">     /// <see cref="dbcontext"/> initialize repository.     /// </param>             /// <param name="factory">     /// factory <see cref="dbcontext"/> argument. used make repository.     /// if null, gets factory <see cref="_repositoryfactories"/>.     /// </param>     /// <returns></returns>     protected virtual t makerepository<t>(func<dbcontext, object> factory, dbcontext dbcontext)     {         var f = factory ?? _repositoryfactories.getrepositoryfactory<t>();         if (f == null)         {             throw new notimplementedexception("no factory repository type, " + typeof(t).fullname);         }         var repo = (t)f(dbcontext);         repositories[typeof(t)] = repo;         return repo;     }      /// <summary>     /// set repository type t provider should return.     /// </summary>     /// <remarks>     /// plug in custom repository if don't want provider create one.     /// useful in testing , when developing without backend     /// implementation of object returned repository of type t.     /// </remarks>     public void setrepository<t>(t repository)     {         repositories[typeof(t)] = repository;     }      /// <summary>     /// <see cref="repositoryfactories"/> create new repository.     /// </summary>     /// <remarks>     /// should initialized constructor injection     /// </remarks>     private repositoryfactories _repositoryfactories;     } }  using system; using system.data; using system.data.entity; using system.data.entity.infrastructure; using system.linq; using data.contracts;  namespace data { /// <summary> /// ef-dependent, generic repository data access /// </summary> /// <typeparam name="t">type of entity repository.</typeparam> public class efrepository<t> : irepository<t> t : class {     public efrepository(dbcontext dbcontext)     {         if (dbcontext == null)             throw new argumentnullexception("dbcontext");         dbcontext = dbcontext;         dbset = dbcontext.set<t>();     }      protected dbcontext dbcontext { get; set; }      protected dbset<t> dbset { get; set; }      public virtual iqueryable<t> getall()     {         return dbset;     }      public virtual t getbyid(int id)     {         //return dbset.firstordefault(predicatebuilder.getbyidpredicate<t>(id));         return dbset.find(id);     }      public virtual void add(t entity)     {         dbentityentry dbentityentry = dbcontext.entry(entity);         if (dbentityentry.state != entitystate.detached)         {             dbentityentry.state = entitystate.added;         }         else         {             dbset.add(entity);         }     }      public virtual void update(t entity)     {         dbentityentry dbentityentry = dbcontext.entry(entity);         if (dbentityentry.state == entitystate.detached)         {             dbset.attach(entity);         }         dbentityentry.state = entitystate.modified;     }      public virtual void delete(t entity)     {         dbentityentry dbentityentry = dbcontext.entry(entity);         if (dbentityentry.state != entitystate.deleted)         {             dbentityentry.state = entitystate.deleted;         }         else         {             dbset.attach(entity);             dbset.remove(entity);         }     }      public virtual void delete(int id)     {         var entity = getbyid(id);         if (entity == null) return; // not found; assume deleted.         delete(entity);     }     } }  using system; using data.contracts; using data.helpers; using models;  namespace data { /// <summary> /// "unit of work" ///     1) decouples repos controllers ///     2) decouples dbcontext , ef controllers ///     3) manages uow /// </summary> /// <remarks> /// class implements "unit of work" pattern in /// "uow" serves facade querying , saving database. /// querying delegated "repositories". /// each repository serves container dedicated particular /// root entity type such <see cref="url"/>. /// repository typically exposes "get" methods querying , /// offer add, update, , delete methods if features supported. /// repositories rely on parent uow provide interface /// data layer (which ef dbcontext in example). /// </remarks> public class unitofwork : iunitofwork, idisposable {     public unitofwork(irepositoryprovider repositoryprovider)     {         createdbcontext();          repositoryprovider.dbcontext = dbcontext;         repositoryprovider = repositoryprovider;     }      // repositories     public irepository<dash_pylvr> dash_pylvrs { { return getstandardrepo<dash_pylvr>(); } }     public irepository<dash_sickrecord> dash_sickrecords { { return getstandardrepo<dash_sickrecord>(); } }     public irepository<emdet> emdets { { return getstandardrepo<emdet>(); } }     public irepository<emlva> emlvas { { return getstandardrepo<emlva>(); } }     public irepository<emlve> emlves { { return getstandardrepo<emlve>(); } }     public irepository<emmpo> emmpos { { return getstandardrepo<emmpo>(); } }     public irepository<empos> emposs { { return getstandardrepo<empos>(); } }     public irepository<eventlog> eventlogs { { return getstandardrepo<eventlog>(); } }     public irepository<idmstaging> idmstagings { { return getstandardrepo<idmstaging>(); } }     public irepository<pp_bradford> pp_bradfords { { return getstandardrepo<pp_bradford>(); } }     public irepository<pp_bradford_scores> pp_bradford_scoress { { return getstandardrepo<pp_bradford_scores>(); } }     public irepository<psdet> psdets { { return getstandardrepo<psdet>(); } }     public irepository<psldw> psldws { { return getstandardrepo<psldw>(); } }     public irepository<upz88> upz88s { { return getstandardrepo<upz88>(); } }      /// <summary>     /// save pending changes database     /// </summary>     public void commit()     {         //system.diagnostics.debug.writeline("committed");         dbcontext.savechanges();     }      protected void createdbcontext()     {         dbcontext = new chriscsentities();          // not enable proxied entities, else serialization fails         dbcontext.configuration.proxycreationenabled = false;          // load navigation properties explicitly (avoid serialization trouble)         dbcontext.configuration.lazyloadingenabled = false;          // because web api perform validation, don't need/want ef         dbcontext.configuration.validateonsaveenabled = false;     }      protected irepositoryprovider repositoryprovider { get; set; }      private irepository<t> getstandardrepo<t>() t : class     {         return repositoryprovider.getrepositoryforentitytype<t>();     }     private t getrepo<t>() t : class     {         return repositoryprovider.getrepository<t>();     }      private chriscsentities dbcontext { get; set; }      #region idisposable      public void dispose()     {         dispose(true);         gc.suppressfinalize(this);     }      protected virtual void dispose(bool disposing)     {         if (disposing)         {             if (dbcontext != null)             {                 dbcontext.dispose();             }         }     }      #endregion     } }   using system.linq;  namespace data.contracts {     public interface irepository<t> t : class     {     iqueryable<t> getall();     t getbyid(int id);     void add(t entity);     void update(t entity);     void delete(t entity);     void delete(int id);     } }  using models;  namespace data.contracts { /// <summary> /// interface "unit of work" /// </summary> public interface iunitofwork {     // save pending changes data store.     void commit();      // repositories     irepository<dash_pylvr> dash_pylvrs { get; }     irepository<dash_sickrecord> dash_sickrecords { get; }     irepository<emdet> emdets { get; }     irepository<emlva> emlvas { get; }     irepository<emlve> emlves { get; }     irepository<emmpo> emmpos { get; }     irepository<empos> emposs { get; }     irepository<eventlog> eventlogs { get; }     irepository<idmstaging> idmstagings { get; }     irepository<pp_bradford> pp_bradfords { get; }     irepository<pp_bradford_scores> pp_bradford_scoress { get; }     irepository<psdet> psdets { get; }     irepository<psldw> psldws { get; }     irepository<upz88> upz88s { get; }     } } 

this looks lot john papa's code. attempted basic explanation of before.

lets want make articlerepository read only. this:

public class articlerepository: efrepository<article> {    //add custom implementation - can add custom methods here 1 empty     //because hiding functions rather creating new functions    //we inherit efrepository class has insert , update methods,     //but doesn't matter because expose findbyid , getall methods     //in interface }  public interface iarticlerepository {    //a custom interface exposes want    findbyid(int id);    getall(); } 

as multiple contexts, have no experience under-qualified, think should able add second context unit of work in same way first , if there saves going on span more 1 context, using transactionscope()

now - place in code should specify how create custom repositories:

/// modify method add custom factory functions /// </remarks> private idictionary<type, func<dbcontext, object>> getfactories() {     return new dictionary<type, func<dbcontext, object>>         {            //{typeof(iarticlerepository), dbcontext => new articlerepository(dbcontext)},            //{typeof(iurlrepository), dbcontext => new urlrepository(dbcontext)},         }; } 

just un-comment first entry in dictionary , repositoryprovider return instance of articlerepository class when ask iarticlerepository in unit of work

in particular example (where implementation empty) don't need articlerepository class. use line dictionary entry instead:

{typeof(iarticlerepository), dbcontext => new efrepository<article>(dbcontext)}

other references:

the repository , unit of work patterns

john papa's original source

how ensure proxies created when using repository pattern


Comments

Popular posts from this blog

java.util.scanner - How to read and add only numbers to array from a text file -

rewrite - Trouble with Wordpress multiple custom querystrings -