Hello Sam,
The command handler on a constructor is a specific case of command handler to simpify the use case of creating an aggregate.
Normally you would need to introduce separate command handler that would create an instance of aggregate and then it save it, axon simplifies this process by letting you do the thing inside class constructor of an aggregate.
There is however, an solution to your issue, if I’m not mistaken, you want to create an aggregate identifier based on some database id generator, and by the point in time when you publish such command you do not have access to the ORM/Repository implementation.
In axon, there’s a thing https://github.com/AxonFramework/AxonFramework/blob/master/messaging/src/main/java/org/axonframework/commandhandling/distributed/UnresolvedRoutingKeyPolicy.java which controls how to route the command when there is no aggregate identifier, there was also a pull request for configuring such here: https://github.com/AxonFramework/AxonFramework/pull/456.
Using above classes and configuration, you could create a command that is dispatched to static command handler which behavior would be like this:
You create command class for static dispatch with either defined aggregate identifier as static one, or you configure the unresolved key policy, whatever you choose, it will work.
Now, in your constructor of your aggregate, instead of passing / persisting the id specified in the command, you generate that with your repository id generator.
However it really smells like a design smell. The aggregate command handler itself should not really have a knowledge of persistence, nothing should in your core domain, unless really necessary, an ideal way would be to create command handler for creating your aggregate outside of your aggregate and call it an application service, that would just listen for commands and create appropriate aggregates for you depending on how you would like to create the ids. You are adding dependency of your external write model to the aggregate itself which for me just doesn’t seem right.
To summarize, yes it is possible, however it is not in my opinion the place where aggregate ids should be passed, generated etc, i think that you’re trying to make your life easier with integrating your external database with the axon infrastructure. In my opinion axon has its own persistence model which should not be modified to our needs, but the other way around, our needs should be modified in favor of axon.
An example:
`
@Component
class AggregateCreator {
@Autowired
private lateinit var aggregateRepository: Repository<Aggregate>
@CommandHandler
fun handle(cmd: CreateHotWallet, identifierFactory: IdentifierFactory) {
val createCommand = CreateHotWallet(identifierFactory.generateIdentifier())
this.aggregateRepository.newInstance { Aggregate(createCommand) }
}
}
`