Как правильно использовать 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.

Другие вопросы по тегам