solidservices icon indicating copy to clipboard operation
solidservices copied to clipboard

Commands depending on other commands when using the decorator pattern for transaction

Open ghost opened this issue 8 years ago • 3 comments

Hi,

I've been using your TransactionCommandHandlerDecorator and I came across a small problem when using this in conjunction with a command that has a dependency on another command as it is creating a second transaction block for the other command when I want it to share the same transaction?

Here is some code to demonstrate the problem.

Public Class TransactionCommandHandlerDecorator(Of TCommand)
    Implements ICommandHandler(Of TCommand)

    Private ReadOnly _decorated As ICommandHandler(Of TCommand)
    Private ReadOnly _context As ApplicationDBContext

    Public Sub New(context As ApplicationDBContext, decorated As ICommandHandler(Of TCommand))
        _context = context
        _decorated = decorated
    End Sub

    Public Sub Handle(command As TCommand) Implements ICommandHandler(Of TCommand).Handle
        Using transaction = _context.Database.BeginTransaction()
            Try
                _decorated.Handle(command)
                transaction.Commit()
            Catch ex As Exception
                transaction.Rollback()
                Throw
            End Try
        End Using
    End Sub
End Class
Public Class CreateProcedureTemplateDetailQuestionTypeHandler
    Implements ICommandHandler(Of CreateProcedureTemplateDetailQuestionTypeCommand)

    Private ReadOnly _context As ApplicationDBContext
    Private ReadOnly _handler As ICommandHandler(Of CreateProcedureTemplateDetailCommand)

    Public Sub New(context As ApplicationDBContext, handler As ICommandHandler(Of CreateProcedureTemplateDetailCommand))
        _context = context
        _handler = handler
    End Sub

    Public Sub Handle(command As CreateProcedureTemplateDetailQuestionTypeCommand)
        Implements ICommandHandler(Of CreateProcedureTemplateDetailQuestionTypeCommand).Handle
        _handler.Handle(command.DetailCommand)

        'Do other stuff specific to this command
    End Sub
End Class

But once I call handle inside of CreateProcedureTemplateDetailQuestionTypeHandler.Handle() I get an exception as it tries to create another transaction scope. What is the best way of dealing with this, should I just new up instance inside of the CreateProcedureTemplateDetailQuestionTypeHandler and not use DI for that case?

ghost avatar May 24 '17 10:05 ghost

ith a command that has a dependency on another command

This is the core of your problem. My advise is to treat commands as holistic abstractions. This means that command handlers should not depend on other command handlers, especially not within the context of the same abstraction. You should use a different abstraction when dealing with 'sub commands'. This could be as well a generic abstraction, or you use normal non-generic interfaces for them.

dotnetjunkie avatar May 24 '17 11:05 dotnetjunkie

What I have done is created a ICommandStrategyHandler and this is to be used by my sub command and the ICommandHandler is still decorated by the transaction. My instance of ICommandHandler then has a dependency on the new interface for it's sub command. This seems to have sorted it, but was checking to see if this is what you meant? This means that every instance of ICommandHandler will use the transaction but the other interface won't.

ghost avatar May 24 '17 12:05 ghost

Seems legit.

dotnetjunkie avatar May 24 '17 13:05 dotnetjunkie