6

拥有一个父对象 Employee 和一个 Address 子对象列表:

class Employee
{
    List<Address> addresses;
}

和一个存储库方法:

void Insert(Employee);

此存储库中的代码应该尝试保存父 Employee 以及子 Address 对象,还是应该单独的存储库处理父对象和子对象?

如果是单独的存储库,那么当在客户端代码中保存 Employee 对象及其子对象时,这应该是该级别的单独调用,结合某种服务还是有其他选择?

4

5 回答 5

7

存储库应该处理整个聚合对象(父对象和所有子对象),因为这就是使其成为存储库的原因。如果您分别保存根对象和子对象,那么您使用的模式并不真正称为存储库(尽管它可能仍然是一个非常好的解决方案)

“存储库”只是用于一次性加载和保存整个聚合的特定数据访问模式的方便名称 - 因此,当您对另一位开发人员说您正在使用存储库模式时,他们知道这就是正在发生的事情。

于 2009-06-18T00:35:22.497 回答
3

实体之间有两种联系。

一个引用:当一个实体包含对另一个实体的引用时。该实体是独立的,它们中的任何一个都可以与该类型的另一个适当实体组合。

例如:客户和产品、用户和地址等。

另一种类型是聚合:当少数实体表示单个对象时,由于某些原因存储在几个表中/拆分为几个类。但它仍然是一个单一的对象:一个部分没有其他部分就没有意义,也不能与其他实体结合。在这种情况下,一个实体总是主要的,删除主要的总是会导致删除聚合实体。

例如:订购和订购物品、房子和它的房间等。

引用代表关系,聚合代表拥有。

所以 保存引用的实体不应该保存引用的实体(除非引用实体的情况是新的,但在这种情况下,最好先保存引用的实体)。

使用聚合保存实体必须保存聚合实体。在单笔交易中。因为这是一个单一的对象。此外,最好不允许单独保存聚合(仅在性能非常关键的情况下) - 否则您会遇到很多并发问题。

于 2012-08-31T19:54:00.220 回答
1

我会尝试使用工作单元模式,您可以在其中打开、进行更改、提交,然后它会找出正确的做法。

如果你在一个关系数据库中,你最终会得到像 Hibernate 这样的东西,每个表都有一个映射器。如果您在非关系数据库中,您可能需要发挥创造力,并将域对象标记为 IAggregateRoot 或其他东西,以了解哪些有自己的存储库,哪些没有。

例如,如果员工存储在一个 SOA 中,而地址存储在另一个 SOA 中,则它们都是 IAggregateRoots,理想情况下,工作单元会自动将每个脏实例交给其相应的存储库进行保存。

因此,它对客户端代码是透明的,但不是无用的间接层(就像服务一样,无论如何在 java 世界中——并非总是如此,但我见过的那些)。

我喜欢 DDD,但我认为它过度炒作了存储库,并且从经验上讲会引起很多混乱,因为人们总是在问如何正确地使用它们。

除非我的系统具有已知的多个基于 SOA 的后端(而不仅仅是“嘿,我们可能有一天会成为亚马逊并且需要它”),否则我个人会回避存储库。当然,基于 Hibernate 的映射器/DAO/某些东西,但它们似乎比存储库更简单、更具体。

于 2009-06-18T02:20:56.153 回答
0

我更喜欢为您处理级联保存的 NHibernate。

于 2009-06-18T18:45:21.300 回答
0

我更喜欢每个表一个存储库,但将它们粘合到一个聚合存储库中:

public RootEmployeeRepository (
  IEmployeeRepository employeeRepository, 
  IAddressRepository addressRepository)
{
  // init
}

public SaveEmployee (Employee employee)
{
  // call IEmployeeRepository to save the employee record minus childen
  // call IAddressRepository to save employee.addresses
  // commit all changes to the DB via UnitOfWork
}
于 2009-06-18T02:40:01.590 回答