Keeping track of children
charlessolar opened this issue · comments
We currently support children getting information from their parent via
this.Parent
we can support a parent getting it's children like so
this.Children<ChildEntity>()
which would read all ChildEntity streams and return a list of ChildEntities.
Child entity stream ids would be in metadata? Or perhaps an internal Aggregates.Net event
-
Option A (Child streams in parent metadata)
Not ideal since when a child a created we'll be doing a double commit - potentially saving parent metadata without actually saving the child (or vice versa). Would also require parent's being aware a child is being created to figure out they need to update their metadata.. -
Option B (Internal Aggregate.NET event)
Each entity would have an initial "Instantiated" event Agg.net would create when.New
is used. This event would contain the parent information and other entity-related things that could be useful.
Also not great as we'd be messing with the user's streams (in a small way) and potentially making migrations and upgrades harder. -
Option C (Aggregates.NET event not written to entity stream)
This would involve raising some event when a new entity is created as well, but not saving the event to the entity stream. Perhaps we'd have a "Aggregates.NET.Data" entity which would be raise events whenever a new entity is defined.
Not ideal because of the double commit problem. -
Option D (Internal Aggregates.NET projection) probably the best option
We'd write and make sure a projection exists which reads all events, looks over the metadata, and partitions the state based on stream id. EventStore would create a state object for each entity stream, and add children to a simple list when it processes a new event with theParent
metadata
Aggregate.NET metadata for parents currently only contains the parent's stream id
{
"EventId": "fdc51d57-deac-4f47-aa63-a9210064653a",
"EntityType": "eShop.Identity.User.Entities.Role.Role, eShop.Identity.Domain.Entities, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null",
"StreamType": "DOMAIN",
"Bucket": "default",
"StreamId": "2a7f6c3a-f218-4968-bf8c-b2fb9e7fa581",
"Parents": [
"Lucas29"
],
"Compressed": false,
"Version": 0,
"Timestamp": "2018-07-18T06:05:31.720422Z",
...
In order for option D to work we'll need to store the parent's entity type as well.
Perhaps turning the parents array into something like
Parent: [
{ EntityType: 'eShop.Identity.User.User, eShop.Identity.Domain.Entities, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null', Id: 'Lucas29' }
]
I am going to tie this issue into #20 - as it requires somewhat of a redesign revolving around event names and types
Using the new Parent array in metadata - an eventstore projection of:
options({
$includeLinks: false,
reorderEvents: false,
processingLag: 0
});
fromCategory('DOMAIN')
.partitionBy(function(event) {
let metadata = JSON.parse(event.metadataRaw);
if(metadata.Parents === null || metadata.Parents.length === 0)
return undefined;
let lastParent = metadata.Parents.pop();
let streamId = 'CHILDREN' + '-' + metadata.Bucket + '-[' + metadata.Parents.join(':') + ']-' + lastParent.EntityType + '-' + lastParent.Id;
return streamId;
})
.when({
$init: function() {
return {
children: []
};
},
$any: function(state, event) {
let metadata = JSON.parse(event.metadataRaw);
if(metadata.Version !== 0)
return state;
state.children.push({ EntityType: metadata.EntityType, StreamId: metadata.StreamId });
return state;
}
})
.outputState();
Can successfully create streams tracking child entities. Resulting stream states look like:
Stream: $projections-working-CHILDREN-default-[]-Language.World v1-World-result
Data
{
"children": [
{
"EntityType": "Language.Message v1",
"StreamId": "f51aa6de-35a8-47ec-a45e-30297bd3ef65"
},
{
"EntityType": "Language.Message v1",
"StreamId": "9cf6fbed-e832-4338-9960-7e8bdbf0129b"
}
]
}