Differences

This shows you the differences between two versions of the page.

Link to this comparison view

it:ad:patterns:repository_pattern [2019/03/24 12:02] (current)
Line 1: Line 1:
 +# IT:​AD:​Patterns:​Repository Pattern #
 +
 +
 +
 +<callout type="​Navigation"​ class="​small">​
 +* [[../​|(UP)]]
 +{{indexmenu>​.#​2|nsort tsort}}
 +
 +
 +
 +
 +---
 +
 +
 +</​callout>​
 +
 +
 +<panel title="​Summary">​
 +
 +Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects.
 +
 +![MF](http://​martinfowler.com/​eaaCatalog/​repositorySketch.gif)
 +
 +
 +</​panel>​
 +
 +
 +## Facts ##
 +* [0] Implemented by EF 4.2 DbSet (DbContext implements `UnitOfWork` Pattern)
 +
 +
 +## Components ##
 +
 +* [[IT/​AD/​Patterns/​UnitOfWork Pattern/]]
 +* Repository Pattern:  ​
 +    * According to [M.F.]() A Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection. ​
 +
 +Client objects construct query specifications declaratively and submit them to Repository for satisfaction. Objects can be added to and removed from the Repository, as they can from a simple collection of objects, and the mapping code encapsulated by the Repository will carry out the appropriate operations behind the scenes. Conceptually,​ a Repository encapsulates the set of objects persisted in a data store and the operations performed over them, providing a more object-oriented view of the persistence layer. Repository also supports the objective of achieving a clean separation and one-way dependency between the domain and data mapping layers.
 +
 +
 +## Problem Definition ##
 +* A DataContext is for many Aggregate Root Entities
 +* A Repo is needed for each Aggregate Root Entity
 +* A Repo is always associated to one type of DataContext (during the lifespan of that repo it is for EF, or other, but it doesn'​t switch from EF DataContext to NHibernate Session or other such switch).
 +* But a Repo should be able to work against several DataContexts.
 +* SOLID would suggest that a Repo constructor should define up front what it needs...
 +    * It can define up front that it needs a IContext...
 +        *.. but this ties a Repo to only one DataContext (as ServiceLocator always returns the same Repo).
 +    * It can define up front instead that it needs an IContextManager,​ or IUoWManager if there is a 1-1 relationship,​ which will return a '​Current'​ UoW/​Context.
 +* A Controller should declare up front which Repo it wants.
 +* Controller(IMyRepo)
 +    * MyRepo(IUoWManager)
 +* If an ObjectContext IS a UoW, then there is a one to one relationship.
 +    * And the scoping of multiple UoW's is via TransactionScope.
 +
 +
 +
 +
 +## Generic Repository ##
 +Let's get one thing out of the way first: one can make a *vendor-specific* generic Repository, but one can't make -- in a way that adds value -- a generic Repository that is portable across vendors.
 +
 +One can wrap up the IUnit of work, and Context:
 +
 +    //Create EF specific ObjectContext:​
 +    using (ObjectContext origObjectContext = new XAct_App()){
 +      //Wrap in order to work with portable wrapper:
 +      using (IObjectContext objectContext = new EntityObjectContext(origObjectContext)){
 +        //Use it to define a new UoW:
 +        using (IUnitOfWork uow = new UnitOfWork(abstractObjectContext)){
 +          using (IRepository repository = new ExampleRepository(objectContext)){
 +            ...
 +            repository.MakeChanges(...);​
 +            ...
 +            uow.Commit();​
 +          }
 +        }
 +      }
 +    }
 +
 +but it really doesn'​t get you much further along. ​
 +
 +The problem is the lazy loading and include statements. Each vendor has a different solution to the problem. ​ There is no .NET Framework portable Extension method for Including child objects, so to get access to these methods, one has to have a reference to the EF assemblies. It's as simple as that. 
 +If you try to wrap up all those juicy vendor extensions, you'll never finish -- and if you try to go for a lower common denominator,​ you'll be losing half of the advantages that ORM's can provide. Sounds like a bad strategy.
 +
 +As far as I can tell, the only solution is to create a VendorSpecificRepositoryBase that returns IQueryable'​s,​ enherit from that (eg: ContactsRepository) that uses vendor specific Extensions Methods (Include. etc) and exposes methods that return IEnumerable,​ not IQueryable().
 +
 +The reason they have to return IEnumerable,​ and not IQueryable, is to not infest the calling Domain layer with technology specific methods, including Repository (that'​s up to the Application Layer to orchestrate).
 +
 +If the domain is going to call the Reposotory directly -- and it's a quick down and dirty application,​ I guess it could expose its methods as IQueryable. Really wouldn'​t recommend it as a long term strategy.
 +
 +
 +## Mocking ##
 +See: 
 +* (post)[http://​refactorthis.wordpress.com/​2011/​05/​31/​mock-faking-dbcontext-in-entity-framework-4-1-with-a-generic-repository/​] for ideas.
 +
 +## Ambiguity ##
 +
 +A Repository has a 1-1 relationship to its internal DbSet that is wraps in order to manage a single Aggregagate Entity .
 +If there is a cross relationship (for example, Vertices and Edges in a Graph, it's better to have two Repositories,​ linked by a common Context, instead of one Repository, with two DbSets.
 +
 +It certainly makes it easier in terms of method duplication,​ etc.
 +
 +
 +
 +## Resources ##
 +
 +Consider:
 +
 +* Filtered DbSets: [http://​bit.ly/​tUrV3H](http://​bit.ly/​tUrV3H)
 +* [Transactions](http://​www.mssoftwareconsulting.com/​msswc/​blog/​post/​Unit-of-Work-Pattern-for-Entity-Framework-4-and-Unity.aspx)
 +* [Key](http://​stackoverflow.com/​a/​4465417)
 +* [NCommon](http://​www.java2s.com/​Open-Source/​CSharp/​Library/​ncommon/​NCommon/​Data/​UnitOfWork.cs.htm)
 +    * [Good intro](http://​stevemgentile.wordpress.com/​category/​ncommon/​)
 +* [...](http://​kitchaiyong.wordpress.com/​2009/​10/​10/​repository-specification-unit-of-work-persistence-ignorance-poco-with-microsoft-entityframework-4-0-part-2/​)
 +* [http://​www.asp.net/​mvc/​tutorials/​getting-started-with-ef-using-mvc/​implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application](http://​www.asp.net/​mvc/​tutorials/​getting-started-with-ef-using-mvc/​implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application)
 +* [http://​www.asp.net/​mvc/​tutorials/​getting-started-with-ef-using-mvc/​advanced-entity-framework-scenarios-for-an-mvc-web-application](http://​www.asp.net/​mvc/​tutorials/​getting-started-with-ef-using-mvc/​advanced-entity-framework-scenarios-for-an-mvc-web-application)
 +* [http://​www.asp.net/​mvc/​tutorials/​getting-started-with-ef-using-mvc/​implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application](http://​www.asp.net/​mvc/​tutorials/​getting-started-with-ef-using-mvc/​implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application)
 +* [http://​www.primaryobjects.com/​CMS/​Article122.aspx](http://​www.primaryobjects.com/​CMS/​Article122.aspx)
 +* *really* Generic Repository [http://​lostechies.com/​jimmybogard/​2009/​09/​03/​ddd-repository-implementation-patterns/​](http://​lostechies.com/​jimmybogard/​2009/​09/​03/​ddd-repository-implementation-patterns/​)