DDD值对象:如何在没有大量SQL连接的情况下持久保存实体对象?

时间:2010-02-14 20:12:26

标签: c# sql-server ssis domain-driven-design object-persistence

显然我错误地说DDD与EAV / CR的用途相似,但到目前为止我看到的唯一区别是物理表为每个具有大量连接而非三个表和大量连接的实体构建。

这必定是因为我缺乏对DDD的理解。 如何在导入数据时将这些对象物理存储到数据库而没有明显的连接和复杂性?我知道您可以简单地创建输入到存储库的对象,但是很难训练像Microsoft Sql Server这样的工具Integration Server使用您的自定义C#对象和框架。也许这应该是我的问题,你如何使用你的DDD ASP.NET C#框架与Microsoft SQL Server集成服务和报表服务? LOL。

在EAV / CR数据库中,我们可以根据人的类型设置一个具有不同类的Person表:供应商,客户,买方,代表,公司,管理员等。三个表,一些连接,属性是在插入之前总是使用验证字符串,就像MVC中的ModelValidation一样,对象接受任何值,但在它有效之前不会持久存在。

在标准关系模型中,我们曾经为每种类型的实体创建一个表,混合使用像City这样的冗余数据类型。

使用Domain Driven Design,我们使用对象来表示每种类型的实体,每种类型的ValueObject的嵌套对象,以及更多嵌套对象。在我的理解中,这导致每种实体的表和每种信息集(值对象)的表。有了所有这些表,我看到很多连接。我们最终还为每种新的联系人类型创建了一个物理表。显然有一种更好的方法,所以我必须在将对象持久保存到数据库时不正确。

我的供应商看起来像这样:

public class Vendor {
    public int vendorID {get; set;}
    public Address vAddress {get; set;}
    public Representative vRep {get;set;}
    public Buyer vBuyer {get; set;}
}

我的买家:

public class Buyer {
   public int buyerID {get; set;}
   public Address bAddress {get; set;}
   public Email bEmail {get; set;}
   public Phone bPhone {get; set;}
   public Phone bFax (get; set;}
}

我们真的参考像Vendor.vBuyer.bPhone.pAreaCode这样的东西吗?我认为我们会引用并存储Vendor.BuyerPhoneNumber,并将这些对象构建为这些部分的别名:Vendor.Address1,Vendor.Address2,Vendor.BuyerPhoneNumber ......等。

4 个答案:

答案 0 :(得分:1)

您可以将对象序列化为xml并将其保存到Sql Server中的xml列。毕竟,您正试图表示一个分层数据结构,而这正是xml擅长的地方。

答案 1 :(得分:1)

领域驱动的设计支持者经常建议尽可能保持数据模型尽可能接近对象模型,但这不是一个铁定的规则。

如果在对象关系映射层中创建映射以将数据转换(投影)到对象中,则仍然可以使用a EAV/CR database design

决定如何设计对象并提供对子值的访问权限实际上是一个单独的问题,您必须根据具体情况进行解决。 Vendor.BuyerPhoneNumberVendor.vBuyer.bPhone.pAreaCode?答案总是取决于,因为它根植于您的具体要求。

答案 2 :(得分:1)

真正的答案是使您的SQL规范化策略与您的对象相匹配。如果您有许多重复的地址,并且需要将它们关联在一起,那么将数据规范化为单独的表,从而创建对值对象的需求。

答案 3 :(得分:0)

存储域对象的最佳方法之一实际上是文档数据库。之所以能很好地工作,是因为文档的事务边界与“聚合根”的一致性边界完全匹配。您不必担心JOIN或急切/懒惰的加载问题。但是,如果您应用CQRS(我在下面对此进行了介绍),则并非绝对必要。

缺点通常是查询。如果您希望直接查询域对象后面的持久数据,则可以打个结。但这是CQRS旨在为您解决的复杂性,在这种情况下,您要执行查询的应用程序部分与加载/验证/存储域对象的部分不同。

您可能有一个复杂的“命令”实现,该实现在加载域对象之前(包括域对象必须具有行为并封装其数据,否则有可能变得“厌食”)(加载域对象,调用域对象的行为)(记住,域对象必须具有行为并封装其数据)发布有关发生的事件的事件。

然后,您可以使用这些事件来更新其他“读取存储”,尽管您不必这样做。关键是您在应用程序中实现了完全不同的垂直切面,而不必理会复杂的对象模型/ ORM业务,而直接进入数据,准确加载所需的数据并将其返回以显示给用户。

CQRS很困难,而且很复杂。 所有都会指示您为以下内容提供单独的代码:

  1. 处理命令(会改变状态,因此需要业务规则/不变式)。
  2. 执行查询(不会改变状态,因此不需要涉及所有复杂的业务规则/不变式,因此可以“只是”高效地获取数据。