TransactionDecorator + UoW

165 views
Skip to first unread message

pd

unread,
May 15, 2015, 12:08:19 PM5/15/15
to ddd...@googlegroups.com
Have been looking at the 6h Greg CQRS vid, and have a very basic question.

In the vid we see something like this:

public class TransactionalHandler<T> : Handles<T> where T : Message {

    private Handles<T> _next;

    public TransactionalHandler(Handles<T> next) {
        _next = next;
    }
   
    public Handle(t cmd) {
        using (new UnitOfWork()) {
            _next.Handle(cmd);
        }
    }

}

I realise that writing "using (new UnitOfWork())" could be conceptual - for illustration purposes - but if not, I'd like to know how this works.

How is that UoW implemented, how will the aggregates' events be saved within it? How does wiring look when putting the new instance within "using"?

I'd imagine a UoW look something like this:

public class UnitOfWork
{
    private IRepository _repository;
    private List<IAggregate> _uncommitted;

    public UnitOfWork(IRepository repository)
    {
        _repository = repository;
        _uncommitted = new List<IAggregate>();
    }

    public void Add(IAggregate aggregate)
    {
        _uncommitted.Add(aggregate);
    }
   
    public void Submit()
    {
        foreach (var a in _uncommitted)
        {
            _repository.Save(a);
        }
    }
}

Thanks

Kirill Chilingarashvili

unread,
May 18, 2015, 3:23:25 AM5/18/15
to ddd...@googlegroups.com
I think UoW should only collect all uncommited events, not aggregates, and should enforce rules so that only events with same stream name be accepted per UoW instance
So one should not be able to save two aggregates in one transaction

pd

unread,
May 18, 2015, 1:01:41 PM5/18/15
to ddd...@googlegroups.com
Thanks Kirill!

That makes sense. Things are still confusing though. I expose one single method for all commands, (inspired by this: https://github.com/damianh/Cedar.CommandHandling/tree/master/src/Cedar.HttpCommandHandling).
So one command is always one single request which in turn equates to one single unit of work.
In my aggregates, if needed, I raise several different events within one single method, and so the uncommitted events build up. When the method is exited, the aggregate is saved and so all events are committed. That's a unit of work.
However, if several methods of the aggregate were to be called, that would mean several commands have been issued, and that equates to several requests, i.e. UoWs.

Is it not common to raise several events in the same method of an aggregate, or is it bad practice?
I don't see the need of some additional "uow" when raising several events in same method, as it gives the same results - assuming of course that a UoW contains events from one command only.
Am I missing something?

pd

unread,
May 18, 2015, 1:03:19 PM5/18/15
to ddd...@googlegroups.com

João Bragança

unread,
May 18, 2015, 1:51:36 PM5/18/15
to ddd...@googlegroups.com
Nothing wrong with an aggregate emitting more than one event from a method. The key is to make sure they express business intent.

Some prefer not to call await _repository.Save(aggregate) at the end of their handler methods. I suppose at some point it's just personal choice.

--
You received this message because you are subscribed to the Google Groups "DDD/CQRS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dddcqrs+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--

Kirill Chilingarashvili

unread,
May 19, 2015, 2:43:44 PM5/19/15
to ddd...@googlegroups.com
one command can raise many events within one aggregate root
all events will be saved so single stream 

if needed you can add UoW pattern so many commands of a single aggregate instance are consumed in single transaction

var aggr = repo.fetch(aggrId)
aggr.DoCmd1(params);
aggr.DoCmd2(params);
aggr.DoCmd3(params);
repo.Save(aggr);

so here if one command results in 3 events, we have in total 9 events
and repository must save 9 events at once instead of 3 per transaction

implementation of how UoW interacts with repository and command handler is up to you - but logically if you can save 3 events per transaction you can save 9 with same success, given the stream name is the same

João Bragança

unread,
May 19, 2015, 7:13:45 PM5/19/15
to ddd...@googlegroups.com
But it's simpler to have a method that calls the other 3 methods for the two times that you need it. Maybe.

--
You received this message because you are subscribed to the Google Groups "DDD/CQRS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dddcqrs+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Kirill Chilingarashvili

unread,
May 19, 2015, 11:34:34 PM5/19/15
to ddd...@googlegroups.com, joao...@braganca.name
Yes if you add one more command calling three methods - they will be saved in a single transaction

pd

unread,
May 22, 2015, 8:43:01 AM5/22/15
to ddd...@googlegroups.com, joao...@braganca.name
 Okay, so what you guys describe doesn't differ much from what I'm doing.

I have _one_ method in the aggregate, per command. The granularity of events to be stored is all managed within the aggregate, i.e. if I want this process in my business to be described with 9 different events, then 9 events are raised within that single method.
If 4 out of those events are also raised in another process (triggered by another command of course), then those are raised in that method too.
I do however refactor that within the aggregate so that I have private methods there, as to avoid repeating code.

Never will a command lead to the command handler making more than one method call on my aggregate, nor on any other aggregate than that single one.

In a ProcessManager though, that could happen.

So, all in all, with that way of designing it, the UoW is implemented. 1 or n events from a command doesn't make any difference, they are stored all together, or not at all.

Kirill Chilingarashvili

unread,
May 23, 2015, 2:11:59 AM5/23/15
to ddd...@googlegroups.com, joao...@braganca.name
Sometimes you need to have a freedom of calling more then one command in single commit, so that I dont need to change code in aggregate for each use case

Actually  I even not expose UoW in api
I just added overload to IEngine interface

void ExecuteMany(params ICommand[] commands)

the implementation just checks that all commands point to single aggregate instance (otherwise exception is thrown)
and then
1) fetches aggregate from ES
2) applies sequentially each command by locating it's command handler and calling extra method for applying command without saving
3) saves aggregate
Reply all
Reply to author
Forward
0 new messages