Wow, what a sexy title!
This post shows how you can have a repository pattern with the entity framework .
So, here we have a generic repository interface through which you can do all the nice things. You would normally use Castle Windsor (or similar Dependency Injection tool) to configure the Repository implementation (such as EFRepository) so you then just have a dependency on the interface, which is nice. Here's a snippet of how to configure the EFRepository to be used for all requests for IRepository from Castle Windsor. Note the ability to change object contexts and even the repository implementation, as long as IRepository is supported, the application won't care.
<castle> <components>
<component id="objectContext" type="YourObjectContext" ></component> <component id="iEFRepository" service="YourIRepository" type="YourEFRepository" <parameters> <objectContext>${objectContext}</objectContext> </parameters> </component> </components> </castle>
Note the reflection in the EFRepository implementation which allows you to query and work with all types in a hierarchy. By default you can't work directly with sub types in EF, you have to do extra work to get to them. The reflection gets the base type before communication with the ObjectContext to ensure minimal fussing about for the developer. Note i don't understand why this isn't built in to be honest, perhaps they ran out of time!
The whole point of this is that you avoid using your application's ObjectContext explicitly and only work with the core business entities that are then managed by the Entity Framework. This allows us to have a good separation of concerns between the various layers (although our entities are not pure POCO sadly). Note that i have only exposed the most widely used features of ObjectContext, you can extend your Repository interface and implementation to expose more advanced parts of the ObjectContext implementation if needs be.
In the future, EF may move towards greater persistence ignorance, but in the mean time structuring your application working off a Repository interface will mean minimal changes as EF changes moving forwards.
IRepository interface
public interface IRepository {
/// <summary> /// Return reference to an underlying repository context /// </summary> /// <returns>the repository context</returns> object GetRepositoryContext();
/// <summary> /// Return strongly typed IQueryable /// </summary> IQueryable<T> GetQuery<T>();
/// <summary> /// Load entity from the repository or store if necessary /// </summary> /// <typeparam name="T">the entity type to load</typeparam> /// <param name="where">where condition</param> /// <returns>the loaded entity</returns> T Load<T>(Expression<Func<T, bool>> whereCondition);
/// <summary> /// Mark entity to be deleted within the repository /// </summary> /// <param name="entity">The entity to delete</param> void Delete<T>(T entity);
/// <summary> /// Add entity to the repository /// </summary> /// <param name="entity">the entity to add</param> /// <returns>The added entity</returns> void Add<T>(T entity);
/// <summary> /// Updates entity within the the repository /// </summary> /// <param name="entity">the entity to update</param> /// <returns>The updates entity</returns> void Update<T>(T entity);
/// <summary> /// Save all changes from repository to store /// </summary> /// <returns>Total number of objects affected</returns> int SaveChanges();
}
Now we have our proper EFRepository.......
EFRepository implementation
using System; using System.Linq; using System.Linq.Expressions; using System.Reflection;
public class EFRepository : IRepository, IDisposable { private ObjectContext _objectContext;
private Type GetBaseType(Type type) { Type baseType = type.BaseType; if (baseType != null && baseType != typeof(EntityObject)) { return GetBaseType(type.BaseType); } return type; }
private bool HasBaseType(Type type, out Type baseType) { Type originalType = type.GetType(); baseType = GetBaseType(type); return baseType != originalType; }
public EFRepository(ObjectContext objectContext) { _objectContext = objectContext; }
public ObjectContext ObjectContext { get { return _objectContext; } }
public object GetRepositoryContext() { return this.ObjectContext; }
public IQueryable<T> GetQuery<T>() { Type baseType; if (HasBaseType(typeof(T), out baseType)) { return this.ObjectContext.CreateQuery<T>("[" + baseType.Name.ToString() + "]").OfType<T>(); } else { return this.ObjectContext.CreateQuery<T>("[" + typeof(T).Name.ToString() + "]"); } }
public T Load<T>(Expression<Func<T, bool>> whereCondition) { return this.GetQuery<T>().Where(whereCondition).First(); }
public void Add<T>(T entity) { this.ObjectContext.AddObject(GetBaseType(typeof(T)).Name.ToString(), entity); }
public void Update<T>(T entity) { EntityObject entityObject = entity as EntityObject; ObjectContext objectContext = this.ObjectContext; objectContext.ApplyPropertyChanges( GetBaseType(typeof(T)).Name.ToString(), objectContext.GetObjectByKey(entityObject.EntityKey) ); }
public void Delete<T>(T entity) { this.ObjectContext.DeleteObject(entity); }
public int SaveChanges() { return this.ObjectContext.SaveChanges(); }
public void Dispose() { if (_objectContext != null) { _objectContext.Dispose(); } }
Powered by: newtelligence dasBlog 1.9.6264.0
Disclaimer The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.
© Copyright 2008, Keith Patton
E-mail