Generic Repository for Entity Framework

by Mikael Henriksson 26. March 2009 20:42

UPDATE! You might run into problems with pluralized entity set names. Please read this post for an updated version of the generic repository.

I am a very lazy person. I don’t like to repeat myself for boring tasks like data retrieval. I used to code all my repositories by hand but it took away too much of my valuable time so I decided to try out a different approach.

It’s not complete still but the current solution together with MVC makes it real easy to whip up something quickly. This is of course not something I would recommend in a problem domain or if you are in desperate need of performance but I think it is pretty clever so I thought I’d share it with you.

I started off with an interface because I want feel a bit “restricted” with this generic repository of mine.

public interface IRepository : IDisposable
{
	int Add<T>(T entity);
	long Count<T>();
	long Count<T>(ICriterion<T> criterion);
	int Delete<T>(T entity);
	IList<T> GetAll<T>();
	IList<T> GetAll<T>(ICriterion<T> criterion);
	T GetSingle<T>(ICriterion<T> criterion);
	int Update<T>(T entity);
}

The problem with a generic repository comes firstly in the implementation actually. First of all I found it completely impossible to use LiNQ 2 Entities. CreateQuery is the approach I chose. There are some things that exists in this code that you probably for ease of use would remove. I tried the specification pattern but can’t get it to work with OR | or AND &. I am there for not going to post that part yet. You could easily replace the ICriterion<T> parameters with something like:

public void GetAll<T>(Expression<Func<T, bool>> filter)
{
	MyEntities context = GetObjectContext();
	IList<T> entities = context.CreateQuery<T>(
	"[" + typeof (T).Name + "]").Where(filter).ToList();
	ReleaseObjectContextIfNotReused();

	return entities;
}
My issue with this was that I might want multiple criterions. I’ll get back to that at a later stage but for now I’ll show you the whole code. Keep in mind that this is not something I recommend for professional use and particularly not for complex domain driven models but it suits me fine on my spare time :) Oh, and I almost forgot! The RepositoryBase looks like the one in this post

public class Repository : RepositoryBase, IRepository
{
	private bool _disposed;

	public Repository(MyEntities context)
	{
		_context = context;
		_contextReused = true;
	}

	#region IRepository Members

	public int Add<T>(T entity)
	{
		MyEntities context = GetObjectContext();
		context.AddObject(typeof (T).Name, entity);
		int saveValue = context.SaveChanges();
		ReleaseObjectContextIfNotReused();

		return saveValue;
	}

	public long Count<T>()
	{
		MyEntities context = GetObjectContext();
		var query = new ObjectQuery<T>(typeof (T).Name, 
		context, 
		MergeOption.NoTracking);
		int count = query.Count();
		ReleaseObjectContextIfNotReused();

		return count;
	}

	public long Count<T>(ICriterion<T> criterion)
	{
		int count;
		MyEntities context = GetObjectContext();
		
		IQueryable<T> query =
			new ObjectQuery<T>(typeof (T).Name, 
			context, 
			MergeOption.NoTracking).Where(criterion.EvalPredicate);

		count = query.Count();
		ReleaseObjectContextIfNotReused();

		return count;
	}

	public int Delete<T>(T entity)
	{
		MyEntities context = GetObjectContext();

		object originalItem;
		EntityKey key = context.CreateEntityKey(typeof (T).Name, entity);
		if (context.TryGetObjectByKey(key, out originalItem))
		{
			context.DeleteObject(originalItem);
		}
		int returnValue = context.SaveChanges();
		ReleaseObjectContextIfNotReused();

		return returnValue;
	}

	public IList<T> GetAll<T>()
	{
		MyEntities context = GetObjectContext();
		IList<T> entities = context.CreateQuery<T>(
		"[" + typeof (T).Name + "]").ToList();
		ReleaseObjectContextIfNotReused();

		return entities;
	}

	public IList<T> GetAll<T>(ICriterion<T> criterion)
	{
		MyEntities context = GetObjectContext();
		IList<T> entities = context.CreateQuery<T>(
		"[" + typeof (T).Name + "]").Where(
		criterion.EvalPredicate).ToList();
		ReleaseObjectContextIfNotReused();

		return entities;
	}

	public T GetSingle<T>(ICriterion<T> criterion)
	{
		MyEntities context = GetObjectContext();
		T entity = context.CreateQuery<T>("[" + typeof (T).Name + 
		"]").Where(criterion.EvalPredicate).FirstOrDefault();
		ReleaseObjectContextIfNotReused();

		return entity;
	}

	public int Update<T>(T entity)
	{
		MyEntities context = GetObjectContext();

		object originalItem;
		EntityKey key = context.CreateEntityKey(typeof (T).Name, entity);

		if (context.TryGetObjectByKey(key, out originalItem))
		{
			context.ApplyPropertyChanges(key.EntitySetName, entity);
		}
		int returnValue = context.SaveChanges();
		ReleaseObjectContextIfNotReused();

		return returnValue;
	}

	public void Dispose()
	{
		DisposeObject(true);
		GC.SuppressFinalize(this);
	}

	#endregion

	~Repository()
	{
		DisposeObject(false);
	}

	private void DisposeObject(bool disposing)
	{
		if (_disposed)
		{
			return;
		}
		if (disposing)
		{
			if (_context != null)
				_context.Dispose();
		}
		_disposed = true;
	}
}

Tags:

Entity Framework

blog comments powered by Disqus

About the author

Life architect specialized in programming

Month List

Widget Twitter not found.

Root element is missing.X