Skip to content

Instantly share code, notes, and snippets.

@ferventcoder
Created August 16, 2012 17:21
Show Gist options
  • Save ferventcoder/3371820 to your computer and use it in GitHub Desktop.
Save ferventcoder/3371820 to your computer and use it in GitHub Desktop.
Db First Generic Repository with DbFirst Model First - allows use of stored procedures transparently - it's no coincidence that the IRepository is the same as code first implements
public class EntityFrameworkDatabaseFirstRepository : IRepository
{
private readonly IDatabaseFirstDataContext _dataContext;
/// <summary>
/// Gets the data context.
/// </summary>
protected IDatabaseFirstDataContext DataContext
{
get
{
return _dataContext;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="EntityFrameworkDatabaseFirstRepository"/> class.
/// </summary>
/// <param name="dataContext">The data context.</param>
public EntityFrameworkDatabaseFirstRepository(IDatabaseFirstDataContext dataContext)
{
_dataContext = dataContext;
}
/// <summary>
/// Commits the changes.
/// </summary>
public void CommitChanges()
{
this.Log().Debug(() => "EF is saving all changes to the repository");
_dataContext.SaveChanges();
}
/// <summary>
/// Gets the specified key.
/// </summary>
/// <typeparam name="T"> A class that implements <see cref="IDomain" /> with a default constructor </typeparam>
/// <param name="key">The key.</param>
/// <returns></returns>
public T Get<T>(params object[] key) where T : class, IDomain, new()
{
this.Log().Debug(() => "EF is searching for '{0} ({1})'".FormatWith(typeof(T).Name, key));
var set = _dataContext.Set<T>();
//http://stackoverflow.com/questions/5794902/generic-getbyid-for-complex-pk
var keyNames = set.EntitySet.ElementType.KeyMembers.Select(k => k.Name).ToArray();
if (key.Length != keyNames.Length)
{
throw new ArgumentException("Invalid number of key members");
}
var keyPairs = keyNames.Zip(key, (keyName, keyValue) => new KeyValuePair<string, object>(keyName, keyValue));
var entityKey = new EntityKey(set.EntitySet.Name, keyPairs);
return (T)_dataContext.GetObjectByKey(entityKey);
}
/// <summary>
/// Gets all instances of <see cref="T"/> . Can be used with a linq query to limit results
/// </summary>
/// <typeparam name="T">A class that implements <see cref="IDomain"/> with a default constructor</typeparam>
/// <returns>
/// A list of <see cref="T"/>
/// </returns>
public IQueryable<T> GetAll<T>() where T : class, IDomain, new()
{
this.Log().Debug(() => "EF is performing a query for '{0}'".FormatWith(typeof(T).Name));
return _dataContext.Set<T>();
}
/// <summary>
/// Inserts the specified entity instance of <see cref="T"/> on commit.
/// </summary>
/// <typeparam name="T">A class that implements <see cref="IDomain"/> with a default constructor</typeparam>
/// <param name="entity">The entity.</param>
public void InsertOnCommit<T>(T entity) where T : class, IDomain, new()
{
//entity.SetInsertProperties();
this.Log().Debug(() => "EF is inserting a '{0}'".FormatWith(typeof(T).Name));
_dataContext.Set<T>().AddObject(entity);
}
/// <summary>
/// Deletes the specified entity instance of <see cref="T"/> on commit.
/// </summary>
/// <typeparam name="T">A class that implements <see cref="IDomain"/> with a default constructor</typeparam>
/// <param name="entity">The entity.</param>
public void DeleteOnCommit<T>(T entity) where T : class, IDomain, new()
{
this.Log().Debug(() => "EF is deleting a '{0}'".FormatWith(typeof(T).Name));
_dataContext.Set<T>().DeleteObject(entity);
}
}
//Name and namespace is an exact match to the EDMX Object Context implementation
public partial class DatabaseFirstObjectContext : ObjectContext, IDatabaseFirstDataContext
{
public ObjectSet<TEntity> Set<TEntity>() where TEntity : class
{
return CreateObjectSet<TEntity>();
}
public new int SaveChanges()
{
foreach (ObjectStateEntry obj in ObjectStateManager.GetObjectStateEntries(EntityState.Added).OrEmptyListIfNull())
{
var entity = (IDomain) obj.Entity;
if (entity != null)
{
entity.SetReadyForInsert();
}
}
foreach (ObjectStateEntry obj in ObjectStateManager.GetObjectStateEntries(EntityState.Modified).OrEmptyListIfNull())
{
var entity = (IDomain) obj.Entity;
if (entity != null)
{
entity.SetReadyForUpdate();
}
}
return base.SaveChanges(SaveOptions.AcceptAllChangesAfterSave);
}
}
// name here is an exact match to a class in the EDMX model
// repeat this pattern as many times as is necessary.
// for an ID that is multiple parts (composite), create a class and put those in it, then have the Id return those back and set the items in the model when setting
public partial class ClassThatIsInEDMXModel : IDomain<int>
{
public int Id
{
get { return ModelsID; }
set { ModelsID = value; }
}
public void SetInsertProperties() {}
public void SetUpdateProperties() {}
}
public interface IDomain
{
DateTime CreateDate { get; set; }
int CreateUserId { get; set; }
DateTime UpdateDate { get; set; }
int UpdateUserId { get; set; }
void SetInsertProperties();
void SetUpdateProperties();
}
/// <summary>
/// For situations where you need access to the key
/// </summary>
/// <typeparam name="TKeyType">The type of the key.</typeparam>
public interface IDomain<TKeyType> : IDomain
{
/// <summary>
/// Gets or sets the id.
/// </summary>
/// <value>
/// The id.
/// </value>
TKeyType Id { get; set; }
}
public static class IDomainExtensions
{
public static void SetReadyForInsert(this IDomain domain)
{
domain.SetInsertProperties();
domain.CreateDate = DateTime.Now;
domain.UpdateDate = DateTime.Now;
domain.CreateUserId = ApplicationParameters.GetCurrentUserId();
domain.UpdateUserId = ApplicationParameters.GetCurrentUserId();
}
public static void SetReadyForUpdate(this IDomain domain)
{
domain.SetUpdateProperties();
domain.UpdateDate = DateTime.Now;
domain.UpdateUserId = ApplicationParameters.GetCurrentUserId();
}
}
/// <summary>
/// The data context used work with the database. This interface repeats items already in the DbContext or ObjectContext
/// </summary>
public interface IDataContext
{
/// <summary>
/// Saves the changes.
/// </summary>
int SaveChanges();
}
public interface IDatabaseFirstDataContext : IDataContext
{
/// <summary>
/// Grabs a set, can be used with linq queries to limit results
/// </summary>
/// <typeparam name="TEntity">The type of the entity.</typeparam>
/// <returns></returns>
ObjectSet<TEntity> Set<TEntity>() where TEntity : class;
/// <summary>
/// Gets the object by key.
/// </summary>
/// <param name="key">The key.</param>
/// <returns></returns>
object GetObjectByKey(EntityKey key);
}
/// <summary>
/// The data context used work with the database. This interface repeats items already in the DbContext
/// </summary>
public interface ICodeFirstDataContext : IDataContext
{
/// <summary>
/// Grabs a set, can be used with linq queries to limit results
/// </summary>
/// <typeparam name="TEntity">The type of the entity.</typeparam>
/// <returns></returns>
DbSet<TEntity> Set<TEntity>() where TEntity : class;
/// <summary>
/// Gets the database.
/// </summary>
Database Database { get; }
}
/// <summary>
/// The repository for working with the database.
/// </summary>
public interface IRepository
{
/// <summary>
/// Commits the changes.
/// </summary>
void CommitChanges();
/// <summary>
/// Gets an instance of <see cref="T" /> with the specified key.
/// </summary>
/// <typeparam name="T"> A class that implements <see cref="IDomain" /> with a default constructor </typeparam>
/// <param name="key"> The key. </param>
/// <returns> </returns>
T Get<T>(params object[] key) where T : class, IDomain, new();
/// <summary>
/// Gets all instances of <see cref="T" /> . Can be used with a linq query to limit results
/// </summary>
/// <typeparam name="T"> A class that implements <see cref="IDomain" /> with a default constructor </typeparam>
/// <returns> A list of <see cref="T" /> </returns>
IQueryable<T> GetAll<T>() where T : class, IDomain, new();
/// <summary>
/// Inserts the specified entity instance of <see cref="T" /> on commit.
/// </summary>
/// <typeparam name="T"> A class that implements <see cref="IDomain" /> with a default constructor </typeparam>
/// <param name="entity"> The entity. </param>
/// <returns> The Id of the inserted item </returns>
void InsertOnCommit<T>(T entity) where T : class, IDomain, new();
/// <summary>
/// Deletes the specified entity instance of <see cref="T" /> on commit.
/// </summary>
/// <typeparam name="T"> A class that implements <see cref="IDomain" /> with a default constructor </typeparam>
/// <param name="entity"> The entity. </param>
void DeleteOnCommit<T>(T entity) where T : class, IDomain, new();
}
/// <summary>
/// The entity framework repository
/// </summary>
public class EntityFrameworkCodeFirstRepository : IRepository
{
private readonly ICodeFirstDataContext _dataContext;
/// <summary>
/// Gets the data context.
/// </summary>
protected ICodeFirstDataContext DataContext
{
get { return _dataContext; }
}
/// <summary>
/// Initializes a new instance of the <see cref="EntityFrameworkCodeFirstRepository" /> class.
/// </summary>
/// <param name="dataContext"> The data context. </param>
public EntityFrameworkCodeFirstRepository(ICodeFirstDataContext dataContext)
{
_dataContext = dataContext;
}
/// <summary>
/// Commits the changes.
/// </summary>
public virtual void CommitChanges()
{
this.Log().Debug(() => "EF is saving all changes to the repository");
_dataContext.SaveChanges();
}
/// <summary>
/// Gets an instance of <see cref="T" /> with the specified key.
/// </summary>
/// <typeparam name="T"> A class that implements <see cref="IDomain" /> with a default constructor </typeparam>
/// <param name="key"> The key. </param>
/// <returns> </returns>
public virtual T Get<T>(params object[] key) where T : class, IDomain, new()
{
this.Log().Debug(() => "EF is searching for '{0} ({1})'".FormatWith(typeof (T).Name, key));
return _dataContext.Set<T>().Find(key);
}
/// <summary>
/// Gets all instances of <see cref="T" /> . Can be used with a linq query to limit results
/// </summary>
/// <typeparam name="T"> A class that implements <see cref="IDomain" /> with a default constructor </typeparam>
/// <returns> A list of <see cref="T" /> </returns>
public virtual IQueryable<T> GetAll<T>() where T : class, IDomain, new()
{
this.Log().Debug(() => "EF is performing a query for '{0}'".FormatWith(typeof (T).Name));
return _dataContext.Set<T>();
}
/// <summary>
/// Inserts the specified entity instance of <see cref="T" /> on commit.
/// </summary>
/// <typeparam name="T"> A class that implements <see cref="IDomain" /> with a default constructor </typeparam>
/// <param name="entity"> The entity. </param>
/// <returns> The Id of the inserted item </returns>
public virtual void InsertOnCommit<T>(T entity) where T : class, IDomain, new()
{
//entity.SetInsertProperties();
this.Log().Debug(() => "EF is inserting a '{0}'".FormatWith(typeof (T).Name));
_dataContext.Set<T>().Add(entity);
}
/// <summary>
/// Deletes the specified entity instance of <see cref="T" /> on commit.
/// </summary>
/// <typeparam name="T"> A class that implements <see cref="IDomain" /> with a default constructor </typeparam>
/// <param name="entity"> The entity. </param>
public virtual void DeleteOnCommit<T>(T entity) where T : class, IDomain, new()
{
//this.Log().Debug(() => "EF is deleting '{0} ({1})'".FormatWith(typeof (T).Name, entity.GetKey()));
this.Log().Debug(() => "EF is deleting a '{0}'".FormatWith(typeof (T).Name));
_dataContext.Set<T>().Remove(entity);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment