Domain driven design DDD:具有两个聚合根的简单域建模

Domain driven design DDD:具有两个聚合根的简单域建模,domain-driven-design,root,aggregate,Domain Driven Design,Root,Aggregate,比如说,我想创建一个action网站,会员可以在这里投标。为了给这个领域建模,我有三个类:成员、项目和出价。 我的头脑风暴是这样的: 项目可以包含多个出价 投标与一个项目和一个成员关联 成员可以包含多个出价 成员和项目可以在没有bid实例的情况下存在 没有成员和项目,投标实例不能存在 考虑到这一点,很明显,由于成员和项目对象是独立的,所以我们可以考虑它们是聚合根。投标将是其中一个合计的一部分。这很清楚,但现在让我困惑的是,我应该选择哪个聚合根?项目还是成员 这是Apress的《Pro ASP

比如说,我想创建一个action网站,会员可以在这里投标。为了给这个领域建模,我有三个类:成员、项目和出价。 我的头脑风暴是这样的:

  • 项目可以包含多个出价
  • 投标与一个项目和一个成员关联
  • 成员可以包含多个出价
  • 成员和项目可以在没有bid实例的情况下存在
  • 没有成员和项目,投标实例不能存在
考虑到这一点,很明显,由于成员和项目对象是独立的,所以我们可以考虑它们是聚合根。投标将是其中一个合计的一部分。这很清楚,但现在让我困惑的是,我应该选择哪个聚合根?项目还是成员

这是Apress的《Pro ASP.NET MVC 3框架》一书中的示例,他们的做法如下:

其中给出了以下代码:

public class Member 
{
    public string LoginName { get; set; } // The unique key
    public int ReputationPoints { get; set; }
}

public class Item 
{
    public int ItemID { get; private set; } // The unique key
    public string Title { get; set; }
    public string Description { get; set; }
    public DateTime AuctionEndDate { get; set; }
    public IList<Bid> Bids { get; set; }
}

public class Bid 
{
    public Member Member { get; set; }
    public DateTime DatePlaced { get; set; }
    public decimal BidAmount { get; set; }
}
公共类成员
{
公共字符串LoginName{get;set;}//唯一键
公共int信誉点{get;set;}
}
公共类项目
{
public int ItemID{get;private set;}//唯一密钥
公共字符串标题{get;set;}
公共字符串说明{get;set;}
public DateTime AuctionEndDate{get;set;}
公共IList出价{get;set;}
}
公开课投标
{
公共成员成员{get;set;}
public DateTime DatePlaced{get;set;}
公共小数位数{get;set;}
}
成员和项目在此是聚合根,投标包含在项目中。 现在让我们假设我有一个应用程序用例:“获取特定成员发布的所有出价”。这是否意味着我必须首先获取所有项目(例如,通过存储库接口从数据库中获取),然后枚举试图找到匹配成员的每个项目的所有出价?这不是有点低效吗?所以更好的方法是在成员内部聚合出价对象。但在这种情况下,考虑新的用例:“获得特定项目的所有出价”。现在我们又需要换一种方式来获得所有的出价


因此,考虑到我需要在我的应用程序中实现这两个用例,那么对这个域进行建模的正确和有效的方法是什么?

您的域实际上应该只反映命令()需求(更新/更改数据)。我假设您需要查询(读取数据,不更新/更改数据):“获取特定项目的所有出价”和“获取特定成员发布的所有出价”。因此,这种“查询”与域无关,因为查询实现独立于命令实现(命令调用域方法)。这使您可以自由地以高效的方式实现每个查询。我的方法是实现一个高效的DB视图,只获取要在UI中显示的数据。然后创建一个名为BidForItemDto(DTO=)的新类,并将数据从DB视图映射到BidForItemDto的集合中(您可以通过ADO.NET手动执行此操作,也可以使用NHibernate(首选,为您执行所有操作))。与第二个查询相同,创建一个名为BidPostedByMemberDto的新类

所以,如果是您需要的查询,只需忘记域,认识到它只是您想要在UI中显示的数据,并从DB高效地查询它们。仅当您在UI中执行某些操作(例如,单击一个按钮进行出价)时,它才会执行“出价”命令,该命令将在末尾调用域方法项.PlaceBid(成员成员、日期时间、小数金额)。顺便说一句,IMHO是一个“有很多出价”的项目,域方法“放置出价”肯定需要访问以前的出价才能正确实现整个逻辑。把收集到成员的出价没有太多的意义,我

在我的脑海中,有一些DB视图和sql查询的示例:

获取特定项目的所有投标:

create view BidForItemDto
as
select 
    i.ItemId,
    b.BidId,
    b.MemberId,
    b.DatePlaced,
    b.BidAmount     
from Item i
join Bid b ON b.ItemId = i.ItemId
查询:

SELECT *
from BidFormItemDto
where ItemId = <provide item id>
SELECT *
from BidPostedByMemberDto
where MemberId = <provide member id>
查询:

SELECT *
from BidFormItemDto
where ItemId = <provide item id>
SELECT *
from BidPostedByMemberDto
where MemberId = <provide member id>
选择*
从BidPostedByMemberDto
其中MemberId=

谢谢您的回答。您的引语:“您的域应该真正只反映命令(CQRS)需求(更新/更改数据)。”真的很有趣,我在哪里可以阅读更多关于这个“反映命令”视角的DDD建模方法的内容?我首先使用EF代码,因此项目中没有DTO,我在所有层中使用域对象。这个事实是否改变了你对我问题的评价?此外,在C#代码中,“获得特定成员发布的所有投标”查询如何查看?请查看我的博客-有一个基于CoreDdd库的演示应用程序Eshop,在教程中,您可以找到有关DDD建模、CQR的更多信息,以及类似的“获得特定成员发布的所有投标”查询示例。即使到目前为止,您的项目中还没有DTO和独立的(基于命令的)查询基础设施,您仍然可以以类似于Eshop演示中所示的方式添加它。