Я использую NHibernate, DI / IoC и шаблон единиц работы.
Большинство примеров UoW, которые я видел, удостоверяются, что может быть только один активный UoW / сеанс одновременно, например этот и этот .
К сожалению, я пока не совсем понимаю, как мне обращаться с двумя службами, обе из которых используют UoW, но одна вызывает другую.
Возьмите этот пример:
Регистратор, использующий UoW:
public class LoggerService : ILoggerService
{
private ILoggerRepository repo;
public LoggerService(ILoggerRepository Repo)
{
this.repo = Repo;
}
public void WriteLog(string message)
{
using (UnitOfWork.Start())
{
// write log
}
}
}
... и другая служба, которая также использует UoW И вызывает регистратор:
public class PlaceOrderService : IPlaceOrderService
{
private IOrderRepository repo;
private ILoggerService service;
public PlaceOrderService(IOrderRepository Repo, ILoggerService Service)
{
this.repo = Repo;
this.service = Service;
}
public int PlaceOrder(int orderNumber)
{
using (UnitOfWork.Start())
{
// do stuff
this.service.WriteLog("Order placed!"); // will throw exception!!
// do more stuff
}
}
}
Если моя реализация UoW удостоверится, что одновременно существует только одна активная UoW (и выдает исключение, если вы попытаетесь запустить другую, как в обоих связанных примерах), мой код вылетит в строке this.service.WriteLog
в методе PlaceOrder:
Уже будет активный UoW, созданный методом PlaceOrder, и метод WriteLog попытается открыть второй, поэтому реализация UoW выдает исключение из-за этого.
Итак, что я могу с этим поделать?
Я выдвинул две идеи, но обе они выглядят как-то «хакерскими» для меня.
Не запускайте новое UoW в LoggerService, вместо этого предполагайте, что в вызывающем коде уже есть активный.
Вот чем я сейчас занимаюсь. Я просто удалил материал using (UnitOfWork.Start())
из LoggerService и убедился, что вы не можете напрямую вызывать LoggerService, только из других служб.
Это означает, что приведенный выше код будет работать, но LoggerService будет аварийно завершать работу, если вызывающий код не запускает UoW, потому что LoggerService предполагает, что он уже существует.
Оставьте пример кода как есть, но измените реализацию UoW.Start () следующим образом:
а) если нет активного UoW, начните новый
б) если уже является активным UoW, верните это
Это позволило бы мне вызывать LoggerService напрямую И из других служб, независимо от того, есть ли уже UoW или нет.
Но я никогда не видел ничего подобного в сети.
(И в этом примере есть только две службы. Это может стать намного сложнее, просто подумайте о классе PlaceSpecialOrderService
, который делает некоторые специальные вещи, а затем вызывает PlaceOrderService.PlaceOrder()
...)
Есть советы?
Заранее спасибо!
EDIT:
Спасибо за ответы.
Хорошо, возможно, регистрация не была лучшим примером.
Я понимаю вашу точку зрения относительно использования отдельного сеанса для регистрации, и я посмотрю и попробую.
В любом случае, мне все еще нужно найти способ заставить вложенные вызовы службы работать.
Вообразите какой-нибудь другой пример вместо регистрации, такой как пример PlaceSpecialOrderService, который я упоминал выше.
Ответчикам, предлагающим запустить UoW где-то в инфраструктуре, а не непосредственно в службах:
С одной стороны, это тоже имеет смысл, но с другой стороны это, очевидно, означало бы, что я не могу выполнить две разные транзакции в одном вызове службы.
Мне придется подумать об этом, потому что я совершенно уверен, что мне это где-то понадобится (например: сохранить заказ в одной транзакции, затем сделать больше вещей во второй транзакции, и даже если это не удастся, заказ не не откатывайся).
Вы делали это так (по одному UoW на сервисный вызов) в своих приложениях?
Разве вам не нужна была возможность запустить второй UoW в том же сервисном звонке?