我了解DDD中的概念,但在实践中会有些混乱。
我正在使用C#,SQL Server和EF。我看到基于我的数据库模式,持久性模型看起来与聚合不同。为了定义整洁,美观的聚合,实体和值对象,我的域模型看起来与数据库模型有所不同。
此外,如果我尝试合并这2个对象,那么我将以某种方式尝试根据技术而非领域来设计领域模型。
也许是一个更具体的例子,例如:
如果该ID仅用于DB,我是否需要在实体中添加ID字段?
如果出现Many2Many关系,也会变得很棘手
这两个模型是否不同,并且存储库的实现必须将db模型转换为域模型,还是应该使域模型与EF使用的模型相同?
答案 0 :(得分:1)
从DDD开始时,这是一个常见问题。
它们完全是 个独立的东西。
域模型是一个抽象。它不应该关心您使用的技术,也不代表数据库表,文档,类,函数等。
域模型表示概念,依赖性和这些概念之间的相互作用。
技术用于域模型的实施。
可以使用不同的技术来实现相同的域模型。
尽我们所希望的自由为您的域模型做我们想做的事,但实际上,我们确实使用一种技术来实现它,有时会影响到它。
当然,您可以转储所有freameworks和库,并制定自己的解决方案,从而使您的实现更加容易。即使执行此操作,仍然会留下您的语言,C#,Java,Rubi等以及它提供的工具。
这是一个例子:
假设我们开发了一个罐头租赁系统。一个人可以租车。在我们的域中,我们具有 Person 具有的 Account 的概念,即Car
和CarRental
。
这就是您的域模型。在这一点上,我们不关心语言,数据库或任何东西
现在是域模型的实现。
我们将使用C#。现在我们需要决定一个数据库。如果我们决定使用SQL,则可以决定使用RDBMS的出色功能进行联接,因此我们可以通过以下方式使用整数ID来实现它:
public class Account {
public int ID { get; private set; }
// other stuff
}
public class Car {
public int ID { get; private set; }
// other stuff
}
public class CarRental {
public int AccountID { get; private set; }
public int CarID { get; private set; }
// other stuff
}
另一方面,我们可能会认为整数ID不好,因为如果必须使用其他系统并移动数据库和其他内容,则可能会发生冲突,因此我们决定考虑一下,然后将电子邮件用作帐户和驾照位置的唯一标识符,作为汽车的唯一标识符:
public class Account {
public Email Email { get; private set; }
// other stuff
}
public class Car {
public LicencePlace LicencePlace { get; private set; }
// other stuff
}
public class CarRental {
public Email AccountEmail { get; private set; }
public LicencePlace CarLicencePlace { get; private set; }
// other stuff
}
如果我们遵循DDD并将您的实体正确地划分为 Aggregates ,则您无需在它们之间进行联接,因为它们不应加载或在同一转换中进行更改
另一方面,我们可能不希望在同一数据库上建立其他模型(如果使用CQRS,则可能是读取模型,或者我们可能需要提取报告),而使用第二种方法可能会使这一工作更加困难因为我们失去了加入联接的能力。
另一方面,例如,如果我们使用像MongoDB这样的NoSQL数据库,则无法进行联接。因此,使用整数ID不会给我们带来任何价值。
即使我们决定使用SQL数据库并且不使用整数ID,我们仍然可以使用 Domain Events 并使用它们构建其他模型并进行报告。
如果我们有一个分布式系统,那么使用联接也不起作用,因此使用整数ID可能根本不会给我们带来任何价值。
有时候使用您的技术能力使某些事情变得容易是很方便的,但是我们让它损害我们的 Sytems 和 Domain模型。
从技术的角度来看,我们最终构建的系统非常健壮,但是他们没有按照他们的预期去做,这使他们毫无用处。
无用系统是无用,无论其实施效果如何。
如果您还没有阅读DDD书,请阅读。埃里克·埃文斯(Eric Evans)谈论您的技术如何为您提供帮助或全力以赴。埃里克·埃文斯(Eric Evans)还谈到了DDD如何实现实施的自由,这样您就不必与技术作斗争。
如果一直都在考虑持久性,那么我们倾向于做另一件事。的确,我们大部分时间都在坚持事情,但这并不意味着 Domain Model 是持久保存在数据库中的东西。
当我开始编程时,我开始使用计算机图形和建模应用程序,例如3DsMax和Maya。当我开始编写使用冬青数据库的应用程序时,我真的很奇怪,人们如何不思考和不了解自己的领域,只是坚持不懈地使他们工作并进行交流关于技术。
如果您不熟悉 数学 ,那么如果您喜欢计算机图形学,就无法编写类似的代码。因此,您将从学习 数学 开始。知道其中一些内容之后,就可以编写代码了。
以游戏为例。您可以设计一个 Physical Engine (物理引擎),以对 Domain ofphysics 进行建模。在此模型中,您将具有诸如工作,电源,重力,加速等概念。无需持久他们。例如,您确实会保留其他征兆,例如 Player 的 Weight ,以便 Physics Engine 知道重力应该如何影响它,但您仍然不知道不能对数据库保持 Power 。它仍然是域模型。 功能,有效等是函数,而不是集合的实体。它们仍然是您的域模型的一部分。
假设您不想构建物理引擎,而 如果您不想构建物理引擎,则必须了解物理 。物理很复杂。即使您是精通EF或SQL的编程者,也不会帮助您构建物理引擎。了解物理域并能够对其进行 域模型 ,然后 实施 是关键。
如果您想真正感受到实现与域模型之间的区别,请选中this out,在开始任何实现之前,此域可能会让您大吃一惊。
还请检查this article是否具有DDD实体。
编辑
Here is another 文章介绍了NHibernaty和用于域建模的EntityFramework之间的区别。