Event Migration: Best practice for semantically changed event


we used to have two events that belonged together: A Restored Event and a Created event. The Restored event cleared some changes and the Created event applied the changes on top of the cleared state. Now we learned that these events only exist in this combination and no other combination would make any sense. So we combined these to in a changed Created event with one additional property to clear before applying the new changes.

So one step in applying the event (the clearing) ist not backwards compatible. Adding the Restored event and the clearing in the new Created semantics would lead to a different outcome.

We tried to just change the Created event to Version “2” with adding a upcaster assuming that we would detect the “old” events by its old version number. But after passing the upcaster chain the old event has the new version number. So this seems not to be an option.

Some other ideas we had was:

  1. Add a property to the event to differenciate between these two versions. (The upcaster would set “old”, default for new events is “new”.)

  2. We create a new Event CreatedV2 because the semantics changed.

  3. We could use a Multy-Upcaster.

Solution 1 and 2 are a bit “clumsy” and 3 ist technically the most challenging. Still we would prefer 3 because the would not introduce technical properties/names in our events.

What is the “best way” to solve such a situation?

If 3 should be the best one how would this look like?

Thank you!


Hi Marc,

When the semantic meaning of an event changes, that essentially means you have a new type event.
It is thus typically not recommended to upcast these, at all. Just create a new event which serves the intended purpose.

However your description is slightly hazy to me; I’d need to know more of the domain to deduce whether the above is really the best approach to take.
So as always, it depends…

When it comes to writing a many-to-one upcaster, I’d suggest to use the ContextAwareSingleEventUpcaster (as mentioned in the reference guide).

This implementation allows the storage of information of events it passes in its “context”.
If you are looking for an implementation suggestion, I’d have a look at the test cases provided by the framework.
For your convenience, you can find those here.

Steven van Beelen