【问题标题】:Modelling Aggregate Roots with EF Core 3.X使用 EF Core 3.X 对聚合根建模
【发布时间】:2020-10-05 07:26:44
【问题描述】:

假设我有这些实体:

  • 客户
  • 订购
  • 产品

这三个都是聚合根,因为这三个都需要彼此独立地加载和修改。由于聚合根不能包含其他聚合根,对于 Order 聚合根,我们需要更多的实体:OrderCustomer 和 OrderProduct。这些是 Order 聚合的只读和子级。 这样,由于 Order 聚合需要客户和产品,它会加载 OrderCustomer 和 OrderProduct 实体,它们是只读的。订单从不加载客户或产品。

这一切都说得通,但是,我的问题是,这是如何在 EF Core 中实现的,您无法将多个模型映射到同一个表?您是否将 OrderCustomer 和 OrderProduct 定义为非映射模型并手动将它们加载到您的 Order 存储库中?我没有看到任何其他方法可以做到这一点。

(请不要建议使用存储过程或直接 SQL 或类似的东西)

【问题讨论】:

    标签: domain-driven-design aggregateroot ef-core-3.0


    【解决方案1】:

    OrderProductOrderCustomer 可能不是实体,而是值对象,它们的数据与Order 一起持久化。从现有的 ProductCustomer 表中获取数据是不必要的,在某些情况下,这对您的数据完整性非常不利。

    由于一个聚合不应包含对另一个聚合的引用,因此正如您所看到的那样,该想法是通过 id 引用相关聚合。但是,如果您需要的信息不仅仅是 id,您可以再次按照您似乎正在考虑的思路,创建一个包含 id 以及一些相关位的值对象。我喜欢将特定于聚合的值对象作为嵌套类,以使其所属的位置一目了然,但这是一种设计选择。

    至于“复制*Order中相关聚合的数据以重新构成值对象,请考虑一个代表一对“红袜子”的Product。如果您只存储id然后稍后使用产品 ID 获取描述,与此同时,描述可能已更改为“蓝色袜子”。这将导致您的客户出现一些问题。将产品描述非规范化为 Order(通过 OrderLineOrder.Line) 不会在这方面造成任何混淆,并将差异保留在公司内部而不影响客户,因为已经订购了一双“红袜子”。

    【讨论】:

    • 感谢您的回复。正如我正确理解这一点,OrderProduct 和 OrderCustomer 将是附加表,其中将包含产品或客户的 ID,并具有这些表中的一些附加属性。这些值将是创建订单时产品/客户上的值,因此无需担心数据重复。就数据完整性而言,这可能是双向的。例如,如果有订单的客户打电话说他搬家了,那么已经创建的订单将被运送到他的旧地址。
    • OrderProductOrderCustomer,如果被建模为值对象,在这种情况下不会是附加表,但在其他情况下,您可以使用 一对多 关系可能需要添加一个表。附加客户详细信息将与Order 一起存储,附加产品详细信息将存储在OrderItem 上。由于历史原因,即使对于送货地址,订单也会包含地址。如果客户有一个新的送货地址,那么所有以前的订单现在都引用新地址是不正确的。
    【解决方案2】:

    使用 EF Core 时,如果 OrderCustomer 和 OrderProduct 是属于您的 Order Aggregate 根的实体,您可以像您说的那样在存储库中手动加载它们。这种方法没有错。实际上微软自己的架构指南就是这样做的。这是示例中的代码:

    public async Task<Order> GetAsync(int orderId)
        {
            var order = await _context.Orders.FindAsync(orderId);
            if (order != null)
            {
                await _context.Entry(order)
                    .Collection(i => i.OrderItems).LoadAsync();
                await _context.Entry(order)
                    .Reference(i => i.OrderStatus).LoadAsync();
                await _context.Entry(order)
                    .Reference(i => i.Address).LoadAsync();
            }
    
            return order;
        }
    

    【讨论】:

      猜你喜欢
      • 2019-01-31
      • 1970-01-01
      • 1970-01-01
      • 2020-04-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-23
      • 1970-01-01
      相关资源
      最近更新 更多