Как правильно использовать Unit of Work/Repositories на бизнес-уровне?
Создав небольшое приложение с использованием шаблона Unit of Work/Repository, я изо всех сил пытаюсь понять, как правильно использовать это на своем бизнес-уровне. У моего приложения есть уровень доступа к данным, который может быть либо NHibernate, либо Entity Framework. Я могу легко переключаться между ними.
У меня есть несколько репозиториев, например, Клиент, Заказ и т. Д. Моей единицей работы будет либо ISession, либо Object Context, в зависимости от того, с каким DAL я хочу протестировать.
Мой бизнес-уровень содержит единственный бизнес-метод - CreateOrder(). Что я пытаюсь понять, так это то, где на бизнес-уровне я должен инициализировать свою единицу работы и свои репозитории.
Сосредоточив внимание на Nhibernate, мой DAL выглядит так:
public class NHibernateDAL : IUnitOfWork
{
log4net.ILog log = log4net.LogManager.GetLogger(typeof(NHibernateDAL));
ISession context;
public NHibernateDAL()
{
context = SessionProvider.OpenSession();
this.Context.BeginTransaction();
CurrentSessionContext.Bind(context);
}
public ISession Context
{
get { return context; }
}
public void Commit()
{
this.Context.Transaction.Commit();
context.Close();
}
public void Dispose()
{
ISession session = CurrentSessionContext.Unbind(SessionProvider.SessionFactory);
session.Close();
}
}
На своем бизнес-уровне я хочу знать, где я должен декларировать свою единицу работы и репозитории. Они объявлены на уровне класса или в методе CreateOrder?
Например:
public class BusinessLogic
{
UnitOfWork _unitOfWork = new UnitOfWork(NHibernateDAL);
NhRepository<Order> _orderRepository = new NhRepository<Order>(_unitOfWork);
NhRepository<Customer> _customerRepository = new NhRepository<Customer>(_unitOfWork);
....
public void CreateOrder(.....)
{
Order order = new Order();
_orderRepository.Add(order);
_unitOfWork.Commit();
}
}
Приведенный выше код работает только в первый раз, когда вызывается метод CreateOrder (), но не для последующих вызовов, поскольку сеанс закрыт. Я попытался удалить вызов context.Close() после совершения транзакции, но это также не удалось. Хотя вышеуказанный подход не работает, мне кажется более правильным объявить мои репозитории и единицы работы с этой областью.
Тем не менее, если я реализую его, как показано ниже, он работает нормально, но кажется неестественным объявлять репозитории и единицы работы в рамках самого метода. Если бы у меня была масса бизнес-методов, я бы везде объявлял репозитории и единицы работы:
public class BusinessLogic
{
public void CreateOrder(.....)
{
UnitOfWork _unitOfWork = new UnitOfWork(NHibernateDAL);
var _orderRepository = new NhRepository<Order>(_unitOfWork);
NhRepository<Customer> _customerRepository = null;
Order order = new Order();
_orderRepository.Add(order);
_unitOfWork.Commit();
}
}
Если бы я реализовал это с помощью объявления уровня класса, то я думаю, что мне потребуются некоторые средства для повторного открытия той же единицы работы в начале метода CreateOrder.
Как правильно использовать единицу работы и репозитории на бизнес-уровне?
2 ответа
Похоже, ты почти понял. В нашем новом стеке серверов у меня есть эта настройка:
WCF Service Layer --> just returns results from my Business Layer
My business layer is called, creates a unitofwork, creates the respository
Calls the respository function
Uses AutoMapper to move returned results into a DTO
My repository gets the query results and populates a composite object.
Похоже, что у вас там. Хотя мы используем Unity для определения того, что вы называете бизнес-уровнем. (мы просто называем это нашим функциональным процессором)
Однако я настоятельно рекомендую, чтобы вы НЕ держали UnitOfWork на уровне класса. Ведь каждая дескриптивная функция - это единица работы. Итак, мое так (имена были изменены, чтобы защитить невинных):
using ( UnitOfWorkScope scope = new UnitOfWorkScope( TransactionMode.Default ) )
{
ProcessRepository repository = new ProcessRepository( );
CompositionResultSet result = repository.Get( key );
scope.Commit( );
MapData( );
return AutoMapper.Mapper.Map<ProcessSetDTO>( result );
}
У нас также было долгое обсуждение того, когда делать область действия. Коммит и хотя он не нужен для запросов, он устанавливает согласованный шаблон для каждой функции на уровне приложения. Кстати, мы используем NCommon для наших шаблонов репозитория /unitofwork и не должны передавать UoW в репозиторий.
Ваша реализация IUnitOfWork содержит все репозитории.
Ваш IUnitOfWork внедряется в ваш уровень представления, такой как контроллер mvc.
Ваш IUnitOfWork внедряется в контроллер MVC.
Ваш IRepository внедряется в вашу реализацию UnitOfWork.