Как правильно использовать Unit of Work / Repositories на бизнес-уровне? - PullRequest
6 голосов
/ 07 апреля 2011

Создав небольшое приложение с использованием шаблона 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 ]

1 голос
/ 30 июня 2012

Похоже, ты почти понял.В нашем новом стеке серверов у меня есть такая настройка:

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 );
        }

Мы также долго обсуждали, когда нужно делать scope.Commit и, хотя это не нужно для запросов,он устанавливает согласованный шаблон для каждой функции на уровне приложения.Кстати, мы используем NCommon для наших шаблонов хранилища / unitofwork и не должны передавать UoW в хранилище.

0 голосов
/ 10 марта 2013

Ваша реализация IUnitOfWork содержит все репозитории.

Ваш IUnitOfWork внедряется в ваш уровень представления, такой как контроллер mvc.

Ваш IUnitOfWork внедряется в контроллер MVC.

Ваш IRepository внедрен в вашу реализацию UnitOfWork.

...