在服务中使用UnitOfWork的哪种变体更合适

本文关键字:服务 UnitOfWork | 更新日期: 2023-09-27 18:21:20

您好!

我的系统具有N层架构:

  • DAL(数据访问层)(实体框架6,工作单位)
  • 无总线逻辑层
  • PL(表示层)(ASP.NET MVC 4)

问题如下:

UnitOfWork使用哪种变体更合适

第一个变体(特性的使用,在控制器ASP.NET MVC中显式调用Dispose()):

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

换句话说,从第二个服务的一个服务方法调用正确吗

提前感谢!

在服务中使用UnitOfWork的哪种变体更合适

我认为私有变量工作单元是一种更好的方法,因为它更倾向于控制反转,但控制没有注入,对我来说,Using块方法不应该在服务本身中完成。工作单元对象应该被注入,并在其他地方进行控制。IMO工作单元模式的全部意义在于封装事务范围。此事务范围应该能够跨越服务。良好的封装原则指导我们制作原子服务,这些服务是单一聚焦的(SOLID)。即,在您的情况下,与消息有关的一切都应该在消息服务中,这是正确的。但正如您所看到的,由于这一原则,其他服务可能需要发送消息。所以,是的,我认为一个服务调用另一个服务并非没有道理,尤其是在需要执行业务规则的情况下。事实上,多个服务去同一个存储库可能做同样的事情违反了DRY IMO。我还认为,如果出现故障,不发送消息,或者如果消息发送失败,则回滚第一个操作(可能是什么),这将是一种理想的行为。当然,您可以对此进行测试(if..then.type模式),并可能手动编写回滚代码(丑陋

所以您没有将工作单元注入到服务中,所以您的事务范围仅限于创建它的服务。这也增加了测试的难度。所有这些问题都与我现在在另一个项目中所经历的完全相同,该项目遵循相同的代码结构/方法,我将是第一个说,我也还没有找到一个完美的方法,但我会更像这样处理它:

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

这将控制工作单元(作用域)的职责传递给调用者。在您的情况下是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之间放了另一层来控制作用域,Dependency注入了服务,如果你愿意的话,有点像一个工作控制器单元。

不管怎样,我的两美分