Show pageOld revisionsBacklinksBack to top This page is read only. You can view the source, but not change it. Ask your administrator if you think this is wrong. # IT:AD:Patterns:UnitOfWork Pattern # <callout type="Navigation" class="small"> * [[../|(UP)]] {{indexmenu>.#2|nsort tsort}} --- </callout> ## Sumary ## According to [M.F.](http://bit.ly/v7o0Xf) a UoW "keeps track of everything you do during a business *transaction* that can affect the Db. When you're done, it figures out everything that needs to be done to alter the database as a result of your work." * Reference: [http://bit.ly/v7o0Xf](http://bit.ly/v7o0Xf) * In other words, it is the EF ObjectContext that contains methods to Add, Attach, Update, Delete, Commit. ## Considerations ## * Creating a Repository ([[IT/AD/Patterns/Repository/]] per Aggregate Root Entity can lead to a scenario with the various Repositories are working with different Db contexts (ObjectContect (or DbContext)). * A way to ensure they all use the same Db COntext -- and syncronize their Commit across them -- is the UnitOfWork Pattern. * In essense: * a UnitOfWork wraps a common DbContext, * it is injected into each Repository * The repository does not concern itself with the notion of Commit() * When a commit is required, the Controller invokes the UnitOfWork's Commit method, not the Repository's. * It is true that the UnitOfWork's wrapped DbContext does it's Commit all in one transaction, but The UnitOfWork The above is a rather simplistic scenario. * Regarding the relationship between Repository and Object Context: * In 99% of cases, a Repository will work with only one Db Context. In which case: * The DbContext could be injected into the Repository. * Pros: * Follows SOLID methodology. * Cons: * As Context was created prior to Repo, Repo can't close it and start another. Ie: Repository cannot work with secondary Contexts, or allow and partial rollbacks. * A UnitOfWork (wrapping a DbContext) can be injected into the Repository: * Pros: * Follows SOLID methodology. * Cons: * As Context was created prior to Repo, Repo can't close it and start another. Ie: Repository cannot work with secondary Contexts, or allow and partial rollbacks. * Note that if UoW has a Current property, it could wrap a IUoWManager (see below), but I consider that spaghetti (actually Chicken or the Egg) pattern. * The Repository could have an internal property called DbContext that invokes a UnitOfWorkManager.Current that in turn wraps a UnitOfWorkFactory if the Current hasn't been created yet. * Pros: * Can now work with a Current (or a Stack) context. * Cons: * Lose SOLID pattern to some extent (DI is shifted from DbContext to a UnitOfWorkManager injection). * But there is that other 1% case: * It could be that in some cases one is working with an default DbContext, and a TOmbstone DbContext that mirrors the same schema, but without any triggers (this is a common design pattern for keeping track of offline delete scenarios, while being able to undelete the records). * Therefore there is no 1-1 relationship between Could resolve the 1% by something like this: class ContactRepository : IContactRepository : IGenericRepository {} class TombstoneContactRepository : ITombstoneContactRepository : IContactRepository {} that have constructor signatures for: `IUnifWork` and `ITombstoneUnitOfWork` respectively. What's not addressed above are two other questions. * Does a UnitOfWork have a 1-1 relationship to a DbContext? * Transactions / Multiple DbContexts. ## Relationship between UnitOfWork and DbContext ## MF defined a UnitOfWork to be against a Repository. And in 99% of the cases a REpository is against a single vendor product (eg EF). A UnitOfWork is per vendor Context. ## Relationship between UnitOfWork and Transaction ## But if one were to have one UnitOfWork for EF, and another for a WCF based Repo, then the Commit has to hook into something larger -- a TransactionScope. So A UoW has to look for a Current Scope, and if found, hook into it. If non existent, then it is does not hook into an ambient scope, and *is* a scope in itself. Requirements: * UoW: * UoW has 1-1 Relationship to ObjectContext (ie, it wraps it) * UoWFactory has to hook new UoW into any available Ambient Namespace * UoWManager, injected into Repository, and laer invoked by Repository, has to return UoW appropriate to current context. * By Type (ie EF, other) * By ObjectContext (Standard, or Tombstone) public EFContactFactory : IRepository { .. IUoWFactory UoW { get { return _iowFactory.GetCurrent<ObjectContext>();} } .. } public UoWFactory : IUoWFactory { IoW GetCurrent<T> (string tag) { if (T is ObjectContext) { if (tag == "default") {...} } } } /home/skysigal/public_html/data/pages/it/ad/patterns/unitofwork_pattern.txt Last modified: 2023/11/04 03:29by 127.0.0.1