0

I am reading the following tutorial about creating Generic Repository Link in asp.net mvc & EF, to perform CRUD operations, as follow:-

using System;
using System.Collections.Generic;
using System.Linq;
using System.Data;
using System.Data.Entity;
using ContosoUniversity.Models;
using System.Linq.Expressions;

namespace ContosoUniversity.DAL
{
    public class GenericRepository<TEntity> where TEntity : class
    {
        internal SchoolContext context;
        internal DbSet<TEntity> dbSet;

        public GenericRepository(SchoolContext context)
        {
            this.context = context;
            this.dbSet = context.Set<TEntity>();
        }

        public virtual IEnumerable<TEntity> Get(
            Expression<Func<TEntity, bool>> filter = null,
            Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
            string includeProperties = "")
        {
            IQueryable<TEntity> query = dbSet;

            if (filter != null)
            {
                query = query.Where(filter);
            }

            foreach (var includeProperty in includeProperties.Split
                (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
            {
                query = query.Include(includeProperty);
            }

            if (orderBy != null)
            {
                return orderBy(query).ToList();
            }
            else
            {
                return query.ToList();
            }
        }

        public virtual TEntity GetByID(object id)
        {
            return dbSet.Find(id);
        }

        public virtual void Insert(TEntity entity)
        {
            dbSet.Add(entity);
        }


    }
}

but in real web project Add/Edit/Delete/Find operations might not be very simple and standard, as different entities might require different operations inside these methods.

Currently inside my Asset Management asp.net mvc web application, for example I have a repository method to add a new Server entity , where I do the following main operations:-

  • Create a general Technology object and automatically generates a Tag number.
  • Create a new audit record.
  • Create a new Server.
  • etc

so i find it hard to create Generic repository for almost all my current repository methods, because each entity have different requirements when performing CRUD operations.

so my questions is basically , when developing web applications that have different and complex requirements is having a Generic Repository a tasks that can be achieved ? , from my point of view having a Generic Repository will work only if the requirements are simple and standard.

OR i should style my Repository and action method to work with Generic repository , and failing to do so might be a problem ?

Can anyone advice on this please ?

Thanks

John John
  • 1
  • 72
  • 238
  • 501
  • 2
    Have you considered not use the Repository Pattern? In my experience there is not need to use Repository and Unity Of Work patterns, because the entity framework already is a Repository and Unity of Work, instead I use services classes, I know this is not your question, i'm only sharing my particular experience. http://programmers.stackexchange.com/questions/180851/why-shouldnt-i-use-the-repository-pattern-with-entity-framework http://ayende.com/blog/3955/repository-is-the-new-singleton – TlonXP Oct 29 '14 at 02:45
  • @TlonXP i think your reply, is not related to the question,, but using repository will facilitate code re-usability and testability ,, t – John John Oct 29 '14 at 10:21
  • @TlonXP also the links you have provided are saying that using a Repository with Ef is a good practive,, i can not understand what you are trying to say ? – John John Oct 29 '14 at 10:23
  • **Why** do you want a generic repository? What do you even want to achieve with it? – usr Oct 29 '14 at 14:51
  • it will facilitate code re-usability as the Generic repository will provide shared functionality for Add/Edit/Delete/Find & Get also i can pass sort,filter and .Include to the get,, so if i have 20 entities they all can re-use the same methods defined inside the Generic repository.. – John John Oct 29 '14 at 15:51
  • also one of the most popular and most selling books about asp.net mvc 5 which is "Pro ASP.NET MVC 5" uses Repository pattern very frequent ... – John John Oct 29 '14 at 15:58
  • The generic repository rarely results in true reusability and testing is entirely unrelated. You can test a service class far easier than a generic repository. The usage of a generic repository on top of an ORM is one of the **greatest anti-patterns** in all of modern software development. The very reason it is "hard to achieve" as you noted is because it's a mythical unicorn. Data access is rarely generic, artificial boundaries results in terribly designed applications that can't do simple things. – Chris Marisic Oct 30 '14 at 16:02

2 Answers2

2

Why would we use a generic repository? Because we have common requirements that we want to implement with less code duplication. What if we have a repository with requirements that don't fit into this common pattern? Then we don't try to force this repository into a pattern that it doesn't fit.

The purpose of design patterns is to provide some possible common solutions, in cases where the requirements fit the pattern. The purpose is not to stop thinking about design and not to try to force everything into a pattern.

Mike Stockdale
  • 5,256
  • 3
  • 29
  • 33
  • can you explain what do you mean by " The purpose is not to stop thinking about design and try to force everything into a pattern.", so should i design my application to fit Generic Repository ? – John John Oct 29 '14 at 15:54
  • Sorry, typo - I mean 'not to try to force everything...' – Mike Stockdale Oct 29 '14 at 18:35
  • The thing is, as @TionXP says above, the entity framework already is a Repository and Unit of Work pattern, so I feel that I am already locked into that pattern. But the implementation provided is basic. What if you want to change or augment the Remove method on every entity? By wrapping the `DbSet` in my own `BaseRepository`, I can do that. And if I want to change or augment just one entity? I inherit and override. The pattern is appropriate for that kind of stuff. At the same time, your advice is good, you shouldn't force everything into the pattern - such as complex business logic. – Colin Oct 30 '14 at 10:04
  • You don't need the generic repository pattern to prevent code duplication. If anything the generic repository results in mass code duplication for applications they create from their overbearing encapsulation. You will have far more hoops to jump through to do anything other than the most trivial of all CRUD. Do a join and see how your generic repository falls flat on its face. Do a partial update and see how your generic repository falls flat on its face. Do an exists query or sub select query and see how your generic repository falls flat on its face. Full text search... I could go on – Chris Marisic Oct 30 '14 at 16:12
  • @ChrisMarisic Sorry, but I don't get the problem. The repository I have effectively wraps a `DbSet`, so it can do everything that a `DbSet` can do (if that's what I want). The advantage is that I can limit, modify and extend that behaviour to suit my requirements. – Colin Oct 31 '14 at 12:11
  • @Colin if you're extending `DbSet` you should be inheriting from it. If you're inheriting from `DbSet` and replacing `DbSet` usages with `MyDbSet`, by all means continue. However, the generic repository pattern as colloquially defined instead proxies the DbSet with a negative value abstraction. – Chris Marisic Oct 31 '14 at 18:30
  • So you prefer inheritance over composition? – Colin Nov 01 '14 at 01:20
  • @ChrisMarisic the DbSet is a generic repository. Don't know if it's colloquial, but if you inherit it or wrap it, you're using the pattern. Wrapping it added value for me. – Colin Nov 01 '14 at 07:03
1

I used a generic repository pattern in my application. It let me implement filtering on organisation dependent entities, a soft delete and undo - all without code duplication. If I need to add auditing then I will add it to my generic repository with the confidence that all entities will be audited. As far as I am concerned, creating the generic repository let me add quite complex behaviour that isn't present in the DbSet<T> implementation.

When I have additional or different requirements for an entity, I inherit the generic repository and add or override the behaviour in the sub-class. That lets me add quite complex requirements too.

The DbContext/DbSet<T> is a simple implementation of the unit of work / repository pattern but wrapping it in my own has helped me add complex requirements with minimal code.

Colin
  • 22,328
  • 17
  • 103
  • 197
  • thanks a lot for your reply, and explanations. so i am thinking of having the following Two design approaches;; First to create a Generic Repository which do the basic CRUD operations. after that i create a new Repository class for each entity that inherit the generic repository. so in this case if i want to add an entity let say named Customer i can either use the methods provided by the generic repository or the dedicated methods inside the Customer repository class.. – John John Oct 30 '14 at 00:40
  • Second design will be to add all the repositories which inherit from the Generic Repository to use unit of work, so that i will have all the database operations inside a single transaction, and inside action methods i will create an new instance of the unit of work.. can you advice on this please? – John John Oct 30 '14 at 00:40
  • 1
    I based my app on John Papa's Code Camper code http://www.getbreezenow.com/code-camper-jumpstart His implementation of the UoW hands creation of the repositories off to a `RepositoryProvider` http://stackoverflow.com/a/17212706/150342 – Colin Oct 30 '14 at 09:41
  • but will my two design approaches work also? the are similar to this 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 – John John Oct 30 '14 at 11:05
  • 1
    @johnG the CodeCamper stuff looks similar to that too, so I don't see any problem. – Colin Oct 30 '14 at 11:15
  • meh, you could just as easily have added your soft delete behaviors to your DbContext extending its behavior. – Chris Marisic Oct 30 '14 at 16:03
  • @ChrisMarisic Maybe, but the behaviour I want to modify for soft delete is the 'Remove' method and that is in the 'DbSet' not in the `DbContext`. I am happier keeping the `Remove` responsibility in a class that is separate from the one with the `SaveChanges` responsibility. – Colin Oct 31 '14 at 12:00