2015-11-10 2 views
1

Добрый день!Какой вариант использования UnitOfWork в обслуживании является более правильным?

Моя система имеет архитектуру N-слой:

  • DAL (Доступ к данным Layer) (Entity Framework 6, Хранилища, UnitOfWork)
  • BLL (Busisness логика Layer)
  • PL (Presentation слой) (ASP.NET MVC 4)

вопрос заключается в следующем:

Какой вариант использования UnitOfWork более подходит?

Первый вариант (использование характерных, в явно вызывать Dispose() в контроллере ASP.NET MVC):

namespace MyApp.BLL.Services 
{ 
    public class MyService 
    { 
    private UnitOfWork _uow { get; set; } 

    public MyService() 
    { 
     _uow = new UnitOfWork(); 
    } 

    public List<SomeDTO> SomeGetMethod() 
    { 
     IEnumerable<Entity> entities = _uow.SomeRepository.Get(x => x.Id==1); 
     ... 
     return ... 
    } 

    public void SomeSetMethod(int value) 
    { 
     _uow.SomeRepository.Insert(new Entity { Value = value }); 

     _uow.Commit(); // SaveChanges(); 
    } 

    public Dispose() 
    { 
     _uow.Dispose(); 
    } 
    } 
} 

Второй вариант (с использованием блока):

namespace MyApp.BLL.Services 
{ 
    public class MyService 
    { 
    public List<SomeDTO> SomeGetMethod() 
    { 
     using(UnitOfWork uow = new UnitOfWork()) 
     { 
     IEnumerable<Entity> entities = uow.SomeRepository.Get(x => x.Id==1); 
     } 
     .... 
     return ... 
    } 

    public void SomeSetMethod(int value) 
    { 
     using(UnitOfWork uow = new UnitOfWork()) 
     { 
     uow.SomeRepository.Insert(new Entity { Value = value }); 

     uow.Commit(); // SaveChanges(); 
     } 
    } 
    } 
} 

И второй вопрос:

Например, у нас есть служба, которая отвечает за работу модуля сообщений в системе - IMessagesService, и у нас также есть вторая услуга, которая является ответчиком для некоторого модуля - ISomeService. В результате создания метода в службе ISomeService необходимо отправить сообщение в систему. Будет ли правильным вызывать метод другого IMessagesService для отправки сообщения?

Пример:

public interface IMessagesService 
{ 
    void Send(int userFrom, int userTo, string message); 
    // other methods... 
} 

public class MessageService 
{ 
    public void Send(int userFrom, int userTo, string message) 
    { 
    // some logic here 
    } 
} 

public interface ISomeService 
{ 
    void SomeMethod(int somevalue); 
} 

public class SomeService: ISomeService 
{ 
    public void SomeMethod(int somevalue) 
    { 
    // some logic here 

    // после необходимо отправить сообщение 
    messageService = new MessageService(); 
    messageService.Send(1, 2, "some text"); 
    } 
} 

В другом слова- это правильно звонить из одного метода службы второй службы?

Заранее благодарен!

ответ

0

Закрытая переменная unitofwork Я думаю, что это лучший подход, поскольку он больше ориентируется на инверсию управления, но элемент управления не вводится, а подход «Блок-блок» ко мне не выполняется в самих сервисах. Объект unitofwork следует вводить и контролировать в другом месте. IMO - весь элемент шаблона unitofwork - инкапсулировать область транзакции. Эта область транзакций должна иметь возможность охватывать сервисы. Хороший принцип инкапсуляции направляет нас на создание атомных служб, которые являются сингулярными (SOLID). т. е. в вашем случае все сообщения, связанные с Сообщениями, должны быть в службе сообщений, и это правильно. Но, как вы видели, из-за этого принципа другим службам может потребоваться отправить сообщение. Так что да, я считаю, что одна услуга не является необоснованной для вызова другой, особенно если есть бизнес-правила, которые необходимо выполнить. Фактически несколько служб, идущих в один и тот же репозиторий, потенциально могут сделать то же самое, нарушают DRY IMO. Я также считаю, что было бы желательно, чтобы сообщение не отправлялось, если произошел сбой, или откат первого действия (каким бы оно ни было), если отправка сообщения не удалась. Разумеется, вы можете проверить это (если ... тогда тип типа) и, возможно, вручную написать код отката (уродливый!), Но обернуть все сервисы, которые вы используете с помощью той же единицы, что и у вас есть откат (и зафиксировать) в любом случае (особенно, если вы используете ORM-карту, то есть Entity Framework), и множество встроенных if-операторов могут быть немного запаха кода IMO.

Таким образом, вы не вводите unitofwork в сервисы, поэтому объем транзакции ограничен только сервисом, в котором он создан. Также затрудняет тестирование. Все эти проблемы - это то же самое, что я сейчас переживаю в другом проекте, который следует той же структуре кода/подходу, и я буду первым, скажем, я еще не нашел идеального подхода, но я бы подошел это что-то больше, как это:

//Base service class to take the unit of work injection 
public abstract class BaseService 
    { 
    private IUnitOfWork _uow { get; private set; } 

    public BaseService(IUnitOfWork scope) 
    { 
     _uow = scope; 
    } 
} 

, а затем сервис реализаций класса

public class SomeService: BaseService, ISomeService 
{ 
    public MyService(IUnitOfWork scope) : base(scope) 
    { 

    } 
    public void SomeMethod(int somevalue) 
    { 

    //Do something in this service 
    //code here..... 

    //then do something in the next service, passing though 
    //the same unitof work 

    messageService = new MessageService(_uow); 
    messageService.Send(1, 2, "some text"); 
    } 
} 

Это проходит контролирования является ответственным за UnitOfWork (масштаб) для вызывающей стороны. В вашем случае слой презентации PL или для удобства тестирования другого тестового класса, если хотите. От PL-то вроде:

//PL Controller that does something cool 
public class BaseService : Controller 
{ 

    public ActionResult DoSomething(int value) 
    { 
     using(IUnitOfWork scope = new UnitOfWork()) 
     { 
      ISomeService theService = new SomeService(scope); 
      theService.SomeMethod(value); 
     } 
     ...con 
    } 

} 

Я на самом деле положить еще один слой между ними PL и BLL для управления областью, и зависимостях впрыснуть услуги, своего рода unitofworkcontroller, если вы будете.

Во всяком случае мои два цента

+0

Почему вы 'новый()' 'вверх UnitOfWork' и' SomeService'? Если мы говорим о DI, то вы вводите их интерфейсы в конструктор 'BaseService'. – kayess

+0

@ OJay Спасибо! Вы сказали: _I фактически накладываю еще один слой между PL и BLL, чтобы контролировать область действия, а Dependancy вводит сервисы, вроде unitofworkcontroller, если вы будете. Можете ли вы показать мне пример этого слоя, пожалуйста? И 'PL' не должен ссылаться на' DAL' (UnitOfWork здесь), не так ли? – WhiteNinja