3

In my domain there's a part where I have a root entity, with some fields, and then some other entity inside that aggregate, like this:

class AggregateRootEntity {
   ... some fields ...
   Entity listOfInstancesOfThatEntity = [];
}

Given that the aggregate can have, for instance, 200 instances of Entity in that list, how would you update the aggregate with a repository? I mean, if I update only an element of that list, I need to call the repository like repository.update(AggregateRootEntity), but if I do it like then I do not have a way to know what inner entity has changed, so I would need to either:

  1. Retrieve all the inner entities from storage and compute which of them have changed.
  2. Update all of them.

I dislike option 1 because that would make the repository code quite complicated. I also don't like option 2 because that would make every update very costly.

I'm also the same problem when I want to add a new Entity to the list, or remove one.

Any idea how can this be implemented to solve the listed problems? Am I approaching the problem in the wrong way?

1
  • 1
    You don’t mention what type of database you’re using. I’m guessing relational, because this problem is typical for a relational database. Rolling your own change tracking mechanism can be very challenging, especially if you want to keep that code out of the domain. Are you not using an ORM that has change tracking?
    – Rik D
    Commented Apr 24, 2022 at 12:52

2 Answers 2

2

There is an alternative approach: do not to persist without business context.

The scenario you are describing happens all the time with so called "persistence agnostic" designs. This just means that the "logic" does not know anything about how to persist things. This unfortunately also automatically means that the persistence logic does not know anything about what actually happened. The end result is that the persistence part needs to reverse-engineer what happened and how to best persist it. For very simple scenarios this actually works.

There are solutions for very specific things. For example your problem could conceivably be solved by tracking changes in data, then persisting those that changed.

However these will only work to a point and are arguably already business logic specific, since you do them to cover a specific case.

So instead of that, one alternative is to persist in the context of a use-case. For example if you are currently trying to disable all the credit cards of a customer, you can just fire one simple SQL statement and be done with it. You don't really need a separate in-memory data model that you later try to synchronize to the database.

Key is to not expose data, and instead expose behavior. If you manage to do that (and I'm not saying this is easy), these kinds of problems don't appear in the first place, since you always know exactly what the user is trying to do, hence you have the context with which you can optimize for the specific case.

1
1

I delete all the existing data and re-insert inside a transaction.

This is only problematic (in relational dbs) if you also have operations on "All BigEnities" and is much faster that retrieve old version, compare, update.

You have:

   open trans
   delete sub entities by parent id
   delete entity by id
   (bulk?) insert rows
   close trans

you could also do a merge. not sure on the performance difference.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.