我的服务和存储层的职责

发布于 2024-10-21 06:51:28 字数 1449 浏览 8 评论 0原文

有一天我问了这个问题:

存储库层是否应该返回数据-transfer-objects (DTO)?

答案(好吧,只有一个人,但我已经有预感这不是一个好主意)是不,存储库稍后不应该处理DTO 对象(它们的目的纯粹是通过线路发送),服务层应该处理它。

现在我已经提出了一个结构,需要你的意见。这个想法是,当这样做有意义时,存储库层可以返回我定义的名为 IProjectable 的接口类型。这包装了查询(存储库层尚未执行查询),但不允许使用者更改查询(它不是 IQueryable),只是对其执行投影操作(到目前为止对我来说)只有 FirstToPagedList)将执行投影并实际执行查询。

所以在存储库中是这样的:

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;

我是否正确地说,在这里进行实际的数据访问仍然是存储库层的责任(应该如此),并且投影到可序列化的层form 是服务层的责任(理应如此)?

我认为有效地执行此操作的唯一其他方法(从存储库返回 User 并对其 Orders 执行 Count()服务层中的 会导致对数据库的额外查询)是定义一个具有所有这些属性的类型并从存储库层返回它,只是不要将其称为“Dto”,这看起来很愚蠢它与 DTO 相同,只是为了“纯粹”而没有命名相同。这样一来,我似乎就可以鱼与熊掌兼得了。

我看到的缺点是,在服务层执行实际上无法转换为 SQL 的投影(它不应该)不必担心的情况下,或者在执行如此复杂的投影的情况下,您可能会遇到不匹配的情况这使得人们怀疑哪一层正在执行实际的数据访问。

顺便说一句,如果重要的话,我正在使用 Entity Framework 4。

The other day I asked this question:

Should the repository layer return data-transfer-objects (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.

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. 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.

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". 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.

I'm using Entity Framework 4 by the way, if it matters.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

意中人 2024-10-28 06:51:28

我说的正确吗?
这里实际的数据访问仍然是
存储库层的职责
(应该如此)并且
投影到可序列化的形式是
服务的责任
层(应该是这样)?

是的,服务层仍然不知道实际的数据访问是如何执行的(因为它不应该不知道)。调用是否发送到 SQL?中间有缓存层吗?

我看到的缺点是你可以获得
服务层不匹配
执行无法执行的投影
实际上被翻译成 SQL
不应该担心,或者
它在哪里执行如此复杂的操作
令人质疑的预测
哪一层正在处理实际数据
访问。

对于这个问题,我使用管道模式,它基本上只是 IProjectable 上的一组扩展方法,可以执行经过测试的投影。接下来,在 serviceLayer 中,您可以使用这些管道方法的组合来编写查询,例如:

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

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). Are the calls send to 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.

For this problem i use a pipeline pattern which basicly is just a set of extension methods over IProjectable which can perform tested projections. Next, in your serviceLayer you can just write your query using a composition of these pipeline methods, for example:

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

耳钉梦 2024-10-28 06:51:28

我最尊敬的一位开发人员 ayende (http://ayende.com/Blog/Default.aspx) 说:“ORM 是你的存储库”视频在这里 -> http ://community.devexpress.com/blogs/seth/archive/2011/03/09/interview-with-ayende-rahien-aka-oren-eini.aspx

问题是你真的需要存储库模式吗?
只是我的意见:)

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

Question is do you really need Repository pattern?
Just my opinion :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文