Updating multiple aggregates in one transaction

3,403 views
Skip to first unread message

sudarshan

unread,
Jan 20, 2012, 7:38:01 AM1/20/12
to DDD/CQRS
Hi,

I am having a scenario where i am leaning towards breaking the rule of
updating one aggregate per transaction :)

Well i am really new into this DDD/CQRS thing and so my leaning is
probably wrong ...

Well my case being ....

I need to issue a Book and when a book is issued I need to have a
record of the transaction (Moment-Interval)

This is a really simple example application, so the requirements are
cooked up by me :) ... I know that in itself sounds bad !

Ok so i went down the route of promoting all my entities which are
made of only simple attributes into Aggregates ...

So say Book with attributes Id,Name,ISBN is one AR

and BookLending with attributes BookId,MemberId,LendingInterval is
another


When a book is issued, the Book AR is updated to reduce the
availableCopies

and a new BookLending AR is created and persisted ....

Yup so 2 AR's 1 transaction ....

If i expand this example it sort of seems true for any thing which
needs a Moment-Interval class

http://www.step-10.com/SoftwareDesign/ModellingInColour/Moment-Interval.html

Any thoughts

MWightman

unread,
Jan 20, 2012, 9:08:50 AM1/20/12
to DDD/CQRS
Sudarshan,

Transactions are all matter of perspective. When you Call
Book.Loan(person) publish a domain event that the a book audit
service is listening for and have it write the audit record.

Mike
> http://www.step-10.com/SoftwareDesign/ModellingInColour/Moment-Interv...
>
> Any thoughts

sudarshan

unread,
Jan 20, 2012, 12:53:47 PM1/20/12
to DDD/CQRS
Well i was thinking that my AR should ideally model the transaction
boundaries and hence one AR per transaction ...

However in this case my Moment-interval/business transaction record is
important and i would want it to be consistent with my Book AR ....

Also i was under the impression that events are used to notify others
BC's about important landmarks in my current BC ...

With both my AR's Book and BookLending being in the same BC are events
the correct/desirable way communicate between them ?

Can my commandHandler not just create the Momemnt-Interval class and
persist it while it updates the book object?

belitre

unread,
Jan 21, 2012, 4:43:18 AM1/21/12
to DDD/CQRS
Could be availableCopies property changed from Book AR to BookLending
AR?
So you have Book (actor), BookInLends (role), BookLending
(transaction).
BookInLends would belong to BookLending aggregate (it is the same
context) and the command affects just 1 aggregate.

sudarshan

unread,
Jan 21, 2012, 12:51:32 PM1/21/12
to DDD/CQRS
I would imagine it is a fairly common retirement to create or update a
transaction entity because of changes to the main entity .... Is this
usually done through events ?

@ belitre ... Your answer sounds d sensible to me in this case, can
you give me a hint on how it can be extendedfor other similar
scenarios

Thanks

@yreynhout

unread,
Jan 21, 2012, 6:52:50 PM1/21/12
to DDD/CQRS
If I'm lending a book what is the chance I'll be lending the last copy
and somebody else wants to lend that same book at exactly the same
time. Why is that a case to optimize for? How likely is it to happen?
And even if it happens, and it's detected after the fact, what
consequence would it have wrt lending a book?

In other news: Why are you even building a book lending app with CQRS/
ES? What is the competitive advantage in that, beyond a "money down
the drain" experiment to learn CQRS? What's so special about it, that
you can't use an off the shelf solution? I hate bashing as much as the
next guy, but common, when I'm reading some of the domains people work
in when they post an entry here, I'm left with: "Did anybody do the
analysis wrt the applicability of these patterns in THAT domain?
What's complex about that?" I might be wrong ...
I see many (recurring) Qs on trying to solve the same problems "we"
had with layered/tiered CRUD architecture. While useful when you need
them, it's the over-emphasis that feels "disturbing".
I understand this POV will not make me popular ... let me put it this
way: I'm not running for president (aka I don't care). If anything, I
hope it makes most people reevaluate how much of DDD, CQRS, ES it is
they need and where they need it.

@Sudarshan: don't take this personal, it's not meant to be personal. I
just happened to vent this on your thread.

Kelly Sommers

unread,
Jan 22, 2012, 2:35:45 AM1/22/12
to ddd...@googlegroups.com
Sudarshan did say " This is a really simple example application, so the requirements are
cooked up by me :)". I wouldn't say any money is down the drain if someone is implementing to learn. No business cost here.

Even if it wasn't an example, I think it's hard to judge if someone is implementing a simple domain off a couple questions. People have to start somewhere and they aren't likely to start with the most complicated pieces of a domain. Even a complex domain may contain some simplistic pieces. I'm not sure if it's fair to judge people's domains off a single question.

Let's encourage learning. Just my 2c.

Later,
Kell

Dylan Smith

unread,
Jan 22, 2012, 3:43:20 AM1/22/12
to ddd...@googlegroups.com
You could do it in one transaction, but you do so at the price of partitionability (is that a word?). Because you're making the assumption that the events for the Book AR and the BookLending AR live in the same datastore.

The other options are to:
1. Use a saga to model what should happen if the book AR updates succeed but the BookLending creation fails. Whenever I'm doing something that touches more than one AR I start to think in terms of saga's.
2. If there is no way for the BookLending creation to fail (assuming the Book AR updates succeeded), then you don't need to do it inside a command, but can use an EventHandler listending for the Book AR event (as somebody else mentioned).

Scott Reynolds

unread,
Jan 22, 2012, 4:22:14 AM1/22/12
to ddd...@googlegroups.com
Perhaps Book doesn't care about its available copies. Book doesn't really care if its available does it - It seems book is more a record of what books you have. The BookLoan screen within an application wouldn't be a single aggregate.

BookLending might be a better place to store it. Treat Book Lending as a service

You could simply have

Book
{
the descriptive properties of book
}
BookForLoan
{
CopiesAvailable
BookId
BookLoan[] SpecificBooks
}
BookLoan
{
BookSerialNumber, MemberId, LendingInterval
}

Just be careful with The BookForLoan aggregate - at the aggregate is your transaction boundary as well.

sudarshan

unread,
Jan 22, 2012, 9:32:35 AM1/22/12
to DDD/CQRS
@yreynhout

This is just a learning app, what i am trying to evaluate is how
easily can we separate commands and queries in a conventional web
app .... I have learnt from previous experience that using the same
model for both commands and queries can make things confusing ...

So i am trying to build a small POC where in i separate the two,
however i am not using ES here, its just the same RDBMS and i have a
set of views for the read side and then the regular ORM for the
write ....

I am not sure what to call it may be CQS .... I then also use a
command bus to separate out my server side logic from the Web
controller ... So i guess i am borrowing from the CQRS pattern ....

But i think my question had its roots more in DDD, and here too i
think DDD principles like AR's and so on should serve well for most
projects ...

I really appreciate that CQRS is not sold as a silver bullet :),
however the principles do have wide applicability IMHO


@Scott

When do we create a BookForLoan AR ? I mean when here BookForLoan AR
looks like a Role that the Book (Thing) is playing, so we create
BookForLoan AR when a Book AR is created so that we can say we
purchased 5 copies of XXXX book ....

I am borrowing all my lingo about Role,Thing from

http://www.step-10.com/SoftwareDesign/ModellingInColour/Role.html


My larger question is how do we overlay the concepts from archetypes
and DDD and some of the guiding principles from CQRS (One AR update
per Transaction) in this case ...

When a AR gets updated which requires the creation/updation of a
Moment Interval archetype .... should we tend towards Eventual
consistency using Events .... (By events i do not mean ES, I mean
Events as a means of letting interested components know) ...

I sort of get that the answer for my above question is "it depends" :)
basically driven by the consistency needs of the domain ....

However the way I see it most MI classes will be AR's in there own
right and will be updated/created when a transaction it performed on a
Role/Party ... so that automatically means that 2 AR's get affected by
a single command .... Yes we could say that 1 of them gets
"eventually" affected ....

So is that how most of us handle similar scenarios ?


On Jan 22, 2:22 pm, Scott Reynolds <scott.reynolds...@gmail.com>
wrote:
> >http://www.step-10.com/SoftwareDesign/ModellingInColour/Moment-Interv...
>
> > Any thoughts

@yreynhout

unread,
Jan 22, 2012, 3:41:36 PM1/22/12
to DDD/CQRS
I'm all for learning, Kelly, and yes, I might have hijacked this
thread somewhat :)

Well, "no cost here", as long as you're doing that in your own time or
your employer agrees to it. Regardless, I'm pretty sure some will
choose these acronyms without proper analysis, and there's nothing
much anybody can do about it, aside from raising awareness that this
choice should be made explicitly and in context. I think this might be
even more of a concern wrt DDD.

I'm not judging the domains people work in. I seriously doubt many of
us work in user or order mgmt. Maybe it's my craving for more
facinating domains, maybe it's my allergy for these somewhat naive
domains, maybe most of these things aren't a domain at all, especially
these made up examples that spawn whole threads of - well, I won't say
pointless, I'm sure there's a point, I really do - discussion going
forward and backward trying to distill what the domain is about or
what the true invariant is, or providing a solution upfront. If they
don't get side-tracked in definitions/redefinitions or plain technical
discussions (which I do enjoy BTW), that is.
That sounded a bit negative, so there must be some truth in it. I've
partcipated in many of these in the past, so no point in me being a
hypocrit ;)

Don't get me wrong, it's not about scaring new people - getting their
feet wet - away. Yes, that needs encouraging. But also clarification
that service/bounded context are no loose terms and the development
style you apply in them matters.

I hope people walk away with "I need to think this thru before
choosing to apply this on a project that will see production daylight
(or at least that is the intent)" ... that's all I really want. That
leaves plenty of room for examples, trying out, trying to understand,
asking questions here, ... before coming to a decision. I'm all for
it ;)

Carry on ... Nothing to see here.

Roy

unread,
Jan 25, 2012, 1:14:46 AM1/25/12
to DDD/CQRS
I'm glad you're learning this topic. For real projects or large
projects, you normally don't have the luxury to model the entire
system in DDD fashion. This is why it is recommend to model the core.
That special, perhaps proprietary, aspect of the business. You said
you're not using event sourcing, but you do need a mechanism for
tracking changes or events of all ARs in a transaction. I don't think
you can escape producing events. You have to implement your own Unit
of Work pattern for in-memory processing in the command handler.


On Jan 20, 7:38 am, sudarshan <sudarsha...@gmail.com> wrote:
> http://www.step-10.com/SoftwareDesign/ModellingInColour/Moment-Interv...
>
> Any thoughts

sudarshan

unread,
Jan 25, 2012, 11:55:59 AM1/25/12
to DDD/CQRS
I am looking at something like

http://codeofrob.com/archive/2011/09/28/cqrs-is-too-complicated.aspx

The model where he talks about using views to project a denormalised
view of your database.

I think its the 4th daigram in the post ..

Nuno Lopes

unread,
Jan 25, 2012, 3:24:28 PM1/25/12
to ddd...@googlegroups.com
Hi,

It is totally fine to have two domain objects participating in the the same transaction. It works most cases and you can still use DDD in those circumstances.

You can relax the consistency boundary of an AR by make some transaction in an Aggregate dependent on the completion of others as long as they belong to the same Bounded Context. There is no point in over complicating things.

For instance consider the simple scenario where the person gets into a store, asks for a book to be lent, the clerk checks the book availability, goes downstairs to the warehouse, picks the book and registers the lend. The clerk already has the book in his hands, so even if you use two separate transactions it would hardly fail if not for a major failure of ones database system between two writes. So just make both writes in the same transaction. Probably this is the scenario you have in mind.

Nothing wrong with that.

Having said this, lending books can be more involved then this. Consider the case of an online store where the books are stored in uncertain location (for instance we have multiple warehouses spread across the country). The value in stock can be uncertain at the time of lending the book. For instance, can we actually infer that the book is lent if not shipped? And so on.

So to distributive nature of your business you might need a long running business transactions, say a BookLendingOrder which might fail during the process.

Cheers,

Nuno

Philip Jander

unread,
Jan 25, 2012, 6:26:58 PM1/25/12
to ddd...@googlegroups.com
Am 25.01.2012 21:24, schrieb Nuno Lopes:
> Hi,
>
> It is totally fine to have two domain objects participating in the the same transaction. It works most cases and you can still use DDD in those circumstances.
>
> You can relax the consistency boundary of an AR by make some transaction in an Aggregate dependent on the completion of others as long as they belong to the same Bounded Context. There is no point in over complicating things.
>
I second that. In particular when using event sourcing, I find it quite
useful to momentarily couple two aggregates in one transaction.
The only issue is that this prevents scaling out by sharding, but this
decision is not forever. Nothing prevents you from reimplementing the
interaction using messaging and sags should the need arise.
On the other hand, implementing an interaction between two aggregates
which are living on the same physical tier anyway through messaging
produces a lot of unneccessary overhead upfront.

So I would say that while an aggregate is defined by a consistency
boundary, it follows that all changes to an aggregate must be in one
transaction, the inverse is not true:
Having two aggregates cooperate in a transaction for certain use cases
neither violates the consistency boundary (each aggregate is fully
consistent)
nor does it neccessarily hint towards incorrent aggregate layout.

Cheers
Phil

netfocus

unread,
Jan 29, 2012, 12:03:01 PM1/29/12
to DDD/CQRS
The moment-interval represents some object interactions, at least two
aggregates participate in the interaction.
For the book lending example. Lending a book or borrow a book is an
interaction. The result of this action is a book was borrowed or you
can said a book was lent.
In general, i think any of the interaction will generate a new
aggregate. In the book lending example, a BorrowedBook AG will be
created. This aggregate contains the information about all the
interaction participator objects. Such as the book, the borrower, and
also the borrowed time. So the BorrowedBook AG class will look like
below:
public class BorrowedBook : AggregateRoot
{
public Guid BookId { get; private set; }
public Guid BorrowerId { get; private set; }
public DateTime BorrowTime { get; private set; }
}

After the BorrowedBook AG was created, there will be a
BorowedBookCreated event handler(maybe a saga) which will send a
UpdateBookCopies command to update the book's remaining copies. The
code may looks like below:
public class BorrowedBookCreatedEventHandler : SagaBase,
IEventHandler<BorrowedBookCreated>
{
public void Handle(BorrowedBookCeated evnt)
{
_commandBus.SendCommand(new UpdateBookCopiesCommand());
}
}


The question is who has the book copies information, and when this
information was generated. The answer is that when the book manager
put the books on the book stock, you can understand this as a context
when the book manager input the book information and its copies
information into the computer. In that context, a BookOnStockInfo AG
will be created:
public class BookOnStockInfo : AggregateRoot
{
public Guid BookId { get; private set; }
public int Copies { get; private set; }
public DateTime OnStockTime { get; private set; }
}

So the UpdateBookCopies command will result in updating the
BookOnStockInfo AG. Some code like below:
public class UpdateBookCopiesCommandHandler :
ICommandHandler<UpdateBookCopiesCommand>
{
public void Handle(UpdateBookCopiesCommand command)
{
var book = _repository.GetById<Book>(command.BookId);
var bookOnStockInfo =
_repository.GetById<BookOnStockInfo>(book.StockInfoId);
bookOnStockInfo.DecreaseCopiesCount();
}
}

Some explanations, in my design, the Book AG looks like below:
public class Book : AggregateRoot
{
public string Name { get; private set; }
public string Author { get; private set; }
public int Pages { get; private set; }
// some other book common properties, etc.
public Guid StockInfoId { get; private set; } //empty by default,
but when the book was put on the stock, this property will be updated.
}

In my opinion, yes, aggregate represents a consistency boundary, a
transaction boundary, that's correct. But in real projects, a lot
command represents an interaction. Any interactions must have at least
two aggregates to involved in.
For example, when a user want to apply a job, then he submit a resume
to the target company. This will generate a JobApplication aggregate.
this aggregate will contains the applicant user and the job position
and the apply time information.

So my question is, why we can ensure one command will only just effect
one aggregate?

sudarshan

unread,
Jan 31, 2012, 5:50:45 AM1/31/12
to DDD/CQRS
+1 for your question

And i think Philip answers your here

"
So I would say that while an aggregate is defined by a consistency
boundary, it follows that all changes to an aggregate must be in one
transaction, the inverse is not true:
Having two aggregates cooperate in a transaction for certain use
cases
neither violates the consistency boundary (each aggregate is fully
consistent)
nor does it neccessarily hint towards incorrent aggregate layout.
"

Thanks
Reply all
Reply to author
Forward
0 new messages