ASP.NET MVC,Nhibernate和小型/中型项目的存储库

时间:2011-01-21 13:41:49

标签: asp.net-mvc nhibernate repository-pattern

我目前正在开发一个小型的ASP.NET MVC项目 我试图实现Nhibernate持久化MS Sql Server数据库。 花了很长时间研究DDD和互联网上发现的其他项目后,我决定采用存储库模式。 现在我面临两难选择 使用Nhinbernate时我真的需要一个存储库吗? 拥有一个与Nhinbernate交互的服务层(我目前没有服务层)不是更好,避免写多次这样的事情:

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);
}

我找到了一个旧的Ayende的POST,这是针对存储库的 我知道围绕这些主题有一个很大的争论,答案总是......依赖,但在我看来,由于抽象层次过多,事情变得更加复杂,难以理解。 我错了吗?

3 个答案:

答案 0 :(得分:7)

Ayende反对以你的方式编写存储库,因为你提出这个问题的原因,它是重复的代码,NH无论如何都可以处理所有这些问题。他提倡像你一样直接打电话给NH,并且不再担心它。

我非常赞同他。除了更多的工作之外,真的没什么可收获的。

答案 1 :(得分:4)

请改用通用存储库。每个类的一个存储库很容易过度。

我使用一个存储库,包含Get,Load,Save方法和各种匹配方法(一个用于Linq,另一个用于我的域查询)。

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>();
    }
}

最后一个方法接受ICreateCritiera实现。下面是界面和它的一个实现。

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;
    }
}

这让我可以将查询分解为自己的类,并轻松地在我的项目中重复使用它们。

答案 2 :(得分:0)

我找到了你应该使用Repository / DAO / Whatever的一些原因。

  1. 单元测试。我从未试图模拟/存储一个ISession,但我会说它应该比模拟或存根存储库/ DAO接口更复杂。
  2. 重复使用代码。如果将查询直接写入服务/控制器,则在需要重用特定查询时,最终会将其复制。如果你将它包装到存储库中,只需调用它的方法。
  3. Single Responsibility Principle 即可。围绕控制器传播查询会使您违反此原则。
  4. NHibernate依赖。好吧,这很难发生,但是如果你需要更改你的ORM,存储库会让它更容易(看起来,它更容易,不容易:))。或者,即使您需要将用户DataSource从数据库更改为Microsoft Active Directory,也会更容易。
  5. 这是知道的,不记得别的。