locked
EF4 with Repository and Unit of Work patterns – Is that necessary? RRS feed

  • Question

  • Hello All,

    I’ve been reading recently about EF4, and how to build an architecture for asp.net web forms application using it.

    I explored using POCOs (self tracking entities), with WCF, but found out that my application will be deployed on a single box (i.e. one tier), so I started reading about logical separation of layers, and came up with the following solution:

    1. DAL layer that contains EDMX model and EF APIs, and also generated context object.
    2. Entities DLL that holds all generated POCO entities using ADO.NET POCO entity generator. (for persistence ignorance, and decoupling entities from DAL).
    3. Business layer that contains a façade for each related group of business functions, the façade will be aware of and using DAL layer. And in each function, it will initiate context and uses different entities to carry out specific job (i.e. function)
    4. UI layer that only calls the business layer façade classes. With no awareness of DAL, but it will be aware of entities (i.e. using entities DLL), as the business layer will return results basically as entity collections.

    I want to know what you think about this architecture… that’s one…

    I also read about an architecture that uses repository and unit of work patterns, but what I understand is that context object is already implementing a UOF pattern, and also object sets are implementing repository pattern (correct me if I’m wrong), so the only advantage of using additional abstraction over them is to make the business layer communicates to my classes, not EF classes, and this is good only if the DAL strategy might change (i.e. by using another tool other than EF, which is not my plan), and for unit testing, and separating business from DAL (which I don’t necessarily need now).

    So I had the impression that the first approach is good and the second one is an over head (in my scenario).

    What do you think?

    If you see the latter implementation is the minimum decent architecture, please let me know what the best practice for implementing it on EF4 is.

    Thanks in advance…

    Monday, September 27, 2010 1:16 PM

Answers

  • Hi Abdallah,

    It looks good for me. The only point that I ussually do different is that I don't use a "generic" repository.

    I create one repository and interface for each "aggregate" (e.g. IPersonRepository and PersonRepository), and then I expose methods like GetByName(string name) and put the LINQ2Entities query inside.

    So, from the BL I am always calling a very explicit method (GetByName) and I don't have this query distributed in different places.

    The other good point of this approach (not using a "generic" repository) is that it is easier to test the BL objects using Mock objects (for repositories) without lambda expressions as parameters. 

    But, again, there is no a unique answer, and it looks good.


    Regards,

    Jorge Fioranelli
    • Proposed as answer by Jorge Fioranelli Friday, October 8, 2010 1:45 AM
    • Marked as answer by liurong luo Friday, October 15, 2010 2:08 AM
    Friday, October 8, 2010 1:45 AM

All replies

  • On 9/27/2010 9:16 AM, Abdallah.Hussein wrote:
    >
    > What do you think?
    >
     
    The UI should be unaware of the BLL, it should be a dumb UI. The UI uses
    the methods and properties in View interface of a Model View Presenter
    and dependency injection.
     
    The View interface has the ASP.NET controls on the interface which are
    linked to the controls on the page and any other property needed using
    the Get/Set on the View interface.
    The presenter is the layer that controls the UI and the BLL, the BLL
    uses a Service layer using service layer interfaces, the Service layer
    is in contact with the DAL using DAL interfaces and the DAL is in
    contact with the model.
     
    This way, Unit Testing can be done against interfaces by using mocked
    objects for expected results to achieve code coverage in the layers.
     
    > If you see the latter implementation is the minimum decent architecture,
    > please let me know what the best practice for implementing it on EF4 is.
    >
     
    http://www.dofactory.com/Framework/Framework.aspx
     
     
    Tuesday, September 28, 2010 1:38 AM
  • Hi Abdallah,

    I have recently written a post series about this topic:

    N-Tiers using POCOs and Entity Framework

    1. Architecture
    2. Model and Entities
    3. Presentation Layer
    4. Business Layer
    5. DataAccess Layer

    Please let me know if you need any help.

    Regards,

    Jorge

    Tuesday, September 28, 2010 4:51 AM
  • Hello Darnold92, Hello Jorge.

    Thank you for your help, but actually I'm using a web forms in my UI layer, not a MVC, also i don't want to write a repository for each entity (that would take huge time, as we have a rich model) that's why I wanted to understand the necessity of Repository/Unit of work pattern with EF.

    specially when I see that both patterns are already applied in EF architecture. Thanks.

    Tuesday, September 28, 2010 8:52 AM
  • On 9/28/2010 4:52 AM, Abdallah.Hussein wrote:
    > Hello Darnold92, Hello Jorge.
    >
    > Thank you for your help, but actually I'm using a web forms in my UI
    > layer, not a MVC, also i don't want to write a repository for each
    > entity (that would take huge time, as we have a rich model) that's why I
    > wanted to understand the necessity of Repository/Unit of work pattern
    > with EF.
    >
    > specially when I see that both patterns are already applied in EF
    > architecture. Thanks.
    >
     
    MVP is not MVC and MVP works with WEB or Windows forms. It sounds like
    you're about to put complicated unnecessary code in the Web forms, when
    the code should be in the MVP Presenter, and the MVP Presenter should
    have the complicated code making the Web forms as dumb as possible. The
    Web forms should only have the controls on the forms, and the form's
    methods should be calling like named methods on the Presenter who has
    the control.
     
    Repository/Unit of work, I am using with NHibernate in a project using
    WCF. I don't particularly care for the Repository/Unit of work pattern.
    I think using a Manager with its methods in the BLL that call the DAL is
    a much more flexible and unit testable solution.
     
    Tuesday, September 28, 2010 12:13 PM
  • I think using a Manager with its methods in the BLL that call the DAL is
    a much more flexible and unit testable solution.
     

    I think this is similar to what I proposed on first (recalling):

    1. DAL layer that contains EDMX model and EF APIs, and also generated context object.
    2. Entities DLL that holds all generated POCO entities using ADO.NET POCO entity generator. (for persistence ignorance, and decoupling entities from DAL).
    3. Business layer that contains a façade for each related group of business functions, the façade will be aware of and using DAL layer. And in each function, it will initiate context and uses different entities to carry out specific job (i.e. function)
    4. UI layer that only calls the business layer façade classes. With no awareness of DAL, but it will be aware of entities (i.e. using entities DLL), as the business layer will return results basically as entity collections.

    But I called it "façade" and you called it "manager", but I think you're proposing the same idea, right.?
    Tuesday, September 28, 2010 5:56 PM
  •  
    "Abdallah.Hussein" wrote in message news:70e8b02d-cce3-4174-895d-8d6c6c2e91a9...
    I think using a Manager with its methods in the BLL that call the DAL is
    a much more flexible and unit testable solution.
     

    I think this is similar to what I proposed on first (recalling):

    1. DAL layer that contains EDMX model and EF APIs, and also generated context object.
    2. Entities DLL that holds all generated POCO entities using ADO.NET POCO entity generator. (for persistence ignorance, and decoupling entities from DAL).
    3. Business layer that contains a façade for each related group of business functions, the façade will be aware of and using DAL layer. And in each function, it will initiate context and uses different entities to carry out specific job (i.e. function)
    4. UI layer that only calls the business layer façade classes. With no awareness of DAL, but it will be aware of entities (i.e. using entities DLL), as the business layer will return results basically as entity collections.

    But I called it "façade" and you called it "manager", but I think you're proposing the same idea, right.?
     
    my response------------------------------------------------------------------------------------
     
    It seems to be the same thing, but the UI is unaware of the BLL. The UI knows about the presenter, the presenter is aware of the BLL and entity objects are mapped to DTO(s) or DTO used by the UI. I can't say that I would use POCO(s) but rather DTO(s), since I have not worked with 4.0 and only 3.5. And for sure, I would have no complicated code in a Web form, all logic would be in the presenter, controls on the IView of MVP presenter doing unit testing against the methods in the Presenter, which reduces functional testing of code in  the UI form. The presenter has the control and is unit testable. Code in the Web forum is not unit testable.
     
    Tuesday, September 28, 2010 10:20 PM
  • Hello Darnold92, Hello Jorge.

    Thank you for your help, but actually I'm using a web forms in my UI layer, not a MVC, also i don't want to write a repository for each entity (that would take huge time, as we have a rich model) that's why I wanted to understand the necessity of Repository/Unit of work pattern with EF.

    specially when I see that both patterns are already applied in EF architecture. Thanks.


    The repository pattern allows you to isolate the dataaccess logic. Take a look at the Evans (DDD) and Fowler (PoEAA) definitions:


    So, the question is: "Do you think the LINQ2Entities queries and the EF context methods are dataaccess logic?"

    If your answer is "yes", the Repository pattern could help you to isolate this code.

    If your answer is "no", you don't need the Repository pattern.

    In my opinion, it is better to have all the LINQ2Entities queries encapsulated inside Repositories rather than having this code distributed in the BL. But there isn't a unique answer.

    Regarding the UoW, it could help you if you want to encapsulate the savechanges() method of the EF context, but if you aren't using Repositories it doesn't make sense.

    Regards,

    Jorge

    Wednesday, September 29, 2010 3:56 AM
  • On 9/28/2010 11:56 PM, Jorge Fioranelli wrote:
    > Hello Darnold92, Hello Jorge.
    >
    > Thank you for your help, but actually I'm using a web forms in my UI
    > layer, not a MVC, also i don't want to write a repository for each
    > entity (that would take huge time, as we have a rich model) that's
    > why I wanted to understand the necessity of Repository/Unit of work
    > pattern with EF.
    >
    > specially when I see that both patterns are already applied in EF
    > architecture. Thanks.
    >
    >
    > The repository pattern allows you to isolate the dataaccess logic. Take
    > a look at the Evans (DDD) and Fowler (PoEAA) definitions:
    >
    > * http://domaindrivendesign.org/node/123
    > * http://martinfowler.com/eaaCatalog/repository.html
    >
    >
    > So, the question is: "Do you think the LINQ2Entities queries and the EF
    > context methods are dataaccess logic?"
    >
     
    Yeah it's DAL logic, but that doesn't mean that a BLL Manager, call it
    AccountsPayableManager, cannot make the calls to the DAL methods for
    CRUD operations against the model for AccountsPayable functionality
    through an interface, which is isolation too of the dataaccess logic.
     
    In the case where there is a service such as a WCF service and it has a
    reference to classlib project that contains the BLL in a folder, the
    DAL and the model in another folder within the same project and it sits
    behind the service, I don't see the need for a repository there either,
    as code is still isolated through interfaces.
     
    As long as one can run an isolated unit test against the interface of
    the BLL or DAL, I don't see the need for a repository.
     
    It all depends on what's best for a given situation to use a repository
    or to use a manager in the BLL.
     
     
    Wednesday, September 29, 2010 4:20 AM
  • Hello Darnold92, Hello Jorge...

    First of all I would like to thank you for your time and valuable opinions, then I want to let you know what I came up with and know your opinions about it (Given that my app run on one server, and not uses WCF)

    I came up with the following:

    1-      Created a model, generated POCO using ADO.NET POCO entity generator. Placed that in a DLL  as DAL .

    2-      Separated POCO classes in a nother DLL as (Entities ). (DAL is adding Entities as reference)

    3-      Created a new DLL holding a generic repository that wraps up all original object sets in a generic way, with the help of a unit of work that wraps up the original context, this DLL will act as a bridge between the business managers and the EF, as I want to make the business manager ignorant about the DAL and EF .
    Code of generic repository and unit of work is as follows (it will use System.Data.Entity):

    public interface IRepository<T> where T : class
        {
            IQueryable<T>   AsQueryable();
            IEnumerable<T>  GetAll();
            IEnumerable<T>  Find(Expression<Func<T, bool>> predicate);
            T               Single(Expression<Func<T, bool>> predicate);
            T               First(Expression<Func<T, bool>> predicate);

            void    Add(T entity);
            void    Remove(T entity);
            void    Remove(Expression<Func<T, bool>> predicate);
            void    Attach(T entity);
        }

        public class Repository<T> : IRepository<T> where T : class
        {

            private IObjectSet<T> _objectSet;

            public Repository(UnitOfWork objectContext)
            {
                _objectSet = objectContext.CreateObjectSet<T>();
            }

            public IQueryable<T> AsQueryable()
            {
                return _objectSet;
            }

            public IEnumerable<T> GetAll()
            {
                return _objectSet.ToList();
            }

            public IEnumerable<T> Find(Expression<Func<T, bool>> predicate)
            {
                return _objectSet.Where(predicate);
            }

            public T Single(Expression<Func<T, bool>> predicate)
            {
                return _objectSet.Single(predicate);
            }

            public T First(Expression<Func<T, bool>> predicate)
            {
                return _objectSet.First(predicate);
            }

            public void Add(T entity)
            {
                _objectSet.AddObject(entity);
            }
          
            public void Attach(T entity)
            {
                _objectSet.Attach(entity);
            }

            public void Remove(T entity)
            {
                _objectSet.DeleteObject(entity);
            }

            public void Remove(Expression<Func<T, bool>> predicate)
            {
                IEnumerable<T> records = from x in _objectSet.Where<T>(predicate) select x;
                foreach (T record in records)
                {
                    _objectSet.DeleteObject(record);
                }
            }
        }

        public class UnitOfWork: IDisposable
        {
            private readonly ObjectContext _context;

            public UnitOfWork()
            {
                _context = new Entities();
            }

            internal IObjectSet<T> CreateObjectSet<T>() where T : class
            {
                return _context.CreateObjectSet<T>();
            }

            public void SaveChanges()
            {
                _context.SaveChanges();
            }

            public void Dispose()
            {
                _context.Dispose();
            }
        }

    4-  Then I create my business managers with reference only to 3 (repository and unit of work), with no knowledge about Entity framework or real object sets, but alsouses POCO Entities (2):

    namespace BusinessServices
    {
        public class BloggingManager
        {
            public BloggingManager()
            {
            }

            public int CreateNewBlogger(Person newBlogger)
            {
                using (UnitOfWork context = new UnitOfWork())
                {
                    IRepository<Person> repPersons = new Repository<Person>(context);
                    repPersons.Add(newBlogger);
                    context.SaveChanges();
                }
                return newBlogger.ID;
            }
        }
    }

    5-  Then the UI client referring only to 4 as follows:

    //defining new blogger..
                Person blogger = new Person();
                blogger.Surname = "Hussein";
                blogger.Firstname = "Abdallah";
                blogger.EmailAddress = "abdallah.abdel-azeem@hp.com";

                //adding
                BloggingManager blogManager = new BloggingManager();
                blogManager.CreateNewBlogger(blogger);

    I aimed from this architecture to achieve:

    • Persistence ignorance in entities as well as repositories (which are entities wrappers).
    • Achieve separation of concerns, by separating the UI, and also business manager’s layers from the EF and Data access in the simplest way I could.
    • Hopefully the above will achieve smooth testability.
    What do you guys think? Your opinion is highly appreciated...
    Thursday, September 30, 2010 8:03 AM
  • Hi Abdallah,

    It looks good for me. The only point that I ussually do different is that I don't use a "generic" repository.

    I create one repository and interface for each "aggregate" (e.g. IPersonRepository and PersonRepository), and then I expose methods like GetByName(string name) and put the LINQ2Entities query inside.

    So, from the BL I am always calling a very explicit method (GetByName) and I don't have this query distributed in different places.

    The other good point of this approach (not using a "generic" repository) is that it is easier to test the BL objects using Mock objects (for repositories) without lambda expressions as parameters. 

    But, again, there is no a unique answer, and it looks good.


    Regards,

    Jorge Fioranelli
    • Proposed as answer by Jorge Fioranelli Friday, October 8, 2010 1:45 AM
    • Marked as answer by liurong luo Friday, October 15, 2010 2:08 AM
    Friday, October 8, 2010 1:45 AM
  • Hi Folks!

    I´m  trying to keep up-to-date  with all this  stuff  of  DDD, TDD, ORM (EF4), MVP, MVC and  So  On...

    Actually  I´m looking  for  a good Implementation  of  MVP  with  EF4  and  some  concepts of DDD I´ve been looking  in http://webformsmvp.com/  but  didn´t  help  me  much  I really  need  see  some  real code  to understand the concept.

    If  someone have  any  tip  let me know! Thank you

     

    Ed

     

     

    Sunday, October 10, 2010 1:27 PM
  • Hi Ed,

    Re: Web Forms MVP, drop an email to webformsmvp@googlegroups.com and a bunch of us will be more than happy to help you out there.

     

    --

    Tatham

    (coordinator of Web Forms MVP)

    Tuesday, October 19, 2010 5:22 AM
  • Hi Jorge,

    Thank you very much for your reply, it helped me a lot, Actually  I'm considering implementing your suggestion about having repository for each aggregate.

    But I have two question regarding this approach:

    1- what's the need of interfaces for repositories?

    2- how to determine "aggregate" entities?

    Thank you very much.

    Wednesday, October 27, 2010 2:34 PM
  • Hi Jorge,

    Thank you very much for your reply, it helped me a lot, Actually  I'm considering implementing your suggestion about having repository for each aggregate.

    But I have two question regarding this approach:

    1- what's the need of interfaces for repositories?

    2- how to determine "aggregate" entities?

    Thank you very much.


    Hi Abdallah,

    1. They are great for isolating the dependencies and allowing you to mock the repositories in your unit tests. If you want to test some logic and exclude the repository behavior, you can inject a mock for the interface.

    2. Here you have a good reference: http://devlicio.us/blogs/casey/archive/2009/02/16/ddd-aggregates-and-aggregate-roots.aspx

     


    Regards,

    Jorge Fioranelli
    Wednesday, October 27, 2010 10:24 PM