简体   繁体   English

我的服务和存储库层的职责

[英]The responsibilities of my service and repository layer

The other day I asked this question: 前几天我问了这个问题:

Should the repository layer return data-transfer-objects (DTO)? 存储库层是否应该返回数据传输对象(DTO)?

The answer (well by just one person, but I already had a hunch that it wasn't a good idea) was that no, the repository later should not have to deal with the DTO objects (their purpose is purely to be sent over the wire) and the service layer should deal with that. 答案(只有一个人,但我已经预感到这不是一个好主意)是不,存储库以后不应该处理DTO对象(他们的目的纯粹是通过()和服务层应该处理。

Now I've come up with a construction in the meantime that I need your opinion on. 现在我想出了一个建筑,同时我需要你的意见。 The idea is that, when it makes sense to do so, the repository layer can return an interface type I've defined called IProjectable . 这个想法是,当这样做时,存储库层可以返回我定义的名为IProjectable的接口类型。 This wraps the query (the repository layer does not execute the query yet) but does not allow the consumer to change the query (it's not IQueryable ), just to perform projection operations on it (so far for me only First and ToPagedList ) that would perform the projection and actually execute the query. 这包装了查询(存储库层还没有执行查询)但是不允许使用者更改查询(它不是IQueryable ),只是为了对它执行投影操作(到目前为止我只有FirstToPagedList )执行投影并实际执行查询。

So something like this in the repository: 在存储库中是这样的:

public IProjectable<User> GetUser(int id)
{
  var query = from u in Set<User>()
              where u.UserID == id
              select u;

  return query.AsProjectable();
}

And in the service layer something like this: 在服务层这样的事情:

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;

Am I correct in saying that doing the actual data access here is still the responsibility of the repository layer (as it should be) and that the projection to a serializable form is the responsibility of the service layer (as it should be)? 我是否正确地说,在这里进行实际数据访问仍然是存储库层的责任(应该是这样),并且对可序列化表单的投影是服务层的责任(应该是这样)?

The only other way I see to do this efficiently (returning a User from the repository and doing the Count() on his Orders in the service layer would result in an extra query to the database) is to define a type that has all these properties and return it from the repository layer and just don't call it "Dto", which seems silly as it would be identical to the DTO just not named the same for the sake of "purity". 我认为有效地执行此操作的另一种方法(从存储库返回User并在服务层中对其Orders执行Count()将导致对数据库的额外查询)是定义具有所有这些属性的类型并从存储库层返回它,并且不要将其称为“Dto”,这看起来很愚蠢,因为它与DTO相同,只是为了“纯度”而没有命名相同。 This way, it seems, I can have my cake and eat it for the most part too. 这样看来,我可以吃蛋糕,大部分也吃。

The downside I see is that you can get a mismatch where the service layer performs projections that can't actually be translated to SQL which it shouldn't have to worry about, or where it performs such complex projections that makes it questionable what layer is doing the actual data access. 我看到的缺点是,你可以得到一个不匹配的地方,服务层执行无法实际转换为SQL的投影,它不应该担心,或者它执行如此复杂的投影,使得哪个层有问题做实际的数据访问。

I'm using Entity Framework 4 by the way, if it matters. 如果重要的话,我正在使用实体框架4。

Am I correct in saying that doing the actual data access here is still the responsibility of the repository layer (as it should be) and that the projection to a serializable form is the responsibility of the service layer (as it should be)? 我是否正确地说,在这里进行实际数据访问仍然是存储库层的责任(应该是这样),并且对可序列化表单的投影是服务层的责任(应该是这样)?

Yes you are, the service layer still has no idea how the actual DataAccess is being performed (as it should not have not). 是的,服务层仍然不知道如何执行实际的DataAccess(因为它不应该没有)。 Are the calls send to SQL? 调用是否发送给SQL? is there a caching layer in between? 中间是否有缓存层?

The downside I see is that you can get a mismatch where the service layer performs projections that can't actually be translated to SQL which it shouldn't have to worry about, or where it performs such complex projections that makes it questionable what layer is doing the actual data access. 我看到的缺点是你可以得到一个不匹配的地方,服务层执行的投影实际上无法转换为SQL,它不应该担心,或者它执行这样复杂的投影,使得哪个层有问题做实际的数据访问。

For this problem i use a pipeline pattern which basicly is just a set of extension methods over IProjectable which can perform tested projections. 对于这个问题,我使用一个管道模式,它基本上只是一组IProjectable上的扩展方法,可以执行测试投影。 Next, in your serviceLayer you can just write your query using a composition of these pipeline methods, for example: 接下来,在serviceLayer中,您可以使用这些管道方法的组合编写查询,例如:

var users = repository.GetUsers().FilterByName("Polity").OrderByAge().ToTransferObjects(); var users = repository.GetUsers()。FilterByName(“Polity”)。OrderByAge()。ToTransferObjects();

One of developers I most respect ayende (http://ayende.com/Blog/Default.aspx) said: "ORM is your repository" video here -> http://community.devexpress.com/blogs/seth/archive/2011/03/09/interview-with-ayende-rahien-aka-oren-eini.aspx 其中一位开发人员,我最尊重ayende(http://ayende.com/Blog/Default.aspx)说:“ORM是你的存储库”视频在这里 - > http://community.devexpress.com/blogs/seth/archive/ 2011/03/09 /采访与- ayende-rahien-AKA -奥伦- eini.aspx

Question is do you really need Repository pattern? 问题是你真的需要Repository模式吗? Just my opinion :) 只是我的观点 :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM