locked
Generic repository data patter in relatively more complex application. Need some advices on the design. RRS feed

  • Question

  • User-1296510619 posted

    Hi

    I understand the problem I am presenting here could be more like debate and there is no simple answer or simple solution :p. I am rather an inexperience programmer who passionate in writing applications. Hope some of you can give me some good starter points :)

    I have read a very good tutorial on the Repository Pattern using generic classes and Unity of Work. I would really like to apply this in my application. The one thing that made me decide on that was much to ability to implement tests--I think it is called TDD. I feel l have a firm understanding of how it works. The tutorial is here on the ASP.Net Implementing the Repository and Unit of Work Patterns in an ASP.NET MVC ApplicationThe application I am working on is going to be written using MVC framework and C# with Razor in Visual Studio 2010 SP1. I also use Entity Framework 6 when I write this. Front-end of that system is a collection of forms in order for data to gather, validate and save to database. The website is protected by login/password.

    The problem is that I need my application to track who signs in, what has been done in terms of CRUD activity, what are the old and new values, which tables is affected and when activity was performed.

    The repository pattern I've read cover only a simple CRUD methods with additional filtering / ordering data. I feel that a repository in my application would have to be more complex and do some extra work. Perhaps what I am talking about is not even one repository. So I have a couple of questions:

    • Does it have to be one repository even if it's generic?
    • If not one repository, should I have a repository per table and its archive version, or should the business of all CRUD / archiving like updating / archiving, deleting /archiving old data be implemented in a repository per Creating, Updating, Deleting etc.
    • How can the Unity of Work be helpful here 

    I am guessing that to track user, I would need to send user information to repository or simply store it there like DbContext and use it every time it needed. As can be seen, I ask a lot of questions which may sound silly. I would simply like to have proper approach before I get my hands into programming all this. I will be grateful for your comments, links, books etc.  :)

    Thursday, February 26, 2015 4:25 AM

All replies

  • User-760709272 posted

    Entity Framework already implements repository-per-table and unit of work patterns so there is no great need to implement your own on top of it.  All you'll end up doing is having a repo with a bunch of single-line methods

    public void AddPerson(Person p)
    {
        dbContext.Persons.Add(p);
    }

    all you're doing is slightly changing the syntax of adding things to your database.  Doing your own repo becomes more valuable if you want to abstract how your data is stored, or you want a repo for entities that don't one-to-one match tables.  For example if you have an Order and OrderItem table then EF gives you an Order and OrderItem repo.  You might want a repo that lets you manage things at the order level, and that repo understands how and when to get related data from OrderItems.  So your order repo might have a "GetTotalCostOfOrder" method.

    Thursday, February 26, 2015 5:17 AM
  • User-1296510619 posted

    Hi AidyF.

    I can only trust you on EF having already reposition. It's correct that we simply use dbContext.Table.function etc.  Then, as far as I understand it, I agree EF has implemented this functionality but the main advantage of having own reposition is I think decoupling from the database. I guess this is one of the reasons why you can implement testing, easily. It's really important to me. Do you have any suggestions how to do design tests without having reposition?

    Thursday, February 26, 2015 5:55 AM
  • User-760709272 posted

    If you google "mocking entity framework dbcontext" you'll find some articles on how to do this.  However using your own repo will indeed make testing, and TDD, easier.

    Thursday, February 26, 2015 5:57 AM
  • User-1296510619 posted

    Thanks. If I decided on my own Reposition, would you suggest anything on recording users' activities and saving / archiving records when CRUD operations are concerned? Is there any well-known pattern of doing this or am I just on my own here? I don't know how exactly I should approach this problem in terms of my own repository.

    Thursday, February 26, 2015 6:16 AM
  • User-760709272 posted

    Look into "Unit of work" implementations.

    Thursday, February 26, 2015 6:22 AM
  • User1689970273 posted

    Hi Zbigman,

    What AidyF describes regarding DBContext is true. DbContext itself is already a UOW pattern so you don't have to duplicate. My advice is to create your own Generic IRepository and abstract generic BaseRepository and your implementation of Repository per domain. For example, I do have an Employee, Address, Benefits Model. Here's a simple code snippets. You attack repository pattern on  domain basis. Example, Customer Domain(may consist of few models), Order Domain(may consists of few models).

    So for each domain, you could have CustomerRepository,OrderRepository, etc. These are testable in repository level.  Hope this helps.

    It may not be complete since I have to hide some of my complex implementations.

      public interface IRepository<T>
        {
            IQueryable<T> GetAll();
            T Get(int id);
            int Insert(T entity);
            int Update(T entity);
            int Update(T entity, Expression<Func<T, object>>[] properties);
            int Delete(T entity);
            IQueryable<T> GetAllFromDatabase();
        }

     public abstract class BaseRepository<T> : IRepository<T> where T : class
        {
            protected IDatabaseContext DatabaseContext { get; private set; }

            protected BaseRepository(IDatabaseContext databaseContext)
            {
                DatabaseContext = databaseContext;
            }

            public abstract IQueryable<T> GetAll();
            public abstract T Get(int id);
            public abstract int Insert(T entity);
            public abstract int Update(T entity);
            public abstract int Delete(T entity);
           


            public int Update(T entity, Expression<Func<T, object>>[] properties)
            {
                
            }
        }

     public interface IEmployeeRepository : IRepository<Employee>
        {
        }

    public class EmployeeRepository: BaseRepository<Employee>, IEmployeeRepository
        {
            public EmployeeRepository(IDatabaseContext databaseContext): base(databaseContext)
            {
            }

            public override IQueryable<Employee> GetAll()
            {
                var allEmployee = DatabaseContext.Set<Employee>();
                return allEmployee;
            }

            public override Employee Get(int id)
            {
                return DatabaseContext.Set<Employee>().Include("Address").Include(d => d.Benefits).Single(x => x.Id == id);
            }

            public override int Insert(Employee entity)
            {
              
                DatabaseContext.Entry(entity).State = EntityState.Added;
                DatabaseContext.Insert(entity);
                return DatabaseContext.SaveChanges();  
            }

            public override int Update(Employee entity)
            {
                DatabaseContext.Entry(entity).State = EntityState.Modified;
                DatabaseContext.Update(entity);
                return DatabaseContext.SaveChanges();
            }

           

            public override int Delete(Employee entity)
            {
                
              
                DatabaseContext.Delete(entity);
                return DatabaseContext.SaveChanges();
            }

          
        }

    Saturday, February 28, 2015 10:51 PM
  • User-1296510619 posted

    Thanks for your answer itpreneur. It's really helpful. I hope it's still np as I came back so late :)

    Monday, August 3, 2015 6:31 AM
  • User-1129594362 posted

    Implementing the Repository and Unit of Work Patterns in an ASP.NET MVC Application (9 of 10)

    http://www.asp.net/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application

    Friday, September 4, 2015 2:32 PM