Detecting changes in objects within the aggregate root

I want to see what approaches people could find to detect changes in entities that are part of their aggregates. I have something that works, but I'm not crazy. Basically, my repository is responsible for determining if the state of the aggregate root has changed. Suppose I have an aggregate root named Book

and an object called Page

inside the aggregate. A Book

contains one or more objects Page

stored in the collection Pages

.

First of all, insert and update scripts are executed by checking the root of the aggregate and its entities to determine if a key exists. If the key is present, it is assumed that the object was saved at the same time in the underlying data source. This makes it a candidate for renewal; but this is not final based on this alone. With an aggregate root, the answer is obvious, since there is only one and that is a particular entry point, one might assume that the presence of the key would dictate the operation. In my case, this is an acceptable scenario to keep the aggregate root itself so that I can capture the modified date.

To facilitate this behavior for the objects themselves, my class EntityBase

contains two simple properties: IsUpdated()

, IsDeleted()

. Both are false by default. I don't need to know if it is new or not, because I can make this determination based on the presence of the key, as mentioned earlier. The implementation methods, in this case the page, will have each method that changes the support dataset IsUpdated()

to true.

So, for example, a page has a method called UpdateSectionName()

that changes the backing value of a SectionName

read-only property . This approach is used consistently as it allows a logical binding point of validators in a method (preventing an object from entering an invalid state) that does this data customization. The end result is what I have to put this.IsUpdated() = true;

at the end of the method.

When the aggregated root is posted to the repository for Save()

(a boolean switch for an operation Insert()

or Update()

), it can then iterate over the collection Pages

in Book

, looking for any pages that have one of three scenarios:

  • There is no key. A Page

    keyless A will be inserted.
  • IsDeleted = true;

    The uninstall will throw an update and the uninstall will succeed - ignoring any update for Page

    .
  • IsUpdated = true;

    The page will be updated.

Doing it this way prevents me from simply blindly updating everything in the Pages collection, which can be tricky if, for example, there were several hundred pages in a book. I considered getting a copy of the book and comparison, and only change detection (inserts, updates, and deletions based on presence and / or comparison), but that seemed like an awfully frequent way.

The main disadvantage is that the developer has to remember to set IsUpdated on every method in the entity. Forget it and it won't be able to detect changes for this value. I played with the idea of ​​some kind of specialized backup store that could change timestamps transparently, which in turn could make IsUpdated

a read-only property that the repository can use to aggregate updates.

The repository uses a work pattern implementation unit that bases its actions on the timestamp generated when an aggregate root is added to it. Since there can be multiple objects in operations, the operations of the entities are collapsed and executed immediately after the operation (s) of the aggregate root to which the entities belong. I could go a step further and create another unit of work to just handle the entity operations and base them on some kind of tracking of the events used in the entity (this is how I assume some of the ORM products on the market achieve a similar level of functionality).

Before I proceed in this direction, I would like to hear ideas / recommendations / experiences regarding this.

Edit: A few additional details that might be helpful:

  • The current language I'm working with is C #, although I've tried to store as much language-specific information as possible because it's more of a theoretical discussion.
  • Code for repositories / services / objects / etc. is based on a concept by Tim McCarthy in his book ".NET Domain-Driven Design with C #" and supporting code on CodePlex . It provides a flawless understanding of the type of approach taken, although what I'm working with has mostly been rewritten from scratch.
+2


source to share


1 answer


In short, my answer is that I went with what I suggested. It works, although I'm sure there is room for improvement. The changes actually took very little time, so I feel like I'm not getting very far from the KISS or YAGNI executives in this case. :-)



I still feel like there is room for questions related to synchronization by operations, but I should be able to work around them in repository implementations. Not a perfect solution, but I'm not sure if it is worth reinventing the wheel to fix a problem that can be avoided in less time than it takes to fix.

+1


source







All Articles