Home > .NET Development > >Generic Repository pattern using Entity Framework (EF4) – Simplified

>Generic Repository pattern using Entity Framework (EF4) – Simplified


>I’ve modified Mikael Henriksson generic repository pattern to come up with simplified version. Below illustrate how you can use the generic repository without any or should i say 1 line of code.

IRepository.cs
/// <summary>

/// Generic Repository Interface
/// </summary>
public interface IRepository : IDisposable
{
/// <summary>
/// Method to add new record to <paramref name=”T”/>
/// </summary>
/// <typeparam name=”T”></typeparam>
/// <param name=”entity”></param>
/// <returns></returns>
bool Add <T> (T entity) where T: class,IEntityWithKey;

/// <summary>
/// Method to delete record from <paramref name=”T”/>
/// </summary>
/// <typeparam name=”T”></typeparam>
/// <param name=”entity”></param>
/// <returns></returns>
bool Delete<T>(T entity) where T : class, IEntityWithKey;

/// <summary>
/// Method to update record from <paramref name=”T”/>
/// </summary>
/// <typeparam name=”T”></typeparam>
/// <param name=”entity”></param>
/// <returns></returns>
bool Update<T>(T entity) where T : class, IEntityWithKey;


/// <summary>
/// Returns new Transaction Scope
/// </summary>
/// <returns></returns>
TransactionScope BeginTransaction();


/// <summary>
/// Method to add new record to <paramref name=”T”/> using transaction.
/// You must manually call the CommitTransaction() so that changes will be reflected.
/// </summary>
/// <typeparam name=”T”></typeparam>
/// <param name=”entity”></param>
/// <returns></returns>
bool AddUsingTransaction<T>(T entity) where T : class,IEntityWithKey;


/// <summary>
/// Method to delete record from <paramref name=”T”/> using transaction.
/// You must manually call the CommitTransaction() so that changes will be reflected.
/// </summary>
/// <typeparam name=”T”></typeparam>
/// <param name=”entity”></param>
/// <returns></returns>
bool DeleteUsingTransaction<T>(T entity) where T : class, IEntityWithKey;

/// <summary>
/// Method to update record from <paramref name=”T”/> using transaction.
/// You must manually call the CommitTransaction() so that changes will be reflected.
/// </summary>
/// <typeparam name=”T”></typeparam>
/// <param name=”entity”></param>
/// <returns></returns>
bool UpdateUsingTransaction<T>(T entity) where T : class, IEntityWithKey;


/// <summary>
/// Method that instructs the object context to accept all changes
/// </summary>
void Commit();

/// <summary>
/// Method that returns the count of <paramref name=”T”/>
/// </summary>
/// <typeparam name=”T”></typeparam>
/// <returns></returns>
long Count<T>() where T : class,IEntityWithKey;


/// <summary>
/// Method that returns the count of <paramref name=”T”/>
/// </summary>
/// <typeparam name=”T”></typeparam>
/// <param name=”criterion”></param>
/// <returns></returns>
long Count<T>(Expression<Func<T, bool>> criterion) where T : class, IEntityWithKey;


/// <summary>
/// Method to return all records from <paramref name=”T”/>
/// </summary>
/// <typeparam name=”T”></typeparam>
/// <returns></returns>
List<T> GetAll<T>() where T : class, IEntityWithKey;


/// <summary>
/// Method to return all records from <paramref name=”T”/>
/// </summary>
/// <typeparam name=”T”></typeparam>
/// <param name=”criterion”></param>
/// <returns></returns>
List<T> GetAll<T>(Expression<Func<T, bool>> criterion) where T : class, IEntityWithKey;


/// <summary>
/// Method to return the first record from <paramref name=”T”/>
/// Throws an exception if there’s no result.
/// </summary>
/// <typeparam name=”T”></typeparam>
/// <param name=”criterion”></param>
/// <returns></returns>
T GetSingle<T>(Expression<Func<T, bool>> criterion) where T : class, IEntityWithKey;

/// <summary>
/// Method to return the first record from <paramref name=”T”/> or null value if no record found
/// </summary>
/// <typeparam name=”T”></typeparam>
/// <param name=”criterion”></param>
/// <returns></returns>
T GetSingleOrDefault<T>(Expression<Func<T, bool>> criterion) where T : class, IEntityWithKey;
}
———————————-
DataRepositoryBase.cs

/// <summary>
/// Generic Repository base class for Data Processing
/// </summary>
public abstract class DataRepositoryBase : IRepository
{
protected ObjectContext mContext;
protected bool mContextReused;


/// <summary>
/// Ctor
/// </summary>
/// <param name=”context”></param>
public DataRepositoryBase(ObjectContext context)
{
this.mContext = context;
}


/// <summary>
/// Method to add new record to <paramref name=”T”/>
/// </summary>
/// <typeparam name=”T”></typeparam>
/// <param name=”entity”></param>
/// <returns></returns>
public virtual bool Add<T>(T entity) where T : class, IEntityWithKey
{
mContext.AddObject(mContext.GetEntitySet<T>().Name, entity);
int saveValue = mContext.SaveChanges();
return saveValue > 0 ? true: false;
}


/// <summary>
/// Method to delete record from <paramref name=”T”/>
/// </summary>
/// <typeparam name=”T”></typeparam>
/// <param name=”entity”></param>
/// <returns></returns>
public virtual bool Delete<T>(T entity) where T : class, IEntityWithKey
{
object originalItem;
EntityKey key = mContext.CreateEntityKey(entity.EntityKey.EntitySetName, entity);
if (mContext.TryGetObjectByKey(key, out originalItem))
{
mContext.DeleteObject(originalItem);
}


int returnValue = mContext.SaveChanges();
return returnValue > 0 ? true : false;
}


/// <summary>
/// Method to update record from <paramref name=”T”/>
/// </summary>
/// <typeparam name=”T”></typeparam>
/// <param name=”entity”></param>
/// <returns></returns>
public virtual bool Update<T>(T entity) where T : class, IEntityWithKey
{
object originalItem;
Type type = typeof(T);
EntityKey key = mContext.CreateEntityKey(entity.EntityKey.EntitySetName, entity);
if (mContext.TryGetObjectByKey(key, out originalItem))
{
mContext.ApplyCurrentValues(key.EntitySetName, entity);
}
int returnValue = mContext.SaveChanges();
return returnValue > 0 ? true : false;
}


/// <summary>
/// Method to add new record to <paramref name=”T”/> using transaction.
/// </summary>
/// <typeparam name=”T”></typeparam>
/// <param name=”entity”></param>
/// <returns></returns>
public virtual bool AddUsingTransaction<T>(T entity) where T : class, IEntityWithKey
{
mContext.AddObject(mContext.GetEntitySet<T>().Name, entity);
mContext.SaveChanges(SaveOptions.AcceptAllChangesAfterSave
SaveOptions.DetectChangesBeforeSave);
return true;
}


/// <summary>
/// Method to delete record from <paramref name=”T”/> using transaction.
/// </summary>
/// <typeparam name=”T”></typeparam>
/// <param name=”entity”></param>
/// <returns></returns>
public virtual bool DeleteUsingTransaction<T>(T entity) where T : class, IEntityWithKey
{
object originalItem;
EntityKey key = mContext.CreateEntityKey(entity.EntityKey.EntitySetName, entity);
if (mContext.TryGetObjectByKey(key, out originalItem))
{
mContext.DeleteObject(originalItem);
}
mContext.SaveChanges(SaveOptions.AcceptAllChangesAfterSave
SaveOptions.DetectChangesBeforeSave);
return true;
}


/// <summary>
/// Method to update record from <paramref name=”T”/> using transaction.
/// </summary>
/// <typeparam name=”T”></typeparam>
/// <param name=”entity”></param>
/// <returns></returns>
public virtual bool UpdateUsingTransaction<T>(T entity) where T : class, IEntityWithKey
{
object originalItem;
Type type = typeof(T);
EntityKey key = mContext.CreateEntityKey(entity.EntityKey.EntitySetName, entity);
if (mContext.TryGetObjectByKey(key, out originalItem))
{
mContext.ApplyCurrentValues(key.EntitySetName, entity);
}
mContext.SaveChanges(SaveOptions.AcceptAllChangesAfterSave
SaveOptions.DetectChangesBeforeSave);
return true;
}


public virtual void Commit()
{
mContext.AcceptAllChanges();
}


/// <summary>
/// Method that returns the count of <paramref name=”T”/>
/// </summary>
/// <typeparam name=”T”></typeparam>
/// <returns></returns>
public virtual long Count<T>() where T : class, IEntityWithKey
{
int count = mContext.CreateQuery<T>(“[” + mContext.GetEntitySet<T>().Name + “]”).Count();
return count;
}


/// <summary>
/// Method that returns the count of <paramref name=”T”/>
/// </summary>
/// <typeparam name=”T”></typeparam>
/// <param name=”criterion”></param>
/// <returns></returns>
public virtual long Count<T>(Expression<Func<T, bool>> criterion) where T : class, IEntityWithKey
{
int count = mContext.CreateQuery<T>(“[” + mContext.GetEntitySet<T>().Name + “]”).Count(criterion);
return count;
}


/// <summary>
/// Method to return all records from <paramref name=”T”/>
/// </summary>
/// <typeparam name=”T”></typeparam>
/// <returns></returns>
public virtual List<T> GetAll<T>() where T : class, IEntityWithKey
{
var entities = mContext.CreateQuery<T>(“[” + mContext.GetEntitySet<T>().Name + “]”).ToList();
return entities;
}


/// <summary>
/// Method to return all records from <paramref name=”T”/>
/// </summary>
/// <typeparam name=”T”></typeparam>
/// <param name=”criterion”></param>
/// <returns></returns>
public virtual List<T> GetAll<T>(Expression<Func<T, bool>> criterion) where T : class, IEntityWithKey
{
var entities = mContext.CreateQuery<T>(“[” + mContext.GetEntitySet<T>().Name + “]”).Where(criterion).ToList();
return entities;
}
/// <summary>
/// Method to return the first record from <paramref name=”T”/>
/// Throws an exception if there’s no result.
/// </summary>
/// <typeparam name=”T”></typeparam>
/// <param name=”criterion”></param>
/// <returns></returns>
public virtual T GetSingle<T>(Expression<Func<T, bool>> criterion) where T : class, IEntityWithKey
{
T entity = mContext.CreateQuery<T>(“[” + mContext.GetEntitySet<T>().Name + “]”).First(criterion);
return entity;
}


/// <summary>
/// Method to return the first record from <paramref name=”T”/> or null value if no record found
/// </summary>
/// <typeparam name=”T”></typeparam>
/// <param name=”criterion”></param>
/// <returns></returns>
public virtual T GetSingleOrDefault<T>(Expression<Func<T, bool>> criterion) where T : class, IEntityWithKey
{
T entity = mContext.CreateQuery<T>(“[” + mContext.GetEntitySet<T>().Name + “]”).SingleOrDefault(criterion);
return entity;
}


/// <summary>
/// Method for dispose
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}


protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (mContext != null)
{
mContext.Dispose();
mContext = null;
}
}


}


/// <summary>
/// Returns new Transaction Scope
/// </summary>
/// <returns></returns>
public System.Transactions.TransactionScope BeginTransaction()
{
return new System.Transactions.TransactionScope();
}
 
————————————–
ObjectContextExtension.cs
 
/// <summary>


/// Object Context Extension Methods
/// </summary>
public static class ObjectContextExtensions
{
/// <summary>
/// Extension method for retrieving the EntitySetBase of <paramref name=”T”/>
/// </summary>
/// <typeparam name=”TEntity”></typeparam>
/// <param name=”context”></param>
/// <returns></returns>
internal static EntitySetBase GetEntitySet<TEntity>(this ObjectContext context)
{
EntityContainer container = context.MetadataWorkspace.GetEntityContainer(context.DefaultContainerName, DataSpace.CSpace);
Type baseType = GetBaseType(typeof(TEntity));
EntitySetBase entitySet = container.BaseEntitySets.Where(item => item.ElementType.Name.Equals(baseType.Name)).FirstOrDefault(); return entitySet;
}


/// <summary>
/// Method that returns the base type of <paramref name=”type”/>
/// </summary>
/// <param name=”type”></param>
/// <returns></returns>
private static Type GetBaseType(Type type)
{
var baseType = type.BaseType;
if (baseType != null && baseType != typeof(EntityObject))
{
return GetBaseType(type.BaseType);
}
return type;
}
}
 
—————————
 
This is sample implementation of the Repository.You need to create two class, one class that inherits from DataRepositoryBase (Actual repository) and another that implements IRepository (Test Repository). Of course
you need to have a model that is created using Entity Framework in .NET 4.0.
 
Actual Repository:
 
public class MySampleActualRepository : DataRepositoryBase
{
public MySampleActualRepository()
: base(new MyCustomEntities())
{
}
}
Short code right?, you only need to pass the object context of EF to the base.
 
Test Repository:
 
Create a class MySampleTestRepository that implements IRepository’, I’m not going to show it here but you get the idea right? You can use my previous post especially in the GetAll() method since it’s returning a generic list.
 
 With this two classes in place i think we are ready to try.


Create another method that would return the repository to be used.


public IRepository GetRepository (bool isTest)
{
    if(isTest)
        return new MySampleTestRepository();
    else
       return new MySampleActualRepository();
}


Sample usage:


using (IRepository repository = GetRepository(false))
{
      //Add
       DataEntities.Order order = new DataEntities.Order
      {
           order_ponumber = “00001”;
       };
       repository.Add(order);


      //Update
      var search = repository.GetSingleOrDefault<DataEntities.Order>(i=> i.order_id == order.order_id);
      search.change_date = DateTime.Now;


      repository.Update(search);


     //Delete
     repository.Delete(search);
}


 Sample usage with Transaction Scope:


bool isCommit = false;
using (IRepository repository = GetRepository(false))
{
    using(TransactionScope transactionScope = repository.BeginTransaction())
    {
       //Update
        var search = repository.GetSingleOrDefault<DataEntities.Order>(i=> i.order_id == 1);
       search.change_date = DateTime.Now;
        repository.UpdateUsingTransaction(search);


      //Update # 2
       var search2 = repository.GetSingleOrDefault<DataEntities.Order>(i=> i.order_id == 2);
         search2.change_date = DateTime.Now;
         repository.UpdateUsingTransaction(search);

     isCommit = true;


       if(isCommit)
      {
             transactionScope.Complete();
             repository.Commit();
       }
    }
}


If the update #2 failed, the changes in update #1 will be rollback.


Finally, when building new solution you never need to code the DataComponents part just create the model (EF) then create two class that inherits from DataRepositoryBase and IRepository respectively and it’s done.

Advertisements
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: