C# 如果没有域驱动设计,存储库是否有用?

C# 如果没有域驱动设计,存储库是否有用?,c#,asp.net,nhibernate,entity-framework,domain-driven-design,C#,Asp.net,Nhibernate,Entity Framework,Domain Driven Design,假设我的应用程序不能保证完整的DDD设置,那么存储库还会有用吗?我喜欢它们屏蔽底层实现细节(如实体框架的使用)的方式。然而,根据定义,存储库往往与聚合根绑定(这个概念对我来说仍然是一个圣杯) 我想问题也可以这样说:如果我有一个典型的三层应用程序,其业务层外观由基于功能的“逻辑分组”类(而不是像DDD中那样的聚合根)组成,例如TradingManager和ContactsManager,那么创建“逻辑分组”存储库是否有意义。或者可能是一个数据访问对象,我认为它就像一个没有聚合根需求的存储库。当然,

假设我的应用程序不能保证完整的DDD设置,那么存储库还会有用吗?我喜欢它们屏蔽底层实现细节(如实体框架的使用)的方式。然而,根据定义,存储库往往与聚合根绑定(这个概念对我来说仍然是一个圣杯)

我想问题也可以这样说:如果我有一个典型的三层应用程序,其业务层外观由基于功能的“逻辑分组”类(而不是像DDD中那样的聚合根)组成,例如TradingManager和ContactsManager,那么创建“逻辑分组”存储库是否有意义。或者可能是一个数据访问对象,我认为它就像一个没有聚合根需求的存储库。当然,我仍然会有一个模型(EF POCOs),它将在层之间上下传递

另外,我刚才描述的方法是否会被视为事务脚本方法?这肯定不是DDD,也不是活动记录。我甚至不确定EF4是否像Nhibernate一样存在活动记录


我试图了解其他人在不遵循DDD的情况下是如何构造n层应用程序的。

正如您所暗示的,听起来您更倾向于DAO。我认为DAO在非DDD项目中非常有用,在这些项目中,您希望将数据层技术完全抽象出来

就事务脚本而言,它与您的数据层设计是正交的。事务脚本意味着每个业务操作都被分组到一个过程调用中。示例:事务脚本模式通常用于服务器端的WCF服务调用,每个服务方法都遵循事务脚本模式。可以这样想:对于事务脚本,实际的业务逻辑不在对象中,而是直接写在事务脚本过程调用中。公共业务逻辑可以在事务脚本之间共享,但通常是通过静态方法、助手等来完成的。。。而不是通过“纯”OO

这里有一些伪代码

// traditional transaction script
public class MailService
{
    public void UpdateEmail(string userName, string newEmail)()
    {
       if(db.UserExists(userName))
       {
          if(EmailHelper.ValidateEmailFormat(newEmail))
          {
             db.UpdateEmail(userName, newEmail);
          }
       } 
    }
}

// transaction script with anemic domain objects
public class MailService
{
    public void UpdateEmail(string userName, string newEmail)()
    {
       var userDAO = new UserDAO();
       var emailDAO = new EmailDAO();

       var existingUser = userDAO.GetUserByName(userName);       

       if(existingUser != null)
       {
          if(EmailHelper.ValidateEmailFormat(newEmail))
          {
             emailDAO.UpdateEmail(existingUser, newEmail);
          }
       } 
    }
}  

// More of an OO / DDDish approach
public class MailService
{
    public void UpdateEmail(string userName, string newEmail)()
    {
       var userRepository = new Repository<User>();

       var userToUpdate = userRepository.Where(x => x.UserName = userName).FirstOrDefault();

       if(userToUpdate != null)
       {
           userToUpdate.Email = newEmail;

           if (user.IsValid())
           {
               userRepository.Update(userToUpdate);
           } 
       }
    }
}
//传统事务脚本
公共类邮件服务
{
public void UpdateEmail(字符串userName,字符串newEmail)()
{
如果(db.UserExists(userName))
{
if(EmailHelper.ValidateEmailFormat(newEmail))
{
db.UpdateEmail(用户名,newEmail);
}
} 
}
}
//具有贫血域对象的事务脚本
公共类邮件服务
{
public void UpdateEmail(字符串userName,字符串newEmail)()
{
var userDAO=new userDAO();
var emailDAO=new emailDAO();
var existingUser=userDAO.GetUserByName(用户名);
if(existingUser!=null)
{
if(EmailHelper.ValidateEmailFormat(newEmail))
{
emailDAO.UpdateEmail(现有用户,newEmail);
}
} 
}
}  
//更多的是OO/DDDish方法
公共类邮件服务
{
public void UpdateEmail(字符串userName,字符串newEmail)()
{
var userRepository=newrepository();
var userToUpdate=userRepository.Where(x=>x.UserName=UserName).FirstOrDefault();
if(userToUpdate!=null)
{
userToUpdate.Email=newEmail;
if(user.IsValid())
{
userRepository.Update(userToUpdate);
} 
}
}
}
显然,第一个例子根本不是OO。第二个示例比OO更基于对象,因为所有业务逻辑都发生在MailService调用中。第三个例子是传统的OO。服务调用中只出现控制流;所有业务逻辑都在User.IsValid()方法中处理

这一切都归结为您将业务逻辑放在何处。

一如既往。。。“视情况而定”。:对不起


我认为这可以归结为单一责任原则。如果您的DAO所做的只是检索实体(好吧,是CRUD,而不是la和DbContext),那么其他什么都不做。。。然后是的,用一个滚。如果你开始发现你有不同实体的自定义逻辑,那么你会考虑一些类似于存储库的东西。我知道我描述的这个设计不是DDD,也不是活动记录。那是什么呢?假设我的中间层/层方法(无论是WCF服务还是BLL调用)类似于ContactsManager.AddEmail(电子邮件),其中Contacts不是真实的实体,而是对电子邮件、地址、,例如电话实体。更新后提供了一个事务脚本示例在第二个示例中,如果DAO操作POCO实体,我想它不会改变这样一个事实,即它仍然是一个具有贫乏域对象的事务脚本?或者已经被代码暗示,例如,existingUser可能是User类型,newEmail可能是Email类型。逻辑本身不在实体中这一事实使其变得贫乏,使用POCO并没有改变这一点?更新-这一切归结为您如何组织业务逻辑IMHO,而不是您是否拥有POCO。但存储库根据定义将我锁定在DDD路径上?我想我说的是为DAO创建逻辑分组,而不是用1-1和实体。所以电话、电子邮件和地址实体都将通过ContactsDAO进行传输。对不起,我是用速记的。我说的“类似于存储库”,并不是要将其视为字面上的DDD repo,而是更类似于普通DAO。我也不想被“束缚”在某个特定的代码结构上;据我所知,没有DDD警察会因为错误的图案应用而对您处以罚款。;)你是对的!尽管感觉确实如此,因为每次我尝试DDD,我都感觉自己在很多方面都失败了。所以如果我的项目确实远离DDD,