Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 better 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?

like image 220
LeftyX Avatar asked Jan 21 '11 13:01

LeftyX


2 Answers

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.

like image 167
Matt Briggs Avatar answered Oct 13 '22 06:10

Matt Briggs


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.

like image 28
Kenny Eliasson Avatar answered Oct 13 '22 06:10

Kenny Eliasson