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;
}
}