我是DDD + TDD World的新手。但是我已经编程了将近9年。
有人可以向我解释持久性无知的好处吗?典型的nHibernate应用程序只是将类和数据库之间的依赖关系推送到映射文件。
如果我更改了Class文件或数据库,我必须更改映射文件。那么是不是只是通过添加一个抽象层来推动依赖?在我看来,到目前为止,我认为这不是革命性的。但我不确定我是否遗漏了什么。
最后,我如何测试映射文件?映射文件中可能会出现错误,我该如何测试它们?
答案 0 :(得分:47)
让我用一个例子解释一下。让我们假设您正在使用传统的SQL方法实现应用程序。您打开记录集,更改数据并提交它。
伪代码:
trx = connection.CreateTransaction();
query = connection.CreateQuery("Select * from Employee where id = empid");
resultset = query.Run();
resultset.SetValue("Address_Street", "Bahnhofstrasse");
resultset.SetValue("Address_City", "Zürich");
trx.Commit();
使用NHibernate,它看起来像这样:
emp = session.Get<Employee>(empid);
// persistence ignorant 'logic'
emp.Address.Street = "Bahnhofstrasse";
emp.Address.City = "Zürich";
session.Commit();
持久性无知意味着业务逻辑本身不知道持久性。或者换句话说,持久性与逻辑分离。这使它更具可重用性。
将'logic'移动到可重用的方法:
void MoveToZuerichBahnhofstrasse(Employee emp)
{
// doesn't have anything to do with persistence
emp.Address.Street = "Bahnhofstrasse";
emp.Address.City = "Zürich";
}
尝试使用结果集编写这样的方法,你知道持久性无知是什么。
如果您不相信,请看单元测试有多简单,因为与持久性相关的东西没有任何依赖性:
Employee emp = new Employee();
MovingService.MoveToZuerichBahnhofstreasse(emp);
Assert.AreEqual("Bahnhofstrasse", emp.Address.Street);
Assert.AreEqual("Zürich", emp.Address.City);
DDD是不同的东西。在那里,您首先构建域模型(类模型)并根据它创建数据库设计。使用NH非常简单,因为 - 由于持久性无知 - 您可以在拥有(确定的)数据库模型之前编写和单元测试模型和逻辑。
测试:我们通过创建实体实例,将其存储到数据库,获取并进行比较来测试映射。这是通过大量反射自动完成的。但你不需要走这么远。尝试存储实体时会出现大多数典型错误。
你可以对查询做同样的事情。复杂的查询值得测试。如果查询完全被编译,那将是最有趣的。你甚至不需要任何数据。
对于数据库集成测试,我们使用的是Sqlite。这很快。 NH使用SchemaExport动态生成内存数据库(在每次测试之前)。
答案 1 :(得分:7)
我一直在思考这个领域,虽然我过去曾使用存储过程ADO.NET,但只有当我最终转向NHibernate时,我对我的持久性机制感到满意。
域驱动设计(DDD)将重点放在域模型上。这意味着主要关注的是创建一个概念模型,为用户和程序员形成一种通用语言。用户几乎从未对如何保持信息感兴趣。 NHibernate通过使持久性成为捕获业务规则和了解用户真正想要从系统中获得什么的关注点来帮助您实现这种思维方式。
Fluent NHibernate可减少域模型更改对底层映射文件的影响。它还有auto mapping。虽然您永远无法完全忽略系统的持久性,但NHibernate与Fluent NHibernate允许您专注于域模型。如果你不专注于使用丰富的Domain模型,那么NHibernate几乎没有什么好处。
关于测试映射,无论用什么方法实现持久性,都要编写测试(或者你应该是)。这不是因为您使用NHibernate而出现的额外工作。试着测试你的映射是否测试你的持久性是否正常工作。
再次为此Fluent NHibernate是非常宝贵的。在大多数情况下,它有一个Persistence Specification Testing非常简单。
答案 2 :(得分:2)
PI不是关于使用NHibernate。 PI代表忽略数据将如何存储以开发域模型。是的,它通过添加一个更多的抽象层来推动依赖。 DDD不是革命性的 - 它更像是一个想法,一种如何使用已经熟悉的模式(大多数都是)进行编码的方法。即 - 工厂模式或模块模式也不是新的,但却是DDD的重要组成部分。
我最近也开始使用NHibernate,所以 - 无法提供有关它的更多细节。但我得到了一个可能对你有用的提示 - 如果你还没有这样做的话,试试Fluent NHibernate。