Должны ли события предметной области вызываться внутри или вне транзакции?

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

Например,

Когда Orderline добавляется к объекту Order, возникает событие домена OrderLineAdded, одно событие домена изменяет состояние модели домена (поэтому должно выполняться в той же транзакции), а затем, когда транзакция завершена, пользовательский интерфейс должен быть обновлен.

Как бы вы подошли к этой проблеме?

  1. Поднимите два события, одно внутри транзакции и одно вне транзакции.
  2. Поднять событие внутри транзакции, но использовать обработчик событий для отправки асинхронного запроса на обновление пользовательского интерфейса?

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

Может быть, есть лучший подход?


person Andronicus    schedule 14.01.2011    source источник


Ответы (2)


У меня была похожая проблема. Модель домена заключалась в публикации событий (с использованием техники, описанной Уди Даханом здесь). Затем я понял, что мои обработчики, связанные с пользовательским интерфейсом, вызываются, даже если что-то идет не так, и транзакция откатывается позже.

Чтобы исправить это, я ввел в систему еще одну роль, другой вид обработчика событий. У меня есть ITransactionalEventHadneler и INonTransactionalEventHandler. Первые вызывались синхронно сразу в методе DomainEvents.Publish(). Последние были поставлены в очередь для вызова, как только транзакция будет зафиксирована (с использованием перехватчиков System.Transactions). Решение работало нормально и было вполне читабельным и ремонтопригодным.

person Szymon Pobiega    schedule 17.01.2011
comment
Это звучит как хорошее решение, но как вы называете свои события, чтобы отличать транзакционные события от нетранзакционных? - person Andronicus; 19.01.2011
comment
Я полагался только на реализованный интерфейс. Не было никакого соглашения об именах. - person Szymon Pobiega; 19.01.2011
comment
@Szymon: это было давно, но под крючками вы подразумеваете TransactionCompleted в классе .NET Transaction? У вас есть пример? - person dstj; 15.11.2012
comment
Вы перевернули названия тезисов? - person Sean; 15.04.2014

Я думаю, что оба подхода могут быть хороши, просто придерживайтесь одного и того же подхода в каждой части вашего кода:

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

Мне лично больше нравится вариант 2, потому что он сохраняет код домена чище, а с помощью асинхронной связи ядро ​​и другие модули будут развязаны, поэтому проблемы во внешних модулях не будут мешать работе ядра. С другой стороны, могут быть обстоятельства, при которых вариант 1 более выгоден.

person Miklos Csuka    schedule 16.01.2011