Тема реализации паттерна Unit Of Work уже поднималась в комментариях к статье «Совершенный код. Разбор выпуска №1». После чего мне пришло множество писем с вопросами по этой теме. Одно из последних писем выношу на отдельное обсуждение.
Вопрос косвенно связан со статьей в твоем блоге «Domain-Driven Design: aggregation root».
В примерах бизнес сценариев ты используешь конструкцию:
using (unitOfWorkFactory.Create()) { var account = new Account("email", "password"); account.AddRole(Role.Admin); accountRepository.Save(account); }В общем с этой конструкцией все ясно, я также изучил набор реализаций UoW для .NET/Java инфраструктур - они все внешне сводятся к одному и тому же. Меня интересует, как реализован конкретно используемый тобой UoW, как с ним работают репозитории, что представляет из себя фабрика.
Я продолжил копаться и нашел то что в принципе полностью удовлетворяет меня на данный момент: http://github.com/riteshrao/ncommon/tree/v1.1/NCommon/src/Data
Внешне из сервиса оно выглядит примерно также как и у тебя в примерах. Внутренне существенное, что разделено UoW и Транзакционность. Unit of Work отвечает только за отслеживание изменений и Flush, когда за транзакцию отвечает отдельная компонента инфраструктуры. Объединяются они с помощью UnitOfWorkScope, что означает UoW + транзакция. Именно он и юзается в бизнес логике. Фабрика UoW скрыта внутри.
Итак, ваши примеры реализации Unit of Work, best practicies, их плюсы и минусы пишите в комментариях или мне на почту.
Как обычно я выложу лучшие советы со ссылкой на авторов и возможно своими дополнениями. Авторы решений, оставляйте, пожалуйста, свои контакты (сайты, блоги), чтобы я мог на вас ссылаться.
Хотелось бы узнать мнения по поводу такой реализации Unit of Work: http://blogs.microsoft.co.il/blogs/gilf/archive/2010/06/21/revisiting-the-repository-and-unit-of-work-patterns-with-entity-framework.aspx
ОтветитьУдалитьсам я скептически отношусь к такой реализации
У меня разрыв мозга, вижу слово "вопрос", но ни самого вопроса, ни знака "?" нет. Явная формулировка отсутствует.
ОтветитьУдалить@Артур
ОтветитьУдалитьВыделил жирным шрифтом.
Look at http://code.google.com/p/taijutsu/source/browse/
ОтветитьУдалить@Wanderer
ОтветитьУдалитьА ты сам какую используешь?
@Nikita Govorov
ОтветитьУдалитьЕсли можно вкраце достоинства этого подхода и недостатки. Используете ли вы его в своих проектах?
@Александр
ОтветитьУдалитьна текущем проекте используем Entity Framework 3.5
Используем что-то типа этого (накидал на скорую руку, возможно что-то не учел, но думаю все предельно просто и понятно):
public interface IUnitOfWork : IDisposable
{
void Save();
}
public class UnitOfWork : IUnitOfWork
{
private readonly TransactionScope _transactionScope;
private readonly ObjectContext _context;
private bool needToAcceptChanges;
protected UnitOfWork(ObjectContext context)
{
_context = context;
_transactionScope = new TransactionScope();
}
public void Save()
{
_context.SaveChanges(SaveOptions.DetectChangesBeforeSave);
_transactionScope.Complete();
needToAcceptChanges = true;
}
public void Dispose()
{
if (needToAcceptChanges)
_context.AcceptAllChanges();
_context.Dispose();
_transactionScope.Dispose();
GC.SuppressFinalize(this);
}
}
Что касается той реализации UOF, к которой я скептически отношусь: мое мнение такое, что не нужно UOF использовать для операций чтения (такая возможность есть в вышеуказанной реализации). Для целей "только для чтения" я использую RepositoryHolder, в котором находятся "лениво"-создающиеся репозитарии. В моей реализации UOF используется только для выполнения операций записи в рамках одной транзакции.
Буду рад любой критики =)
в конструкторе UOF допустил опечатку (нужно public вместо protected)
ОтветитьУдалить@Wanderer
ОтветитьУдалитьТ.е. твоя реализация в данном случае оборачивает ObjectContext из EF.
Тут осталось не раскрыто как репозитории взаимодействуют с UoW?
Было бы полезно увидеть пример использования для сценария сохранения и чтения.
Еще интересно, можешь оценить стоимость перехода на другую ORM с такой реализацией?
На почте уже несколько "ручных" реализаций, т.е. не использующих никакие ORM.
ОтветитьУдалитьЕсть ли у кого-то еще опыт создания/использования такого подхода?
@Александр
ОтветитьУдалитьобязательно отвечу как будет время :)
P.S. Wanderer - это я :)
ОтветитьУдалить@Роман
ОтветитьУдалитьДавай, я на следующей неделе уже свою версию выложу.
А как быть с Lazy-loading в ASP.NET MVC. Например я передаю в модель сущность которая имеет связанные сущности, которые в свою очередь подгружаются по требованию. В вашем примере сессия будет закрыта и ничего не получится.
ОтветитьУдалить@Denis
ОтветитьУдалитьА вы где эти данные подгружать хотите? M? V? C?
V
ОтветитьУдалить@Denis
ОтветитьУдалитьЕсли вам надо подгружать данные во View, значит что-то не так с архитектурой системы.
Последнее место, где можно подгружать данные - это Модель. View предназначена только для отображения подготовленных данных.
Ну для View все так и есть, она не знает о ленивой загрузке работает напрямую с коллекцией связанных объектов, Модель сама как раз и подгружает эти объекты.
ОтветитьУдалить@Denis
ОтветитьУдалитьЯ видимо неправильно сказал. Все данные должны быть готовы для отображения (без каких-либо подгрузок или доп. обработок), когда модель передается во View.