What Belongs to the Aggregate Root

前端 未结 7 1398
温柔的废话
温柔的废话 2021-01-30 05:43

This is a practical Domain Driven Design question:

Conceptually, I think I get Aggregate roots until I go to define one.

I have an Employee entity, which has sur

相关标签:
7条回答
  • 2021-01-30 05:53

    I was wondering what the conclusion would be?

    'Violations' become a root entity. And 'violations' would be referenced by 'employee' root entity. ie violations repository <-> employee repository

    But you are consfused about making violations a root entity becuase it has no behavior.

    But is 'behaviour' a criteria to qualify as a root entity? I dont think so.

    0 讨论(0)
  • 2021-01-30 05:55

    a slightly orthogonal question to test understanding here, going back to Order...OrderItem example, there might be an analytics module in the system that wants to look into OrderItems directly i.e get all orderItems for a particular product, or all order items greater than some given value etc, does having a lot of usecases like that and driving "aggregate root" to extreme could we argue that OrderItem is a different aggregate root in itself ??

    0 讨论(0)
  • 2021-01-30 05:59

    After doing even MORE research, I think I have the answer to my question.

    Paul Stovell had this slightly edited response to a similar question on the DDD messageboard. Substitute "Customer" for "Employee", and "Order" for "Violation" and you get the idea.

    Just because Customer references Order doesn't necessarily mean Order falls within the Customer aggregate root. The customer's addresses might, but the orders can be independent (for example, you might have a service that processes all new orders no matter who the customer is. Having to go Customer->Orders makes no sense in this scenario).

    From a domain point of view, you can even question the validity of those references (Customer has reference to a list of Orders). How often will you actually need all orders for a customer? In some systems it makes sense, but in others, one customer might make many orders. Chances are you want orders for a customer between a date range, or orders for a customer that aren't processed yet, or orders which have not been paid, and so on. The scenario in which you'll need all of them might be relatively uncommon. However, it's much more likely that when dealing with an Order, you will want the customer information. So in code, Order.Customer.Name is useful, but Customer.Orders[0].LineItem.SKU - probably not so useful. Of course, that totally depends on your business domain.

    In other words, Updating Customer has nothing to do with updating Orders. And orders, or violations in my case, could conceivable be dealt with independently of Customers/Employees.

    If Violations had detail lines, then Violation and Violation line would then be a part of the same aggregate because changing a violation line would likely affect a Violation.

    EDIT** The wrinkle here in my Domain is that Violations have no behavior. They are basically records of an event that happened. Not sure yet about the implications that has.

    0 讨论(0)
  • 2021-01-30 05:59

    Eric Evan states in his book, Domain-Driven Design: Tackling the Complexity in the Heart of Software,

    An AGGREGATE is a cluster of associated objects that we treat as a unit for the purpose of data changes.

    There are 2 important points here:

    1. These objects should be treated as a "unit".
    2. For the purpose of "data change".

    I believe in your scenario, Employee and Violation are not necessarily a unit together, whereas in the example of Order and OrderItem, they are part of a single unit.

    Another thing that is important when modeling the agggregate boundaries is whether you have any invariants in your aggregate. Invariants are business rules that should be valid within the "whole" aggregate. For example, as for the Order and OrderItem example, you might have an invariant that states the total cost of the order should be less than a predefined amount. In this case, anytime you want to add an OrderItem to the Order, this invariant should be enforced to make sure that your Order is valid. However, in your problem, I don't see any invariants between your entities: Employee and Violation.

    So short answer:

    I believe Employee and Violation each belong to 2 separate aggregates. Each of these entities are also their own aggregate roots. So you need 2 repositories: EmployeeRepository and ViolationRepository.

    I also believe you should have an unidirectional association from Violation to Employee. This way, each Violation object knows who it belongs to. But if you want to get the list of all Violations for a particular Employee, then you can ask the ViolationRepository:

    var list = repository.FindAllViolationsByEmployee(someEmployee);
    
    0 讨论(0)
  • 2021-01-30 06:10

    You say that you have employee entity and violations and each violation does not have any behavior itself. From what I can read above, it seems to me that you may have two aggregate roots:

    • Employee
    • EmployeeViolations (call it EmployeeViolationCard or EmployeeViolationRecords)

    EmployeeViolations is identified by the same employee ID and it holds a collection of violation objects. You get behavior for employee and violations separated this way and you don't get Violation entity without behavior.

    Whether violation is entity or value object you should decide based on its properties.

    0 讨论(0)
  • 2021-01-30 06:10

    It depends. Does any change/add/delete of a vioation change any part of employee - e.g. are you storing violation count, or violation count within past 3 years against employee?

    0 讨论(0)
提交回复
热议问题