Asp.net mvc ASP.NET MVC、Nhibernate和中小型项目存储库

Asp.net mvc ASP.NET MVC、Nhibernate和中小型项目存储库,asp.net-mvc,nhibernate,repository-pattern,Asp.net Mvc,Nhibernate,Repository Pattern,目前我正在从事一个小型ASP.NET MVC项目。 我正在尝试实现Nhibernate以在MS Sql Server数据库上持久化。 在花了很长时间研究DDD和互联网上的其他项目之后,我决定采用存储库模式。 现在我正面临一个两难选择。 使用Nhinbernate时,我真的需要存储库吗? 有一个服务层(我目前没有服务层)与Nhinbernate交互,避免多次编写类似的内容,不是更好吗 public Domain.Reminder GetById(Guid Code) { return (_

目前我正在从事一个小型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);
}
公共域。提醒GetById(Guid代码)
{
返回(_session.Get(Code));
}
公共域。提醒LoadById(Guid代码)
{
返回(_session.Load(代码));
}
公共bool保存(域.提醒)
{
_会话。保存或更新(提醒);
返回(真);
}
公共bool删除(Domain.rements)
{
_删除(提醒);
返回(真);
}
我发现了一篇老Ayende的帖子,这篇帖子是针对存储库的。
我知道围绕这些话题存在着巨大的争论,答案总是。。。视情况而定,但在我看来,抽象层次太多,事情变得更复杂,更难理解。

我错了吗?

Ayende反对像您这样编写存储库,因为您提出这个问题的原因,它是重复的代码,NH可以以任何方式处理所有这些代码。他提倡直接调用NH,就像调用存储库一样,不要再担心它了


我非常同意他的看法。除了更多的工作之外,真的没有什么收获。

我找到了一些你应该使用Repository/DAO/任何东西的理由

  • 单元测试。我从未尝试过模拟/存根ISession,但我想说,它应该比模拟或存根存储库/DAO接口复杂得多
  • 代码的重用。如果将查询直接写入服务/控制器,则在需要重用特定查询时,最终会复制查询。如果将它包装到存储库中,只需调用它的方法即可
  • 。在控制器周围散布查询会使您违反这一原则
  • NHibernate依赖关系。好的,这很难实现,但是如果您需要更改您的ORM,存储库会使它变得更容易(看,它更容易,不容易:)。甚至当您需要将用户数据源从数据库更改为Microsoft Active Directory时,也会更容易

  • 仅此而已,我不记得其他任何东西。

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

    我使用一个带有Get、Load、Save方法和各种匹配方法的存储库(一个用于Linq,一个用于我的域查询)

    公共类NHibernateRepository:IRepository
    {
    专用只读会话;
    公共NHibernateRepository(会议期间)
    {
    _会话=会话;
    }
    公共T加载(Guid id)
    {
    返回会话加载(id);
    }
    公共无法获取(Guid id)
    {
    return _session.Get(id);
    }
    公共作废保存(T obj)
    {
    _会话。保存或更新(obj);
    }
    公共作废删除(T obj)
    {
    _删除(obj);
    }
    //全力以赴
    public IEnumerable Matching(),其中T:DomainObject
    {
    返回_session.CreateCriteria().List();
    }
    //NHibernate 3.0 Linq
    公共IQueryable匹配(表达式谓词)
    {
    返回_session.Query().Where(谓词);
    }
    公共IEnumerable匹配(ICreateCriteria查询,参数IAppendCriteria[]extraCriterias)
    {
    var-criteria=query.GetCriteria();
    foreach(标准外的var标准)
    {
    标准。附加(标准);
    }
    返回条件.GetExecutableCriteria(_session).List();
    }
    }
    
    最后一个方法接受ICreatera实现。下面是接口和它的一个实现

    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;
        }
    }
    
    公共接口ICreateCriteria:ICreateCriteria
    {
    DetachedCriteria GetCriteria();
    }
    公共类挑战者可用ToRound:ICreateCriteria
    {
    专用只读Guid\u roundId;
    公共挑战者可用环形(圆形)
    {
    _roundId=round.Id;
    }
    public DetachedCriteria GetCriteria()
    {
    var criteria=DetachedCriteria.For()。
    CreateAlias(“事件”、“e”)。
    CreateAlias(“e.Rounds”、“Rounds”)。
    添加(Restrictions.Eq(“rounds.Id”,_roundId));
    退货标准;
    }
    }
    

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

    只是一张小纸条。没有中小型项目,它现在可以很小,但是明天你的经理会问你另一个特性,然后是另一个,最后你会有一个带有中小型架构的大型项目。我真的不喜欢大的设计,但有时你需要提前考虑一下。我完全同意你的观点,但是,如果不是因为我将来可能不使用nihbernate,我看不到使用repository的好处。它产生了很多额外的工作,我现在无法证明这一点。谢谢欧宁。我不想在控制器中编写查询,而是在服务层中编写查询。我认为这也是一个放置一些业务逻辑的好地方。它不会出现在UI中,如果我想在其他地方插入我的服务层,它将是可重用的。Nhibernate依赖性。嗯,是的,我可以同意,但我认为这不会很快发生,我也不认为这与更改存储库有什么不同。无论如何谢谢你。如果您模拟回购协议,您将使用“已知夹具”测试反模式。2.没有任何东西表明您不能在服务层中创建抽象。这是完全错误的。3.一点也不。你会给db打电话的。它是否在服务或repo方法调用或控制器的一部分中并不重要。还是一样的代码。控件
    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;
        }
    }