在服务中使用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");
}
}
换句话说,从第二个服务的一个服务方法调用正确吗
提前感谢!
我认为私有变量工作单元是一种更好的方法,因为它更倾向于控制反转,但控制没有注入,对我来说,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注入了服务,如果你愿意的话,有点像一个工作控制器单元。
不管怎样,我的两美分