ASP.NET MVC, Nhibernate 和仓储在中小型项目中的应用。

5

我目前正在进行一个小的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过时的文章,反对使用仓储模式。
我知道这些话题一直存在很大的争议,答案总是...视情况而定,但是我觉得使用太多的抽象层会使事情变得更加复杂和难以理解。
我错了吗?


只是一个小提示。没有所谓的小中型项目,它可能现在很小,但明天你的经理会要求你添加另一个功能,然后再添加另一个,最终你将拥有一个具有小中型架构的大型项目。我真的不喜欢预先进行大量设计,但有时你需要提前考虑一下。 - goenning
我完全同意你的看法,但是实际上,如果不是因为我将来可能不使用 nihbernate,我真的看不出使用 repository 的好处。这会产生很多额外的工作量,而我目前无法证明其合理性。 - LeftyX
3个回答

7

Ayende反对按照你所做的方式编写存储库,因为你提出这个问题的原因,它是重复的代码,而NH无论如何都可以处理所有问题。他主张直接像调用存储库一样直接调用NH,不再担心它。

我基本上同意他的观点。除了更多的工作外,真的没有太多可获得的好处。


我必须承认,这就是我想听到的答案 :-) - LeftyX

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

最后一种方法接受一个ICreateCriteria实现。下面是该接口及其一个实现的代码:
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;
    }
}

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

0

我找到了一些使用Repository/DAO/Whatever的理由。

  1. 单元测试。我从来没有尝试过模拟/存根ISession,但我认为它应该比模拟或存根Repository/DAO接口要复杂得多。
  2. 代码重用。如果您直接将查询编写到服务/控制器中,当您需要重用特定查询时,您将最终复制它。如果您将其封装到存储库中,只需调用其方法即可。
  3. 单一职责原则。将查询分散在控制器周围会违反这个原则。
  4. NHibernate依赖项。好吧,这很难发生,但是如果您需要更改ORM,则存储库会使其更容易(看,更容易,而不是容易 :))。甚至当您需要将用户数据源从数据库更改为Microsoft Active Directory时,它也会更容易。

就这些了,我想不起来还有其他什么了。


谢谢Oenning。我不想在我的控制器中编写查询,而是在服务层中编写。我认为这是一个很好的放置业务逻辑的地方。它不会出现在UI中,如果我想要将我的服务层插入到其他地方,它也可以重复使用。Nhibernate依赖性。嗯,是的,我同意,但我不认为这会很快发生,也不认为它与更改存储库有什么不同。无论如何,还是谢谢。 - LeftyX
  1. 如果您使用“已知固定装置”测试反模式,则会模拟存储库。
  2. 没有任何东西说您不能在服务层中创建抽象。这是完全错误的。
  3. 一点也不。您将在某个地方调用db。无论是在服务或存储库方法调用中还是作为控制器的一部分,都没有关系。仍然是相同的代码。控制器仍负责查询db。
- John Farrell
  1. "已知 Fixture" 测试反模式是什么?从未听说过。我总是模拟我的 Repositories。
  2. 如果我理解你的话,你最终会得到与 Repository 相同的设计,但你会给它起一个不同的名字。有没有这方面的例子?我想看一些代码。
  3. 控制器不负责查询数据库,他需要向其他人询问。他接收请求,并根据它将任务委派给其他类并选择下一个视图。
- goenning
  1. 在xunit测试页面上找不到文档了,这里没有足够的空间来解释它。
  2. 我对你的困惑感到困惑。无论使用什么模式,您都可以始终删除重复功能。
  3. 是的,在这种情况下,控制器正在要求NHibernate查询数据库。99%的存储库变得毫无意义。
- John Farrell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接