I’ve already written a post describing why a generic repository pattern still works using EF. So, if you want to see my opinions on the usage of what I’m about to show, be my guest and click the link. I’ll wait here, I promise.

Here I’m going to show you HOW to do it, complete with code examples. I am going to assume you know how to generate or already have a DbContext object, like you get when adding a new ADO.NET Data Model to your project. This approach works with code-first as well as model/database first implementations. Either method will get you a DbContext object that you can wrap with the generic repository & unit of work.

Let’s say you are writing a game editor and you have a DbContext object called EnemyEntities:

public partial class EnemyEntities : DbContext
{
    public EnemyEntities()
        : base("name=EnemyEntities")
    {
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        throw new UnintentionalCodeFirstException();
    }

    public virtual DbSet<Enemy> Enemies { get; set; }
    public virtual DbSet<Ability> Abilities { get; set; }
}

I will define Enemy and Ability later.

The first thing you need is the definition of a generic repository:

public interface IRepository<T>
{
    void InsertOrUpdate(T entity);
    void Remove(T entity);
    IQueryable<T> Find(Expression<Func<T, bool>> predicate);
    IQueryable<T> FindAll();
    T First(Expression<Func<T, bool>> predicate);
    T FirstOrDefault(Expression<Func<T, bool>> predicate);
}

I also use a generic IUnitOfWork<T> that is IDisposable to force all unitofwork objects to be disposable, since they hold a DbContext object that is IDisposable:

public interface IUnitOfWork<T> : IDisposable where T : class
{
    int Save();
    DbSet<T> DbSet { get; }
    DbEntityEntry Entry(T entity);
}

On to the implementations:

public class DbContextUnitOfwork<T> : IUnitOfWork<T> where T : class
{
    private readonly DbContext _context;

    public DbContextUnitOfwork(DbContext context)
    {
        _context = context;
    }

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

    public int Save()
    {
        return _context.SaveChanges();
    }

    public DbSet<T> DbSet
    {
        get
        {
            return _context.Set<T>();
        }
    }

    public DbEntityEntry Entry(T entity)
    {
        return _context.Entry(entity);
    }
}
public class EFRepository<T> : IRepository<T>
    where T : class, IEntity
{
    private readonly IUnitOfWork<T> _unitOfWork;
    private readonly DbSet<T> _dbSet;

    public EFRepository(IUnitOfWork<T> unitOfWork)
    {
        _unitOfWork = unitOfWork;
        _dbSet = _unitOfWork.DbSet;
    }

    public void InsertOrUpdate(T entity)
    {
        if (entity.Id != default(int))
        {
            if (_unitOfWork.Entry(entity).State == EntityState.Detached)
            {
                _dbSet.Add(entity);
            }
            _unitOfWork.Entry(entity).State = EntityState.Modified;
        }
        else
        {
            _dbSet.Add(entity);
            _unitOfWork.DbSet.Add(entity);
        }
    }

    public void Remove(T entity)
    {
        _dbSet.Remove(entity);
    }

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

    public IQueryable<T> FindAll()
    {
        return _dbSet;
    }

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

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

Note my use of IEntity as a restriction on T in the repository. Here is IEntity:

public interface IEntity
{
    int Id { get; }
}

Yep, that’s it. This is simply so I can ensure that whatever I’m using in a Repository<T> has the Id property, because I need a way to identify (primary key) the object generically when doing InsertOrUpdate(). Look on line 13 of this example to see where it’s used.

Using a common entity interface like this means that you have to add files to your project that correspond to the entities you want repositories for. I will usually add a Models directory, add class files for all the entities I want to use in this pattern, and then go at it changing namespaces and implementing the Id property. Here is an example for Enemy and Ability:

// Generated code from EF
public partial class Enemy
{
    public int EnemyId { get; set; }
    public string Name { get; set; }
    public IEnumerable<Ability> Abilities { get; set; }
}

// Code that you maintain in a separate file 
// which you have to force to be in the same namespace as the generated entity
public partial class Enemy : IEntity
{
    public int Id
    { 
        get
        {
            return EnemyId;
        }
    }
}

// And Ability's generated code:
public partial class Ability
{
    public int AbilityId { get; set; }
    public string Name { get; set; }
}

// And your code:
public partial class Ability : IEntity
{
    public int Id
    {
        get
        {
            return AbilityId;
        }
    }
}

Now that you have  your generic repository, an EF implementation of said repository, as well as the generic unit of work definition and one that uses dbcontext, and a couple entities to work with, how do you use it? This is the part where I typically would write unit tests to tickle out the API, but I will get straight to a potential implementation.

Imagine you’re working on a class that will perform higher level modifications to Enemies in the database. Let’s call it EnemyLogic:

public class EnemyLogic : IDisposable
{
	public EnemyLogic(IRepository<Enemy> enemyRepository, 
                      IUnitOfWork<Enemy> enemyUnitOfWork)
	{
		_enemyRepository = enemyRepository;
		_enemyUnitOfWork = enemyUnitOfWork;
	}

	public void ClearAbilities()
	{
		var enemies = _enemyRepository.Find(e => e.Name == "Baddy")
					.Include(e => e.Abilities)
					.ToList();

		foreach (var enemy in enemies)
		{
			enemy.Abilities = new List<Ability>();
		}

		_enemyUnitOfWork.Save();
	}

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

And to use the EnemyLogic class, you will need to provide concrete instantiated IRepository<Enemy> and IUnitOfWork<Enemy> objects, but that’s easy. I use IoC containers in everything I do, so here is an example of how to instantiate an object from Unity:

// This is typically done in a bootstrapper function that returns IUnityContainer:
var container = new UnityContainer();
container.RegisterType<IUnitOfWork<Enemy>, 
    DbContextUnitOfWork<Enemy>>(new InjectionMember[]
{
	new InjectionConstructor(new object[]
	{
		new EnemyEntities()
	})
});

container.RegisterType<IRepository<Enemy>, EFRepository<Enemy>>();

// Later on you have access to the container:
using (var enemyLogic = container.Resolve<EnemyLogic>())
{
    enemyLogic.ClearAbilities();
}

If you don’t want to use an IoC container, just instantiate it yourself:

var unitOfWork = new DbContextUnitOfWork<Enemy>(new EnemyEntities());
using (var enemyLogic = new EnemyLogic(new EFRepository<Enemy>(unitOfWork), unitOfWork))
{
	enemyLogic.ClearAbilities();
}

I do love me some Inversion of Control, though, since your concrete definitions are handled completely separate from your business logic, the business logic is testable provided you don’t have a direct call to the IoC bootstrapper in it. That’s outside of the scope of this post, though!

If I helped you or you want to send me flames, please comment below!

Leave a Reply

Your email address will not be published. Required fields are marked *