How to enhance events with data from references?

Hi all,

I currently stumbled into the following problem: How do I enhance
events with data from references?

Example:

- Aggregate "A" has two fields: UUID + Name
- Aggregate "B" has a reference to "A" (it contains a fields with the
UUID of "A")

Now when deleteing "B" I want to have an event that contains also the
name of "A" in it's "toString()" message (Something like "B was
deleted from A").

The workflow would be as follows:

1) handle(DeleteBCommand command)
2) b = repository.load(idOfBToDelete)
3) b.delete()
4) apply(new BDeletedEvent(nameOfA))

But where do I get the "nameOfA" from as I only have the UUID of A
inside the B aggregate?

Now I have two options:

1) Enhance the "delete" method of B: "delete(String nameOfA)" - Seems
to be artificial to me
2) Load the name of A inside the "delete()" method - Requires using a
query service inside the aggregate

What would you prefer?

Cheers,
Michael

Hi Michael,

I assume you avoid querying the aggregate-root of A for the NameOfA
because Axon locks the aggregate root of A pessimistically for the
duration of the transaction (as a read in a recent thread here) and
you don't like this because it hurts the performance of your app.
Is it so?

If so, your other options are 1) Query the Query side of the shop if
it is on the same machine; 2) Keep a persistent mapping of IdOfA to
NameOfA as part of your Command-Side. In other words, make your own
private Query-Side inside the command-side (as you suggested yourself
in a different thread, if I remember correctly).

That said, if the answer to my question above is yes, I don't
understand why Axon doesn't provide read-only operation (parallel
to the normal read-and-lock operations to help these kinds of
situations.

I understand that it is a fundamental principle of CQRS not to
query the Command-Side. But having read-only repository operations
for internal use doesn't conflict with that principle at all.
Implementing read-only operations doesn't seem to be technically
difficult either.

So, I assume that there must be some good reasons for not
providing the read-only operations beyond my understanding.

/ES

Hi,

if you need the name of A in aggregate B, there are a few options. If that name is immutable, you could create B with a reference to A and include the name in that operation. If the name is mutable, you could update B with the new name of A each time, but that would add a lot of complexity.
Anotheroption is for the command handler to query for the name of A whenever needed. The method on B could take that name as a parameter in operations where that name is used.
Finally, you can include the name in the command and expect the client to provide it.

Esfand, using the command model do query for state is technically possible, but it would defeat the whole purpose of CQRS. That’s why Axon doesn’t have “read-only operations” or something of the like. If you want to query state, why not use the query model for it? That’s what it is for, after all. You are talking about read only repository operations “for internal use”, and that they don’t conflict with the cqrs principle. I think they do. The command model is not designed to answer questions about its state. The chance is big that the name isn’t even part of the aggregate’s state at all. The hole idea of CQRS is to have one component exclusively for command handling and the other for queries. That means it prevents -by definition- the command component (or its model) to answer queries.

Do note that although I sometimes say “the” query side or “the” query component, there is no such thing. Each component using data should have its own query component. I do have to admit that in my own applications, I take this with a grain of salt and use a little re-use of tables here and there. But once you start scaling out, you can greatly benefit from having query data near the place there it is ultimately needed.

Cheers,

Allard

Hi Allard,

If that name is immutable, you could create B with a reference to A
and include the name in that operation.

The problem is indeed that the name may be changed any time.

If the name is mutable, you could update B with the new name of
A each time, but that would add a lot of complexity.

Agreed. That's why I didn't include it in my enumeration of the
options.

Anotheroption is for the command handler to query for the name of A whenever
needed. The method on B could take that name as a parameter in operations
where that name is used.

If I do that the method signatures are getting very artificial. If you
have a "delete()" method it's not obvious why it should have a name of
a project as argument.

Finally, you can include the name in the command and expect the client to provide it.

That's another possibility - Only thing I don't like the idea very
much that it's not guarnteed the client sends a valid name.

I finally decided to create a special "query interface" for every
aggregate. It only contains the necessary methods and is at the moment
just a wrapper for the real "Query Service".

Is there any possibility to inject properties after an aggregate was
loaded? Something like the ResourceInjector for Sagas?

Cheers,
Michael

Hi Esfand,

I assume you avoid querying the aggregate-root of A for the
NameOfA because Axon locks the aggregate root of A
pessimistically for the duration of the transaction

No, I agree with Allard that it's basically no good idea to use the
repository for querying. Having a small and specialized database at
the command side for some internal querying may be an option. But I
think in my case using the query service inside the aggregate is the
most natural option. Only thing I'm missing is a place to inject the
query service into the aggregate after I loaded it. At the moment I do
this manually in the command handler.

Cheers,
Michael

Hi,

there is a SpringPrototypeEventSourcingRepository, which allows you to use a spring-prototype bean (of an aggregate). An alternative is to inject the applicationcontext in your command handler and inject an aggregate after loading it. A third option is to wrap the repository with an implementation that does the injection for you.

Personally, I make sure the command handler provides all the information the aggregate needs to perform it duties. It makes testing a lot easier. My 2 cents :wink:

Cheers,

Allard

Hi Allard,

Maybe it's a good idea to collect mail conversation like this one and
create an article for the wiki from it. Especially some pseudo code
examples would help new developers getting started and solve common
problems more easily.

Should I write something about this thread? What format?

Cheers,
Michael

Thank you Allard and Michael.

I had the wrong image of having THE command-side, and that
was one reason for my misunderstandings. It seems it is
OK to have many command-subsystems to the extent that one
subsystem be in charge of one aggregate-root. (Perhaps
with a few more subsystems to take care of the inter-AR
concerns.)

Also I sort of though the query side(s) are there mainly
for the clients' benefit. Now I know if feasible (query
system is on the same machine, etc.) the command-side(s)
can also be clients, otherwise one can create local
query-datastores to satisfy the needs of the
command-subsystems.

Thanks again,
/ES

Hi all,

I extracted a short Wiki HowTo page from this thread:
http://code.google.com/p/axonframework/wiki/HowToEnhanceEvents

Cheers,
Michael