我刚刚学习 DDD(Eric Evans 的书在我面前打开),我遇到了一个我找不到答案的问题。当您只是想获得一个简单的查找记录列表时,您在 DDD 中会做什么?
前任。
员工 ID:123
员工姓名:John Doe
州:阿拉斯加(下拉)
县:瓦西拉(下拉 - 将根据州过滤)。
例如,假设您有一个 Employee 域对象、一个 IEmployeeRepository 接口和一个 EmployeeRepository 类。UI 将使用它来显示员工列表和个人详细信息。在 UI 中,您希望为员工居住的州和县使用下拉菜单。可用县将根据选择的州进行过滤。
不幸的是,数据库表和 UI 看起来非常不同。在 tblEmployees 中,它包含州代码=AK 和县代码=02130,而不是州和县名称。
旧方法(在我开始这个 DDD 任务之前)非常简单,只需创建 2 个查询并使用 DataReader 填充下拉列表。下拉菜单中显示的下方是值,该值会自动用于表单帖子。
但是,对于 DDD,我不确定您应该如何执行此操作。我首先创建了州和县对象以及存储库和存储库接口。但是,编写 4 个类 + 2 个接口和 hbm.xml 文件中的管道 + Employee 业务对象对于 2 个下拉列表的 2 个查询似乎有点过头了。必须有更好的方法,不是吗?我不会很快更改州或县表中的记录,即使我这样做了,也不会通过此应用程序进行。因此,如果没有必要,我真的不想为州和县创建业务对象。
我看到的最简单的解决方案是只使用返回字典的方法创建一个帮助类,例如 GetStatesAll()、GetState() 和 GetCounties() 和 GetCounty(),但从 DDD 的角度来看这感觉不对。
请帮忙。如何在不过度设计几个简单查找的情况下使用 DDD?
最终解决方案 我想我终于通过经验找到了答案,就是将 GetStates() 方法放入它自己的 Data Access 类中,尽管不是存储库类。由于我只进行只读访问,因此我将其放入结构 DTO 中。由于数据库很小,我将它们完全放在一个类中,就像下面描述的 Todd。
我的结论:
- 查找表永远不是值对象,因为查找表总是有一个标识。如果他们没有身份,你就会有重复,这没有多大意义。
- 只读查找表可以有一个存储库,但可能不需要一个。存储库的目标是通过强制仅通过聚合访问来降低复杂性。通过汇总为您提供了一种确保可以强制执行业务规则的方法,例如如果您没有汽车则不添加轮胎。
- 如果您允许对查找表进行 CRUD 维护,那么查找表拥有自己的存储库是有意义的。
- 我最终将代码存储为结构这一事实并没有使它们成为“值类型”。Fowler 在 POEAA 中说结构是一种值类型。没错,结构是不可变的,这就是 Fowler 说它们是“值类型”的原因,但我使用它们的方式不同。我使用结构作为一种轻量级的方式来传递我从未计划在初始创建后更改的 DTO。事实上,我使用的结构确实具有标识,但由于它们是只读的,它们作为结构工作。
- 我一直在使用的一种我在其他地方看不到的模式是使主键字段不可变。它们由构造函数设置,但它们是只读的(不是私有访问器),一旦创建对象就不能更改。