2015-10-27 3 views
1

Я использую cqrs и ddd для создания моего приложения.Логика домена в обработчике команд или обработчике событий?

У меня есть объект учета, объект транзакции и объект transactionLine. Транзакция содержит несколько транзакций. Каждая транзакцияLine имеет сумму и указывает на учетную запись.

Если пользователь добавляет транзакционную транзакцию в транзакцию, которая уже имеет транзакционную линию, которая указывает на ту же учетную запись, что и новая транзакционная строка, я хочу просто добавить новую сумму транзакции в существующую, предотвращая транзакцию от две транзакции, которые указывают на одну учетную запись.

Ex:

Before command : 
    transaction 
     transactionLine1(amount=100, account=2) 
     transactionLine2(amount=50, account=1) 

Command : 
    addNewTransaction(amount=25, account=1) 

Desired result : 
    transaction 
     transactionLine1(amount=100, account=2) 
     transactionLine2(amount=75, account=1) // Add amount (50+25) instead of two different transactionLines 

instead of 

transaction 
    transactionLine1(amount=100, account=2) 
    transactionLine2(amount=50, account=1) 
    transactionLine3(amount=25, account=1) // Error, two different transactionLines point to the same account 

Но мне интересно, если это лучше справиться с этим в команде или обработчик событий.

Если этот случай обрабатывается обработчиком команды

Before command : 
    transaction 
     transactionLine1(amount=100, account=2) 
     transactionLine2(amount=50, account=1) 

Command : 
    addNewTransaction(amount=25, account=1) // Detects the case 

Dispatches event 
    transactionLineAmountChanged(transactionLine=2, amount=75) 
  1. команды AddTransactionLine получен

  2. Проверьте, если transactionLine существует в сделке нового transactionLine с той же учетной записью

  3. Если это так, испустите транзакцию событиеAmountChangedEvt

  4. В противном случае, испускает событие transactionAddedEvt

  5. Соответствующий обработчик событий обрабатывает правильное событие

Если этот случай обрабатывается обработчиком события

Before command : 
    transaction 
     transactionLine1(amount=100, account=2) 
     transactionLine2(amount=50, account=1) 

Command : 
    addNewTransaction(amount=25, account=1) 

Dispatches event 
    transactionLineAdded(transactionLine=3, amount=25) 

Handler // Detects the case 
    transactionLine2.amount = 75 
  1. команда AddTransactionLine является полученные

  2. TransactionLineAdded отправляется событие

  3. TransactionLineAdded обрабатывается

  4. Проверьте добавляемого сделки transactionLine указывает на тот же счет, как существующий transactionLine в этом счете

  5. Если это так, просто добавить количество новой транзакцииЛинии к существующей transactionLine

  6. В противном случае, добавьте новую транзакциюНапряжение

ответ

2

Ни команды, ни события не должны содержать логику домена, только домен должен содержать логику домена. В вашем домене агрегированные корни представляют собой границы транзакций (а не транзакции, а транзакции для логики). Обработка логики в командах или событиях обойдет эти границы и сделает вашу систему очень хрупкой.

Правильное место для этой логики является объектом транзакции.

Так что лучше всего было бы

AddTransactionCommand finds the correct transaction entity and calls 
Transaction.AddLine(...), which does the logic and publishes events of what happened 
TransactionLineAddedEvent or TransactionLineChangedEvent depending on what happened. 
0

Think команд и событий, как «контейнеры», «DTOS» данных, которые вы будете нуждаться для того, чтобы увлажнять ваши AggregateRoots или отправить в мир (событие) для других ограниченных контекстов, чтобы их использовать. Вот и все. Любая другая операция, которая строго связана с вашим Доменом, не имеет места, кроме ваших объектов AggregateRoots, Entities и Value.

Вы можете добавить некоторую «проверку» в свои Команды, используя DataAnnotations или свою собственную реализацию метода проверки.

public interface ICommand 
{ 
    void Validate(); 
} 

public class ChangeCustomerName : ICommand 
{ 
    public string Name {get;set;} 

    public void Validate() 
    { 
     if(Name == "No one") 
     { 
      throw new InvalidOperationException("Sorry Aria Stark... we need a name here!"); 
     } 
    } 
}