首页 > 解决方案 > DDD、数据库和数据列表

问题描述

我刚开始我的第一个“真正的”软件项目,我想从正确的开始。DDD 的概念似乎是一种非常干净的方法,可以将各个软件部分分开,但是在现实中我很难实现这一点。

我的软件是测量跟踪器,本质上存储测量数据列表,由时间戳和数据值组成。

我的领域模型

class MeasurementDM{
   string Name{get;set;}
   List<MeasurementPointDM> MeasurementPoints{get;set;}
}

class MeasurementPointDM{
   DateTime Time{get;set;}
   double Value{get;set;}
}

我的持久性模型:

class MeasurementPM{
   string Id{get;set;} //Primary key
   string Name{get;set;} //Data from DomainModel to store
}

class MeasurementPointPM{
   string Id{get;set;} //Primary Key
   string MeasurementId{get;set;} //Key of Parent measurement
}

我现在有以下问题:

1)因为我想保持我的领域模型纯粹,我不想或不需要这些类中的数据库键。从数据库构建我的域模型时这没问题,但我不明白如何存储它们,因为域模型不再知道数据库 ID。无论如何我应该将它包含在域模型中吗?当我从数据库中检索域对象时,是否应该创建一个将域对象映射到数据库 ID 的字典?

2)测量点本质上与测量本身具有相同的Id问题。此外,我不确定存储测量点本身的正确方法是什么。上面,每个 MeasurementPointPM 都知道它属于哪个 MeasurementPM。当我查询时,我只是根据他们的测量键选择测量点。这是存储此类数据的有效方法吗?随着越来越多的测量值被添加,这似乎会爆炸。将我的 MeasurementPoints 列表序列化为字符串并将整个列表存储为 nvarchar 会更好吗?这将使添加和删除数据点更加困难,因为 Id 总是需要反序列化、重新序列化整个列表

我很难找到一个处理这些问题的 DDD 的好例子,希望有人可以帮助我。

标签: databaselistdomain-driven-design

解决方案


我的软件是测量跟踪器,本质上存储测量数据列表,由时间戳和数据值组成。

您可能需要仔细考虑您是在描述服务还是数据库。如果您的主要用例是存储来自其他地方的信息,那么将域模型引入混合可能不会让您的生活变得更好。

当新信息与旧信息交互时,域模型测试变得有趣。因此,如果您所拥有的只是数据结构,那么很难找到一个好的模型(因为缺少关键元素——模型实体如何随时间变化)。

那就是说……

我不明白如何存储它们,因为域模型不再知道数据库 ID。

这不是你的错。文学很烂。

最常见的答案是 _people 允许他们的模型受到 O/RM 问题的污染。例如,如果您查看 Citerus 示例应用程序中的Cargo实体,您会发现这些行隐藏在底部:

Cargo() {
    // Needed by Hibernate
}

// Auto-generated surrogate key
private Long id;

这是一个间接结果,即“存储库”模式提供了一种对象的内存集合的错觉,这些对象保持自己的状态,而幕后的现实是您正在内存和持久存储之间复制值。

也就是说,如果您想要一个干净的域模型,那么您将需要一个单独的内存表示来存储您的数据,以及在两者之间来回转换的函数。

换句话说,您遇到的是对单一职责原则的违反——如果您使用相同的类型来建模您用来管理持久性的域,那么结果将是这两个问题的混合.

所以基本上你会说域模型的一些最小污染,例如 ID,是标准做法。

较弱;我会说这是一种常见的做法。从根本上说,很多人,特别是在项目的早期阶段,不重视在他们的领域模型和他们的持久性管道之间建立边界。

让每个域模型都从基类继承或实现强制创建唯一 ID 的接口是否有意义?

它可能。网络上有很多示例,其中域实体扩展了一些通用EntityAggregate模式。

真正有趣的问题是

  • 这样做的直接成本和收益是什么?
  • 这样做的递延成本和收益是什么?

特别是,这会让事情变得更容易还是更难改变?


推荐阅读