如何确定添加到存储库的聚合根的ID?

时间:2011-06-08 09:21:20

标签: asp.net-mvc domain-driven-design ddd-repositories

假设我有一个通用存储库接口,如下所示:

public interface IRepository<T>
{
    Add(T item);
    Delete(int itemId);
    Update(T item);
}

通常,通过IRepository.Add()添加的项目的新ID将由某个后端数据库确定,但只有在提交了整个事务/工作单元后才能确定。所以我很确定IRepository.Add()返回添加项的新ID是错误的。存储库真的不应该知道如何创建ID。这是对的吗?

如果是这种情况,如何确定添加到存储库的项目的新ID,或者我应该这样做?我知道像NHibernate这样的ORM能够用具有正确ID的新对象自动替换内存中的对象,但我正在尝试设计我的存储库而不考虑任何特定的ORM实现。

例如,假设我有一个客户可以订购的网站。新客户选择退房并发送到表单以填写其详细信息。此信息用于创建存储在CustomerRepository中的Customer对象。现在他们的订单信息需要创建,但订单需要通过他们的ID引用客户?

Customer newCustomer = new Customer(first, last, address, phone dateOfBirth);
customerRepository.Add(newCustomer);

//How would I determine customerId??
Order newOrder = new Order(customerId, shippingAddress, billingAddress);
newOrder.AddOrderItem("widget");
newOrder.AddOrderItem("doohicky");
newOrder.AddOrderItem("stuff");

6 个答案:

答案 0 :(得分:3)

在您给出的示例中,我将在一个步骤中创建CustomerOrder,并将域对象传递给域对象,而不是传递ID:

Customer newCustomer = new Customer(first, last, address, phone dateOfBirth);

// Pass the customer rather than the CustomerId:
Order newOrder = new Order(newCustomer , shippingAddress, billingAddress);
newOrder.AddOrderItem("widget");
newOrder.AddOrderItem("doohicky");
newOrder.AddOrderItem("stuff");

customerRepository.Add(newCustomer);
orderRepository.Add(newOrder);

// SaveChanges()

...保存更改后,框架会自动填充CustomerOrder的ID,并填写Customer.IdOrder.customerId,等等。 )由于已将Customer对象分配给Order

答案 1 :(得分:2)

我在客户端(la CombGuid.NewGuid())生成id,然后将其传递给构造函数。使用数据库标识has serious disadvantages

时的方法

答案 2 :(得分:1)

埃里克,

在你提到的场景中,我没有看到任何CommitChanges()。我会在transactioncope中包装所有内容,然后在添加订单行之前点击customerRepository.CommitChanges()。然后,您应该能够从新创建的客户对象中获取id,并按如下方式使用它:

Order newOrder = new Order(newCustomer.Id, shippingAddress, billingAddress);

然后,如果订单失败,您可以回滚所有内容并通过不击中scope.Complete()来保持原子。

希望这会有所帮助..

答案 3 :(得分:0)

无论你是否使用NHibernate,我觉得它采用的方法是正确的。任何域对象的目标都是在任何时候只在内存中有一个该对象的实例,即你永远不应该有两个代表相同数据库记录的对象。因此,如果数据库使用新的id更新了记录,则内存中的域对象也应该使用该ID进行更新,因为这是该记录的“一个”真实表示。

调用Add后,对象的ID已设置,然后您可以对该对象进行进一步更改并调用Update,而无需对实施过多了解。

答案 4 :(得分:0)

根据DDD,您的界面比存储库更多DAO:

http://codebetter.com/iancooper/2011/04/12/repository-saveupdate-is-a-smell/

像史蒂夫威尔克斯提到的那样,你应该保持客户在订单中的引用而不是客户ID,所以当处理工作单元时,它将在持久存储中创建正确的链接(SQL DB,Web服务等)

有关DAO的更多信息,请访问http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html

答案 5 :(得分:0)

域实体应该有自己的ID策略,无论数据库ID如何,所以最好在域层生成id,或者如果你真的需要在数据库中生成id,那么在自动生成的数据库旁边的域层添加另一个域标识符标识。

在应用存储库模式的域驱动设计中,您不应将域与数据库绑定,因此依赖数据库创建ID不是一个好主意。

另一点是,您可能希望将客户关联起来,而不仅仅是放置客户ID,这会使域层丰富而稳固。

相关问题