Child Entity Initialization

Child Entity Initialization scenario… Will this work?

AggregateRootParentA has

@EventSourcedMember

Map<String, EntityB> mapOfEntities = new HashMap<String, EntityB>();

@EventHandler
AggregateRootParentA.handle(InitEvent event){

EntityB ent = new EntityB(event.getParam1, event.getParam2);
mapOfEntities.put(event.getParam1, ent);

//??NOW need to initialize events on the newly created entity. Can that be done with a method like this
ent.start(); // this fires the typical init events which cannot be fired in Entity constructor as per documentation.

}

Also, how can a child Entity be initialized from a parent Entity which is not an AggregateRoot and would @EventSourcedMember annotation be needed for that also within and parent Entity which is not Aggregate root?

Thanks and Cheers…

Forgot to mention that EntityB would be something like this

class EntityB{
private Object param1;
private Object param2;

private Object param3;
public EntityB(par1, par2){
this.param1=par1;
this.param2=par2;
}

public void start(){
apply( new InitEvent(param1);

}

@EventHandler
public void handle(InitEvent event){
this.param3 = resultfromSomeLogic(event);
}
}

Seeing that this is probably not possible getting error below

So now the problem is that child entities is a Map<String, Entity>.

Need one instance of entity in map to initialize and fire events and only that instance needs to handle it… and also the aggregate root and other external event handler. Would that be possible? maybe not?

Thanks and cheers…

The aggregate root is unknown. Is this entity properly registered as the child of an aggregate member?

at org.axonframework.common.Assert.isTrue(Assert.java:52)

at org.axonframework.common.Assert.notNull(Assert.java:76)

at org.axonframework.eventsourcing.AbstractEventSourcedEntity.apply(AbstractEventSourcedEntity.java:100)

at org.axonframework.eventsourcing.AbstractEventSourcedEntity.apply(AbstractEventSourcedEntity.java:86)

at com.fp.server.flow.base.ActionStepPlan.start(ActionStepPlan.java:57)

at com.fp.server.flow.base.AbstractFlow.onInquiryInitiated(AbstractFlow.java:416)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

at java.lang.reflect.Method.invoke(Method.java:597)

at org.axonframework.common.annotation.MethodMessageHandler.invoke(MethodMessageHandler.java:75)

at org.axonframework.common.annotation.MessageHandlerInvoker.invokeHandlerMethod(MessageHandlerInvoker.java:66)

at org.axonframework.eventhandling.annotation.AnnotationEventHandlerInvoker.invokeEventHandlerMethod(AnnotationEventHandlerInvoker.java:53)

at org.axonframework.eventsourcing.annotation.AbstractAnnotatedAggregateRoot.handle(AbstractAnnotatedAggregateRoot.java:56)

at org.axonframework.eventsourcing.AbstractEventSourcedAggregateRoot.handleRecursively(AbstractEventSourcedAggregateRoot.java:104)

at org.axonframework.eventsourcing.AbstractEventSourcedAggregateRoot.apply(AbstractEventSourcedAggregateRoot.java:95)

at org.axonframework.eventsourcing.AbstractEventSourcedAggregateRoot.apply(AbstractEventSourcedAggregateRoot.java:75)

Sorry to put so much info, trying to keep context current…

Could work around by firing events in sequence i.e. setup Entities with one event fired from root and after that another event to get child entity started from Aggregateroot event and Aggregateroot event handler…

  1. Noticing that child entity is rebuilt with every event applied to it and does not seem to be snapshotting… i.e. initialized and every event applied. Not sure if this is performant as originally these events were in root and this refactoring is an attempt to improve design, however this rebuild performance??

  2. got it to work and saw stack traces for warning on snapshotter and also this error below which is erratically happening and fatal.

java.lang.IllegalStateException: Cannot set first sequence number if events have already been added

at org.axonframework.common.Assert.state(Assert.java:40)

at org.axonframework.domain.EventContainer.initializeSequenceNumber(EventContainer.java:112)

at org.axonframework.domain.AbstractAggregateRoot.initializeEventStream(AbstractAggregateRoot.java:134)

at org.axonframework.eventsourcing.AbstractEventSourcedAggregateRoot.initializeState(AbstractEventSourcedAggregateRoot.java:63)

at org.axonframework.eventsourcing.EventSourcingRepository.doLoad(EventSourcingRepository.java:226)

at org.axonframework.eventsourcing.CachingEventSourcingRepository.doLoad(CachingEventSourcingRepository.java:113)

at org.axonframework.eventsourcing.CachingEventSourcingRepository.doLoad(CachingEventSourcingRepository.java:40)

at org.axonframework.repository.AbstractRepository.load(AbstractRepository.java:77)

at org.axonframework.repository.LockingRepository.load(LockingRepository.java:100)

at org.axonframework.repository.AbstractRepository.load(AbstractRepository.java:87)

at org.axonframework.repository.AbstractRepository.load(AbstractRepository.java:41)

at com.fp.server.flow.commandhandler.AbstractFlowCommandHandler.completeActionStep(AbstractFlowCommandHandler.java:62)

at sun.reflect.GeneratedMethodAccessor146.invoke(Unknown Source)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

at java.lang.reflect.Method.invoke(Method.java:597)

at org.axonframework.common.annotation.MethodMessageHandler.invoke(MethodMessageHandler.java:75)

at org.axonframework.commandhandling.annotation.AnnotationCommandHandlerAdapter.handle(AnnotationCommandHandlerAdapter.java:102)

at org.axonframework.commandhandling.DefaultInterceptorChain.proceed(DefaultInterceptorChain.java:63)

at org.axonframework.commandhandling.DefaultInterceptorChain.proceed(DefaultInterceptorChain.java:69)

at org.axonframework.commandhandling.SimpleCommandBus.doDispatch(SimpleCommandBus.java:127)

at org.axonframework.commandhandling.SimpleCommandBus.doDispatch(SimpleCommandBus.java:103)

at org.axonframework.commandhandling.SimpleCommandBus.dispatch(SimpleCommandBus.java:75)

Hi,

the code you’ve supplied breaks on of the few rule #1’s :wink: That rule is that you must never apply an event in an event handler. Invoking the start method on your entity does exactly that.

Here is what you need to do:

AggregateRootParentA:

@EventSourcedMember
Map<String, EntityB> mapOfEntities = new HashMap<String, EntityB>();

@EventHandler
AggregateRootParentA.handle(InitEvent event){

EntityB ent = new EntityB(event.entityId(), event.getParam1, event.getParam2);
mapOfEntities.put(event.getParam1, ent);

// DO NOT call your entity here. The entity will automatically receive the InitEvent and should initialize itself based on that event

}

class EntityB{
private SomeIdType entityId;
private Object param1;
private Object param2;

private Object param3;
public EntityB(SomeIdType, id, par1, par2){
this.entityId = id;
this.param1=par1;
this.param2=par2;
}

@EventHandler
public void handle(InitEvent event){
// an event is passed to ALL entities in the aggregate. We need to make sure the event is about this instance
if (event.entityId().equals(entityId) {
this.param3 = resultfromSomeLogic(event);
}

}
}

All the other problems you’re encountering are a result of this. If you consider creation of an entity as a state change like any other, then you’ll be fine.
Just to be clear: putting entities in a Map is allowed. Axon will check both the keys and the values for Entity implementations.

Cheers,

Allard

THx… trying to get my head wrapped around the lifecycle…

this does create an issue that a specific initialization event needs to be fired by the entity intance which is listened to by external listeners… so e.g. External listeners DO NOT listen to the initEvent of aggregate root… but EntityInitEvent which is more granular and entity domain specific… also don’t want all entity instance of the map to listen to the EntityInitEvent but only the entity instance to which it originates from, hence it needs to fired from the entity instance… So not sure but that may not be possible? or could entity map be initialized with initEvent and then immediately after the firing of InitEvent in aggregateRoot get a handle to the Entity map object which would now have been initialized by the aggregate root event handler and fire start on all Entities in the map?? Feels hacky??

If this does not make sense, original design already in place with map a non entity field and managing directly from AggregateRoot ? as then intelligently only the correct map instance and data for state can be kept and all events handled by aggregate, however the root is large and needs some design partitioning, which was the rationale to break it down.

Thoughts welcome…

Thanks and Cheers…

This worked and errors did disappear…

IN ROOT constructor {
apply rootInitEvent
go through EntityMap and apply start on each entity to fire EntityStartEvent for each entity instance as the above event would have initialized the entity map
}

in rootInitEvent Handler{
initialize EntityMap
}

Its so Ironic… you think you have worked on something for a while and got it and then you miss the most basic fundamental stuff… :slight_smile:

Thanks and Cheers…