I read a lots of content about the usage of Entity Framework/NHibernate (or basically any other modern ORM) with the repository/UnitOfWork patterns. Apparently the community is divided. Some would say the repository pattern is almost mandatory, some others would say that it's a waste of time...
Well, I come up with my "own" design and I just wanted to share it with you in order to get some feedback...
In the past, my company decided to develop and use it's own ORM. It's now a total disaster. Performance, stability (and basically everything else) are terrible. We want to switch to another ORM and we want to be keep the ability to switch from an ORM to another. Indeed, we are now using Sharepoint 2010. It means 3.5 and thus NHibernate 3.4 and Entity Framework 4. We plan to migrate to SharePoint 2013 ASAP in order to be able to rely on .net 4.5/EF 6.1/... So we will have to switch to another ORM pretty soon.
To do so, I have developed a set of classes implementing the "IDatabaseContext" interface.
public interface IDatabaseContext : IDisposable
{
IQueryable<TEntity> AsQueryable<TEntity>()
where TEntity : EntityBase;
IList<TEntity> AsList<TEntity>()
where TEntity : EntityBase;
IList<TEntity> Find<TEntity>(Expression<Func<TEntity, bool>> predicate)
where TEntity : EntityBase;
long Count<TEntity>()
where TEntity : EntityBase;
void Add<TEntity>(TEntity entity)
where TEntity : EntityBase;
void Delete<TEntity>(TEntity entity)
where TEntity : EntityBase;
void Update<TEntity>(TEntity entity)
where TEntity : EntityBase;
}
For example, for the prototype I have decided to use NHibernate:
public class NHibernateDbContext : IDatabaseContext
{
private ISession _session = null;
public NHibernateDbContext(ISessionFactory factory)
{
if (factory == null)
throw new ArgumentNullException("factory");
_session = factory.OpenSession();
}
public IQueryable<TEntity> AsQueryable<TEntity>()
where TEntity : EntityBase
{
return _session.Query<TEntity>();
}
public IList<TEntity> AsList<TEntity>()
where TEntity : EntityBase
{
return _session.QueryOver<TEntity>()
.List<TEntity>();
}
public IList<TEntity> Find<TEntity>(Expression<Func<TEntity, bool>> predicate)
where TEntity : EntityBase
{
...
}
public long Count<TEntity>()
where TEntity : EntityBase
{
return _session.QueryOver<TEntity>()
.RowCountInt64();
}
public void Add<TEntity>(TEntity entity)
where TEntity : EntityBase
{
if (entity == null)
throw new ArgumentNullException("entity");
UseTransaction(() => _session.Save(entity));
}
public void Delete<TEntity>(TEntity entity)
where TEntity : EntityBase
{
...
}
public void Update<TEntity>(TEntity entity)
where TEntity : EntityBase
{
...
}
private void UseTransaction(Action action)
{
using (var transaction = _session.BeginTransaction())
{
try
{
action();
transaction.Commit();
}
catch
{
transaction.Rollback();
throw;
}
}
}
public void Dispose()
{
if (_session != null)
_session.Dispose();
}
}
Eventually, my service layer (each entity are associated with a service) relies on this interface so I don't introduce a dependency over the ORM technology.
public class CountryService<Country> : IService<Country>
where Country : EntityBase
{
private IDatabaseContext _context;
public GenericService(IDatabaseContext context)
{
if (context == null)
throw new ArgumentNullException("context");
_context = context;
}
public IList<Country> GetAll()
{
return _context.AsList<Country>();
}
public IList<Country> Find(Expression<Func<Country, bool>> predicate)
{
return _context.Find(predicate);
}
...
}
Eventually, to call a method from the service layer, you just need two lines of code:
var service = new CountryService(new NHibernateDbContext(...)));
or
var service = new CountryService(new TestDbContext(...)));
...
I find this architecture quite simple and very convenient to use. I didn't find (yet) any drawback/flaws/errors.
So what do you think? Did I miss something big? Is there something I can improve?
Thank you for all your feedback...
Regards,
Sebastien
Personally i think your approach is solid. But equally Im surprised you see this approach as very different to the repository / Unit of Work Pattern.
Your IService layer is directly comparable to a basic Unit of Work layer combined with a repository layer implemented via an interface. The repository layer should implement an Interface and be injected or discovered by a core layer to avoid dependency on the underlying ORM.
The actual implementation of your Repository and Unit of Work layers would be specific to the underlying ORM. But you could replace a RepositoryEF class with RespositoryNH or vice versa.
If done properly and used with dependency injection, the Core application never knows what the ORM is.
The problem is with SOME peoples Repository Patterns, they leak the underlying orm by allowing code that accesses ORM directly or leaks the ORMs structures.
eg if an IREPOSITORY exposed DBSet or Context from Entity Framework, then the whole app can be locked to EF.
eg Unit Of Work Interface
public interface ILuw {
IRepositoryBase<TPoco> GetRepository<TPoco>() where TPoco : BaseObject, new();
void Commit(OperationResult operationResult=null, bool silent=false);
}
and a IRepositoryBase interface
public interface IRepositoryBase<TPoco> : IRepositoryCheck<TPoco> where TPoco : BaseObject,new() {
void ShortDump();
object OriginalPropertyValue(TPoco poco, string propertyName);
IList<ObjectPair> GetChanges(object poco, string singlePropName=null);
IQueryable<TPoco> AllQ();
bool Any(Expression<Func<TPoco, bool>> predicate);
int Count();
IQueryable<TPoco> GetListQ(Expression<Func<TPoco, bool>> predicate);
IList<TPoco> GetList(Expression<Func<TPoco, bool>> predicate);
IList<TPoco> GetListOfIds(List<string>ids );
IOrderedQueryable<TPoco> GetSortedList<TSortKey>(Expression<Func<TPoco, bool>> predicate,
Expression<Func<TPoco, TSortKey>> sortBy, bool descending);
IQueryable<TPoco> GetSortedPageList<TSortKey>(Expression<Func<TPoco, bool>> predicate,
Expression<Func<TPoco, TSortKey>> sortByPropertyName,
bool descending,
int skipRecords,
int takeRecords);
TPoco Find(params object[] keyValues);
TPoco Find(string id); // single key in string format, must eb converted to underlying type first.
int DeleteWhere(Expression<Func<TPoco, bool>> predicate);
bool Delete(params object[] keyValues);
TPoco Get(Expression<Func<TPoco, bool>> predicate);
TPoco GetLocalThenDb(Expression<Func<TPoco, bool>> predicate);
IList<TPoco> GetListLocalThenDb(Expression<Func<TPoco, bool>> predicate);
TU GetProjection<TU>(Expression<Func<TPoco, bool>> predicate, Expression<Func<TPoco, TU>> columns);
/// <summary>
/// To use the projection enter an anonymous type like s => new { s.Id , s.UserName});
/// </summary>
IList<TU> GetProjectionList<TU>(Expression<Func<TPoco, bool>> predicate, Expression<Func<TPoco, TU>> columns);
bool Add(object poco,bool withCheck=true);
bool Remove(object poco);
bool Change(object poco, bool withCheck=true);
bool AddOrUpdate(TPoco poco, bool withCheck = true);
}
Your approach is sound, but there are few considerations
AsList<TEntity>() method is a recipe for abuse, many new developers might user this method to get list of data and will probably do the filtering in memory
How transactions are handled.
Personally I'd go with the repository pattern phil soady suggested, but I would not use that much of methods in the IRepository interface.
public interface IRepository<T> where T:IEntity
{
T Single(long id);
T Save(T entity);
void Delete(T entity);
IQueryable<T> FilterBy(Expression<Func<T, bool>> expression);
}
And when the type specific query is required it's handled in it's own repository, like
public interface IContactRepository : IRepository<Contact>
{
IList<Contact> GetForUser(int userId);
}
And handling of transactions, I would go for Using the unit of work per request pattern where you don't have to manually handle transaction each and every time database is updated. A global ActionFilter would be enough to achieve this.
Related
I have been assigned a new project and I have decided to give EF a go.In this project all I do is getting data there is no persistence.I have to implement some caching and that's it.
Reading about Repository patterns I have found tons of code samples etc... they seem all wrong to me.They implement a one to one Entity to Repository.
In my project I just need reading data not saving etc... just reading.I have 100s entities I cannot create 100s repository seems all wrong.
I have decided to start simple and I all need is this:
public interface IRepository : IDisposable
{
IEnumerable<T> GetAll<T>() where T : class;
IEnumerable<T> Find<T>(Expression<Func<T, bool>> predicate) where T : class;
T GetOne<T>(Expression<Func<T, bool>> predicate) where T : class;
}
public class Repository : IRepository
{
public IEnumerable<T> GetAll<T>() where T : class
{
return ???.ToArray();
}
public IEnumerable<T> Find<T>(Expression<Func<T, bool>> predicate) where T : class
{
return ???.Where(predicate).ToArray();
}
public T GetOne<T>(Expression<Func<T, bool>> predicate) where T : class
{
return ???.Where(predicate).FirstOrDefault();
}
public void Dispose()
{
throw new NotImplementedException();
}
}
What I am struggling with is where i put the "???" that should be my IdbSet.
How could I Implement my concrete repository?Any suggestions or noddy test sample will do.
many thanks
First, you better change the GetAll() and Find() methods to return IQueryable<T> instead of IEnumerable<T>, so that further querying on the dataset would be implemented using Linq-to-Entities.
As of the EF implementation, try something like this:
public class EFRepository : DbContext, IRepository
{
// ctor:
// pass a full connecting-string, or "name=someName" from configuration
public EFRepository(string connectionStringOrName) : base(connectionStringOrName)
{
// init sets
this.Entities1 = this.Set<EntityOfSomeType>();
this.Entities2 = this.Set<EntityOfOtherType>();
}
public IEnumerable<T> GetAll<T>() where T : class
{
return this.Set<T>().ToArray();
}
public IEnumerable<T> Find<T>(Expression<Func<T, bool>> predicate) where T : class
{
return this.Set<T>().Where(predicate).ToArray();
}
public T GetOne<T>(Expression<Func<T, bool>> predicate) where T : class
{
return this.Set<T>.FirstOrDefault(predicate);
}
public void Dispose()
{
base.Dispose();
}
// Your DbSets...
public IDbSet<EntityOfSomeType> Entities1 { get; set; }
public IDbSet<EntityOfAnotherType> Entities2 { get; set; }
}
(I used DbContext with the assumption that you're going code-first)
I have been learning about MVC and I am using Entity Framework. What I am trying to understand is repositories. Every tutorial I've read deals with one entity and at that level I have a understanding, but what about multiple tables. I use a variation of code-first, where I associate my model classes with an existing database. In my database,there are three tables; User, Journey and UserJourney (linked table). User and Journey have a many-to-many relationship. Should I have a repository for each entity? Has aggregates any use here? In the long run I want to query the database to find user's journeys and pass to a view.
My question is perhaps vague, but I am quite confused on this matter, so any help in understanding this would be appreciated!
Normally repositories should not be defined for each entity but rather per aggregate root. You have entities that cannot live by themselves, but are related to some parent entity. This parent entity is called aggregate root and you should have a repository for each of them.
Search for a concept called GenericRepository. It will help in getting rid of the repository for each entity problem. Sample below:
public interface IGenericRepository<T> where T : class
{
IEnumerable<T> GetAll();
T SingleOrDefault(Expression<Func<T, bool>> predicate);
IEnumerable<T> Get(Expression<Func<T, bool>> predicate);
void Insert(T entity);
void Update(T entity);
void Delete(object id);
void Delete(T entity);
}
public class GenericRepository<T> : IGenericRepository<T> where T : class
{
readonly MyDbContext _context;
readonly DbSet<T> _dbSet;
public GenericRepository(PfsDbContext context)
{
_context = context;
_dbSet = context.Set<T>();
}
public virtual IEnumerable<T> GetAll()
{
return _dbSet.AsEnumerable();
}
public T SingleOrDefault(Expression<Func<T, bool>> predicate)
{
return _dbSet.Where(predicate).SingleOrDefault();
}
public IEnumerable<T> Get(Expression<Func<T, bool>> predicate)
{
return _dbSet.Where(predicate);
}
public void Insert(T entity)
{
_dbSet.Add(entity);
}
public void Update(T entityToUpdate)
{
_dbSet.Attach(entityToUpdate);
_context.Entry(entityToUpdate).State = EntityState.Modified;
}
public void Delete(T entity)
{
if (_context.Entry(entity).State == EntityState.Detached)
{
_dbSet.Attach(entity);
}
_dbSet.Remove(entity);
}
public void Delete(object id)
{
var entityToDelete = _dbSet.Find(id);
Delete(entityToDelete);
}
}
You can then use it as
var userRepository = new GenericRepository<User>(_context);
var journeyRepository = new GenericRepository<Journey>(_context);
So the problem I am trying to solve is this; We are using Entity Framework to access our Oracle database that has 1200-1500 tables. Now mind you we are not accessing them all, but possibly could have 800+ to access. We are using the UnitOfWork --> Repository --> Service pattern and that works great, but we are trying to figure out if we should have one big DbContext, or multiple little contexts that are specific to the task at hand.
Our UnitOfWork is setup using an EFUnitOfWorkBase like so:
public abstract class EFUnitOfWorkBase : IUnitOfWork
{
private bool isDisposed = false;
public DbContextBase Context { get; set; }
protected EFUnitOfWorkBase(DbContextBase context)
{
Context = context;
}
public int Commit()
{
return Context.SaveChanges();
}
public void Dispose()
{
if (!isDisposed)
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
isDisposed = true;
if (disposing)
{
if (this.Context != null)
this.Context.Dispose();
}
}
public IRepository<TEntity> GetRepository<TEntity>() where TEntity : Common.EntityBase<TEntity>
{
return new Repository<TEntity>(this);
}
}
Any unit of work we create extends that base one and provides the context like so:
public class EmployeeDirectoryUnitOfWork : EFUnitOfWorkBase
{
public EmployeeDirectoryUnitOfWork(string connectionString)
: base(new EmployeeDirectoryContext(connectionString))
{
}
}
The DbContext is passed a connection string through the unit of work.
The Repository looks like this:
public abstract class RepositoryBase<TEntity> : IRepository<TEntity> where TEntity : class
{
protected DbContextBase Context;
protected DbSet<TEntity> EntitySet;
public RepositoryBase(EFUnitOfWorkBase unitOfWork)
{
Enforce.ArgumentNotNull(unitOfWork, "unitOfWork");
Context = unitOfWork.Context;
EntitySet = Context.Set<TEntity>();
}
public TEntity Add(TEntity entity)
{
Enforce.ArgumentNotNull(entity, "entity");
return EntitySet.Add(entity);
}
public TEntity Attach(TEntity entity)
{
Enforce.ArgumentNotNull(entity, "entity");
return EntitySet.Attach(entity);
}
public TEntity Delete(TEntity entity)
{
Enforce.ArgumentNotNull(entity, "entity");
return EntitySet.Remove(entity);
}
public System.Linq.IQueryable<TEntity> Query()
{
return EntitySet.AsQueryable();
}
public TEntity Save(TEntity entity)
{
Enforce.ArgumentNotNull(entity, "entity");
Attach(entity);
Context.MarkModified(entity);
return entity;
}
}
Any suggestions on how to best handle this situation?
In such a case when you have a large application like this, I think you should probably go for a more Domain Driven Design approach and split the contexts into some separate, bounded contexts. This way when later developers are adding features to the program they will be confined to only being able to access certain tables depending on which context they will be using there.
For better information, Julie Lerman recently came out with a course on Pluralsight about Entity Framework in the Enterprise that's really good. She posted a small clip of it (actually about bounded contexts) on this site. It's a very good course, and I highly recommend it, especially for what you appear to be doing.
I am looking into creating an Entity Framework 4 generic repository for a new ASP.NET MVC project i am working on. I have been looking at various tutorials and they all seem to use the Unit of Work pattern ...
From what i have been reading, EF is using this already within the ObjectContext and you are simply extending this to make your own Units of Work.
Source: http://dotnet.dzone.com/news/using-unit-work-pattern-entity?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+zones%2Fdotnet+(.NET+Zone)
Why would one go to the effort of doing this?
Is this the preferred way of working with generic repositories?
Many thanks,
Kohan.
This is not the way I would work with generic repositories. First of all, I would share ObjectContext between ClassARepository, CalssBRepository and other repositories in current request. Using IOC container, using injection and per request behavior is recommended:
This is how my generic repositories look like:
public interface IRepository<T>
{
//Retrieves list of items in table
IQueryable<T> List();
IQueryable<T> List(params string[] includes);
//Creates from detached item
void Create(T item);
void Delete(int id);
T Get(int id);
T Get(int id, params string[] includes);
void SaveChanges();
}
public class Repository<T> : IRepository<T> where T : EntityObject
{
private ObjectContext _ctx;
public Repository(ObjectContext ctx)
{
_ctx = ctx;
}
private static string EntitySetName
{
get
{
return String.Format(#"{0}Set", typeof(T).Name);
}
}
private ObjectQuery<T> ObjectQueryList()
{
var list = _ctx.CreateQuery<T>(EntitySetName);
return list;
}
#region IRepository<T> Members
public IQueryable<T> List()
{
return ObjectQueryList().OrderBy(#"it.ID").AsQueryable();
}
public IQueryable<T> List(params string[] includes)
{
var list = ObjectQueryList();
foreach(string include in includes)
{
list = list.Include(include);
}
return list;
}
public void Create(T item)
{
_ctx.AddObject(EntitySetName, item);
}
public void Delete(int id)
{
var item = Get(id);
_ctx.DeleteObject(item);
}
public T Get(int id)
{
var list = ObjectQueryList();
return list.Where("ID = #0", id).First();
}
public T Get(int id, params string[] includes)
{
var list = List(includes);
return list.Where("ID = #0", id).First();
}
public void SaveChanges()
{
_ctx.SaveChanges();
}
#endregion
}
ObjectContext is injected through constructor. List() methods return IQueryable for further processing in business layer (service) objects. Service layer returns List or IEnumerable, so there is no deferred execution in views.
This code was created using EF1. EF4 version can be a little different and simpler.
Doing my first SL4 MVVM RIA based application and i ran into the following situation:
updating a record (EF4,NO-POCOS!!) in the SL-client seems to take place, but values in the dbms are unchanged. Debugging with Fiddler the message on save is (amongst others):
EntityActions.nil� b9http://schemas.microsoft.com/2003/10/Serialization/Arrays^HasMemberChanges�^Id�^ Operation�Update
I assume that this says only: hey! the dbms should do an update on this record, AND nothing more! Is that right?!
I 'm using a generic repository like this:
public class Repository<T> : IRepository<T> where T : class
{
IObjectSet<T> _objectSet;
IObjectContext _objectContext;
public Repository(IObjectContext objectContext)
{
this._objectContext = objectContext;
_objectSet = objectContext.CreateObjectSet<T>();
}
public IQueryable<T> AsQueryable()
{
return _objectSet;
}
public IEnumerable<T> GetAll()
{
return _objectSet.ToList();
}
public IEnumerable<T> Find(Expression<Func<T, bool>> where)
{
return _objectSet.Where(where);
}
public T Single(Expression<Func<T, bool>> where)
{
return _objectSet.Single(where);
}
public T First(Expression<Func<T, bool>> where)
{
return _objectSet.First(where);
}
public void Delete(T entity)
{
_objectSet.DeleteObject(entity);
}
public void Add(T entity)
{
_objectSet.AddObject(entity);
}
public void Attach(T entity)
{
_objectSet.Attach(entity);
}
public void Save()
{
_objectContext.SaveChanges();
}
}
The DomainService Update Method is the following:
[Update]
public void UpdateCulture(Culture currentCulture)
{
if (currentCulture.EntityState == System.Data.EntityState.Detached)
{
this.cultureRepository.Attach(currentCulture);
}
this.cultureRepository.Save();
}
I know that the currentCulture-Entity is detached. What confuses me (amongst other things) is this: is the _objectContext still alive? (which means it "will be"??? aware of the changes made to record, so simply calling Attach() and then Save() should be enough!?!?)
What am i missing?
Development Environment: VS2010RC - Entity Framework 4 (no POCOs)
Thanks in advance
You are attaching the culture in the context, but you are not telling the context that the object has actually changed.
The generated code I have on my machine is:
public void UpdateDepartment(Department currentDepartment) {
if ((currentDepartment.EntityState == EntityState.Detached)) {
this.ObjectContext.AttachAsModified(currentDepartment, this.ChangeSet.GetOriginal(currentDepartment));
}
}
What matters is the 'AttachAsModified'.
Timores pointed me in the correct direction, the solution (as far as my problem concerns) is very simple: simply add this method to the repository and we're done:
public void AttachModified(T entity)
{
_objectSet.Attach(entity);
_context.ObjectStateManager.ChangeObjectState(entity, System.Data.EntityState.Modified);
}
Now instead of calling Attach() we call AttachModified().
Thank you Timores!