Open CumpsD opened 3 years ago
UPDATE [address-registry].AddressRegistryLegacy.AddressSyndication
SET EventDataAsXml = REPLACE(REPLACE(EventDataAsXml, '</AddressPersistentLocalIdWasAssigned>', '</AddressPersistentLocalIdentifierWasAssigned>'), '<AddressPersistentLocalIdWasAssigned>', '<AddressPersistentLocalIdentifierWasAssigned>')
WHERE [changetype] = 'AddressPersistentLocalIdentifierWasAssigned' AND EventDataAsXml LIKE '<AddressPersistentLocalIdWasAssigned>%'
UPDATE [building-registry].BuildingRegistryLegacy.BuildingSyndication
SET
EventDataAsXml =
(CASE
WHEN [changetype] = 'BuildingPersistentLocalIdentifierWasAssigned' THEN REPLACE(REPLACE(EventDataAsXml, '</BuildingPersistentLocalIdWasAssigned>', '</BuildingPersistentLocalIdentifierWasAssigned>'), '<BuildingPersistentLocalIdWasAssigned>', '<BuildingPersistentLocalIdentifierWasAssigned>')
WHEN [changetype] = 'BuildingUnitPersistentLocalIdentifierWasAssigned' THEN REPLACE(REPLACE(EventDataAsXml, '</BuildingUnitPersistentLocalIdWasAssigned>', '</BuildingUnitPersistentLocalIdentifierWasAssigned>'), '<BuildingUnitPersistentLocalIdWasAssigned>', '<BuildingUnitPersistentLocalIdentifierWasAssigned>')
WHEN [changetype] = 'BuildingUnitPersistentLocalIdentifierWasDuplicated' THEN REPLACE(REPLACE(EventDataAsXml, '</BuildingUnitPersistentLocalIdWasDuplicated>', '</BuildingUnitPersistentLocalIdentifierWasDuplicated>'), '<BuildingUnitPersistentLocalIdWasDuplicated>', '<BuildingUnitPersistentLocalIdentifierWasDuplicated>')
WHEN [changetype] = 'BuildingUnitPersistentLocalIdentifierWasRemoved' THEN REPLACE(REPLACE(EventDataAsXml, '</BuildingUnitPersistentLocalIdWasRemoved>', '</BuildingUnitPersistentLocalIdentifierWasRemoved>'), '<BuildingUnitPersistentLocalIdWasRemoved>', '<BuildingUnitPersistentLocalIdentifierWasRemoved>')
END)
WHERE ([changetype] = 'BuildingPersistentLocalIdentifierWasAssigned' AND EventDataAsXml LIKE '<BuildingPersistentLocalIdWasAssigned>%')
OR ([changetype] = 'BuildingUnitPersistentLocalIdentifierWasAssigned' AND EventDataAsXml LIKE '<BuildingUnitPersistentLocalIdWasAssigned>%')
OR ([changetype] = 'BuildingUnitPersistentLocalIdentifierWasDuplicated' AND EventDataAsXml LIKE '<BuildingUnitPersistentLocalIdWasDuplicated>%')
OR ([changetype] = 'BuildingUnitPersistentLocalIdentifierWasRemoved' AND EventDataAsXml LIKE '<BuildingUnitPersistentLocalIdWasRemoved>%')
Address fix: https://github.com/Informatievlaanderen/address-registry/pull/214
AddressPersistentLocalIdWasAssigned
=> AddressPersistentLocalIdentifierWasAssigned
Rebuild or SQL replace needed
https://github.com/Informatievlaanderen/building-registry/pull/185 Building: rebuild or sql replace needed
BuildingPersistentLocalIdWasAssigned => BuildingPersistentLocalIdentifierWasAssigned
BuildingUnitPersistentLocalIdWasAssigned => BuildingUnitPersistentLocalIdentifierWasAssigned
BuildingUnitPersistentLocalIdWasDuplicated => BuildingUnitPersistentLocalIdentifierWasDuplicated
BuildingUnitPersistentLocalIdWasRemoved => BuildingUnitPersistentLocalIdentifierWasRemoved
We need to make sure the receiving ends also use the correct names.
To check:
The case of
[EventName]
and Syndication FeedsContext
In our usage of Event Sourcing, we keep the event name as a column in our Events to allow for future deserialisation of the event back into an object. In a very early version, we naively took the class name as the event name. Not long afterwards we introduced an EventNameAttribute to turn this into a fixed value, which would survive refactoring of our code.
For example:
If this class ever had to be renamed to
MunicipalityBecameCurrentV1
, it would not break our deserialisation, becauseMunicipalityBecameCurrent
would be the stored key.Over time, this attribute has taken on other usages as well, for example in documenting all our events with Structurizr, together with
EventDescription
.For the most part of the development, events have remained an implementation detail and were not exposed to the outside world. Until a feature request came along to allow our user to get a feed of events. The use case is to allow them to built anything they want based on the events.
This resulted in the creation of the Feeds endpoints. These endpoints are populated by Syndication projections in each registry. In these projections SetEventData is responsible for populating the XML representation of the event for outside consumption. The feed endpoints simply return these pre-serialised events to the consumer.
Problem
Whereas we used the
EventNameAttribute
for de/serialisation in the Event Store, we made the mistake of using the following code in the syndication projections:This means the class name is used in the feeds instead of the attribute name. In most cases these were identical, causing the late detection of this bug, but in some cases they were different:
This resulted in an XML element having
MunicipalityFacilitiesLanguageWasAdded
as a root tag instead ofMunicipalityFacilityLanguageWasAdded
, while also being vulnerable to breaking changes when refactoring class names.Solution
A solution for this has been implemented in https://github.com/Informatievlaanderen/municipality-registry/pull/107 which does not use the class name anymore, but uses the
EventNameAttribute
.This fix has to be implemented in every registry separately.
Update: While fixing it, we did not have to use reflection to get the attribute, the event name was already present in the event itself.
Additional remarks
EventNameAttribute
.Todo
Determine in which registers this occurs to rebuild the projections. Finding this can be done with a unit test:
Registries to check
Rebuilds Required