ASP.NET MVC, Nhibernate and repositories for small/medium projects
I am working on a small ASP.NET MVC project at the moment.
I am trying to implement Nhibernate to persist on a MS Sql Server database. Having spent long hours studying DDD and other projects found on the Internet I have decided to go for the repository pattern. Now I ma facing a dilemma. Do I really need a repository when using Nhinbernate? Wouldn't it be b开发者_C百科etter to have a Service Layer (I don't have a Service Layer at the moment) which interacts with Nhinbernate avoiding to write many times something like that:public Domain.Reminder GetById(Guid Code)
{
return (_session.Get<Domain.Reminder>(Code));
}
public Domain.Reminder LoadById(Guid Code)
{
return (_session.Load<Domain.Reminder>(Code));
}
public bool Save(Domain.Reminder Reminder)
{
_session.SaveOrUpdate(Reminder);
return (true);
}
public bool Delete(Domain.Reminder Reminder)
{
_session.Delete(Reminder);
return (true);
}
I found an old Ayende's POST which is against repositories.
I know there's a huge debate around these topics and the answer is always ... depends, but it seems to me that with too many layers of abstractions things get more complicated and hard to follow. Am I wrong?Ayende was against writing a repository the way you did because of the reasons you asked this question, it is repetitive code and NH can handle all of it anyways. He advocates just calling NH directly as you would a repository, and stop worrying about it.
I pretty much agree with him. There really isn't much to gain except for more work.
Use a generic Repository instead. One repository per class can easily be overkill.
I use one repository with Get, Load, Save methods and various Matching-methods (one for Linq and one for my domain queries).
public class NHibernateRepository : IRepository
{
private readonly ISession _session;
public NHibernateRepository(ISession session)
{
_session = session;
}
public T Load<T>(Guid id)
{
return _session.Load<T>(id);
}
public T Get<T>(Guid id)
{
return _session.Get<T>(id);
}
public void Save<T>(T obj)
{
_session.SaveOrUpdate(obj);
}
public void Delete<T>(T obj)
{
_session.Delete(obj);
}
//Get all T
public IEnumerable<T> Matching<T>() where T : DomainObject
{
return _session.CreateCriteria<T>().List<T>();
}
//NHibernate 3.0 Linq
public IQueryable<T> Matching<T>(Expression<Func<T, bool>> predicate)
{
return _session.Query<T>().Where(predicate);
}
public IEnumerable<T> Matching<T>(ICreateCriteria<T> query, params IAppendCriterion[] extraCriterias)
{
var criteria = query.GetCriteria();
foreach (var criterion in extraCriterias)
{
criterion.Append(criteria);
}
return criteria.GetExecutableCriteria(_session).List<T>();
}
}
The last method accepts a ICreateCritiera implementation. Below is the interface and one implementation of it.
public interface ICreateCriteria<T> : ICreateCriteria
{
DetachedCriteria GetCriteria();
}
public class ChallengesAvailableToRound : ICreateCriteria<Challenge>
{
private readonly Guid _roundId;
public ChallengesAvailableToRound(Round round)
{
_roundId = round.Id;
}
public DetachedCriteria GetCriteria()
{
var criteria = DetachedCriteria.For<Challenge>().
CreateAlias("Event", "e").
CreateAlias("e.Rounds", "rounds").
Add(Restrictions.Eq("rounds.Id", _roundId));
return criteria;
}
}
This lets me break out the queries to their own classes and reuse them all over my project easily.
I found some reasons why you should use Repository/DAO/Whatever.
- Unit Testing. I never tried to mock/stub an ISession, but I would say that it should be a LOT more complex than mocking or stubbing a Repository/DAO Interface.
- Reuse of Code. If you write your query directly into your Services/Controllers you will end up duplicating it when you need to reuse a specific query. If you have it wrapper into a Repository, just call it's method.
- Single Responsibility Principle. Spreading your queries around your Controllers makes you break this principle.
- NHibernate Dependency. Ok, this is hard to happen, but if you need to change your ORM, the repositories make it easier ( look, it's easier, not easy :) ). Or even when you need to change the user DataSource from a Database to Microsoft Active Directory, it would be easier.
That's it for know, can't remember anything else.
精彩评论