我的服务和仓库层的职责

3
前几天我问了这个问题:仓储层应该返回数据传输对象(DTO)吗? 答案是不应该,仓储层不应该处理DTO对象(它们的目的纯粹是为了在网络上传输),而服务层应该处理。
现在我想到了一个构造方法,需要您的意见。我的想法是,在有意义的情况下,仓储层可以返回我定义的接口类型IProjectable。它包装了查询(仓储层尚未执行查询),但不允许消费者更改查询(它不是IQueryable),只能对其执行投影操作(目前只有First和ToPagedList),执行投影并实际执行查询。
所以仓储层可能会像这样返回:
public IProjectable<User> GetUser(int id)
{
  var query = from u in Set<User>()
              where u.UserID == id
              select u;

  return query.AsProjectable();
}

在服务层中,类似这样:

var dto = repository.GetUser(16).Single(u => new SimpleUserDto
{
  FullName = u.FirstName + " " + u.LastName,
  DisplayAddress = u.Address.Street + u.Address.HouseNumber,
  OrderCount = u.Orders.Count()
});

return dto;

我说的正确吗?在此处执行实际数据访问仍然是存储库层的责任(应该是这样的),将其投影为可序列化形式是服务层的责任(也应该是这样的)?我唯一能想到的其他有效方法是定义一个具有所有这些属性的类型并从存储库层返回它,只是不要称其为“Dto”,因为它与DTO相同,只是为了“纯洁性”而不命名。这样看来,我大致上可以兼顾两方面。缺点是你可能会得到不匹配的结果,其中服务层执行不能实际转换为SQL的投影,这是它不必担心的,或者执行如此复杂的投影,使得实际执行数据访问的层变得成问题。顺便说一下,我正在使用Entity Framework 4。
2个回答

0
我这样说是否正确:实际的数据访问仍然是存储库层的责任(应该是这样的),而将其投影到可序列化形式的工作则由服务层负责(也应该是这样的)?
是的,没错。服务层仍然不知道实际的 DataAccess 是如何执行的(也不应该知道)。调用是否发送到 SQL?中间是否有缓存层?
我所看到的缺点是,服务层执行的投影可能与无法转换为 SQL 的实际情况不符,对此它不应该担心,或者执行了如此复杂的投影,以至于难以确定哪一层正在执行实际的数据访问。
针对这个问题,我使用了 Pipeline 模式,它基本上只是在 IProjectable 上执行一组已测试过的投影扩展方法。接下来,在你的 ServiceLayer 中,你可以使用这些管道方法的组合编写查询,例如:
var users = repository.GetUsers().FilterByName("Polity").OrderByAge().ToTransferObjects();

0

即使使用ORM框架,仓储模式仍然非常有用。例如,我在使用LinqToSql时绝对需要仓储模式。这是因为我有一个“真正的”仓储实现,它实际上使用数据库,还有一个虚假的仓储只用于单元测试。虽然可以使用模拟替代工作,但对于大量的测试来说,这太繁琐了(目前我有大约900个测试,其中大多数有几个不同的断言)。 - Adrian Grigore
@Adrian Grigore - 很好的观点,就像所有模式一样,不要自动使用它们。你知道为什么使用存储库,而许多人不知道。那是我的观点。 - Darius Kucinskas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接