How to determine which field changed when content changes

I’m trying to break down a more complicated document into multiple schemas so I can keep the growth of the event database in check. In this case, I have a workItem and a riskAssessmentPart. I want to ensure that the riskAssessmentPart content cannot be changed when a certain field of the “parent” workItem has a certain value. I tried to solve that by using a Reference field on the workItem that points to the riskAssessmentPart and vice versa. Now, when a content editor adds a risk assesment part to the work item, I want to update the risk assessment part’s reference field to point back to its “owner”, but only if it was the workItem's reference field was changed. How can I do that in a plug-in? Neither UpdateContent nor ContentUpdated contain the previous value. Only the new data.

You have to query the old data.

The ContentChangedTriggerHandler is - among other things - responsible to create enriched events from normal events for the rule system. As part of this process it also fetches the previous data:

1 Like

I saw that part of the code base and suspected that was the approach to take. Or use a Rule for that, but that felt a bit expensive. How efficient is loading the content like this? Will it hit the database every time you execute that method, load the events and rebuild the domain object? Or is there some kind of caching?

There is some kind of caching, the latest version are kept in memory. Each domain object is an actor that receives messages and stays in memory until it is not needed anymore. So right after a change to a content item there is no database call involved.

1 Like

So in your opinion, what’s the best extension point? I see a couple of options.

  1. ICustomCommandMiddleware, but this fires before the domain has accepted the chance, which coudl fail
  2. RuleActionHandler, but that will execute (much) later, although it is more reliable in case of a failure
  3. IEventConsumer, but that will raise every event ever published at start-up again
  4. IValidator, but that one is not meant to affect content changes

If you want to make a change afterwards you can use ICommandMiddleware, it should work fine.

But what would happen if the command gets rejected because of a validator at a later point? Will the call to the next delegate throw an exception if a validator or something like that rejects the command? In other words, can I safely invoke await next(context) and then and then publish a new command on the command bus?

Yes, the command just throws and exception. You should also check IsCompleted flag.

Maybe a look to the templates help: https://github.com/Squidex/squidex/blob/master/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/TemplateCommandMiddleware.cs

When you create an app with a template name it looks up this template and just invokes it. The template executes some other commands then to create the schemas.