Hibernate/JPA-less state stored aggregate

We would like to store some aggregates as state stored aggregates. But we are not satisfied with the axon state stored aggregates with hibernate. We would like to implement a hexagonal architecture without technical aspects (other that axon itself) in the domain. Hibernate entity structure often opposes to the structure of a domain focussed domain entity. And hibernate annotations pollute the aggregate. So hibernate does not fit our needs.

I have to mention that we have a SQL Database and it is not an option to switch to a NoSQL database…

A naive way woud be to have a command handler that

  1. loads a hibernate entity,
  2. handles it to a converter to get a technology-free aggregate,
  3. hands over the command to that aggregate,
  4. converts it back to a hibernate entity
  5. stores the changes
  6. publishes events that the aggregate might have produced (one chellange here is to get the correct sequence number)

But this solution has much boylerplate code, bypasses much of axon framework, is not safe for concurrent comands as axon aggregates and it’s not possible to publish a domain event from that aggregate or use @EventHandler logic (wich we also have to do).

My question is: Is there a axon conform way to implement and plug-in e.g. an Aggregate Loading/Saving Component that integrates well into Axon so that we can specify how the aggregate is mapped to the persistence layer?

Hello and welcome, Marc!

I’m not quite sure I fully understand what you need. From

Is there a axon conform way to implement and plug-in e.g. an Aggregate Loading/Saving Component that integrates well into Axon so that we can specify how the aggregate is mapped to the persistence layer?

it sounds like what you need is to implement your own Repository. Have you seen the Command Model Repositories docs?

I experienced that State-Stored aggregates are not the best choice if you want to have a domain model which should in no way be influenced by technical circumstances.

When we started using Axon we used Stste-Stored aggregates, too. After some time we realized that it’s much easier to use a clean event-sourced aggregate and build an additional projection/read model/query model ( for example by using JPA) instead of mixing the command and query side.

2 Likes

Hi Milen,

thanks for your hint. Actually I muissed this part of the documentation. But I was shure axon woult provide a hook like this.

It seems the Interface Repository only provides the loading mechnisms for that aggregate. How is this aggregate saved afterwards? Is there another hook I have to implement?

@Oliver_Libutzki Indeed state stored aggregates have a lot of challanges. The DB structure and the logical structure are not the same and collide even in simple scenarios. This would lead to a database centric design of the aggregate and this should not be preferable.
On the other side not every aggregate has to be event sourced and event sourcing has a significant overhad itself. (We used event sourced aggregates for the last couple of years and now we have a good picture of its advantages and downsides…)
So we decided to skip the CQRS part and use the aggregates as read model. (Again this depends on the uses cases. In our case the tradeoff seems to be okay for this solution.) But this should not lead to a mix-in of technical aspects. The idea above is kind of a hybride of the state- and event sourced world…

You can have a look at LockingRepository and GenericJpaRepository to see how the current JPA based Repository for state-stored Aggregates is implemented. I guess you can follow the same approach with your own implementation.

1 Like

We decided to build those UI centric read model by using a Subscribing EventProcessor, so you don’t have to deal with eventual consistency.
.
U experienced this to be the best trade-off in most scenarios.

1 Like

@Oliver_Libutzki That’s exactly what we did.

But read models written by Event Handlers have one downside: You have to implement and test every event handler on the write side and once again on the read side. This often results in lots of duplicated code and potential bugs. (The difference between write and read side tends to be small but the parts that are different are essential and not easy to spot.) If your read model is nearly exactly the same as the write model and you have many state changing events but not so much state this tends to be overengeneered. A simple state mapping seems to be the easier solution in this case. But as always, it depends… :wink:

1 Like