在分层架构中,面向对象的查询应该放在哪里?
假设:
- 您有一个包含表示层、业务层和数据层的架构。
- 您正在应用领域驱动设计。
- 您正在使用一个对象关系映射器,它允许您创建面向对象的查询(例如,NHibernate,它允许您创建 HQL 查询)。
问题:
面向对象的查询应该放在哪一层?
我的想法:
我认为将它们放入表示层通常是没有意义的。但不知道是放到业务层还是数据层。
示例(NHibernate):
假设您的业务逻辑需要某种方法 GetCustomersPossicallyInterestedIn(Product p)。然后,您可以创建一个复杂的 HQL 查询来选择客户对象,其中客户已经购买了与 p 属于同一类别的产品。
论点 a)
一方面,我想说这个查询显然是业务逻辑,因为根据客户是否购买了同一类别的产品来判断她是否可能对产品感兴趣,这是一个业务决策。不妨选择购买过同一品类、价格相近的多种产品的客户,例如
论点 b)
另一方面,业务层不应该依赖于数据层,因此在业务层直接使用 NHibernate 会产生一些问题。警钟。
可能的解决方案 1)
创建您自己的面向对象查询语言,在业务层中使用该语言,并在数据层中转换为 HQL。 我认为这会造成很大的开销。如果您使用基于查询对象的查询语言而不是解析的查询语言,您可能会付出一些努力,但我的反对意见仍然适用。
可能的解决方案2)
在业务层直接使用NHibernate是可以的,因为NHibernate能够提供的HQL、ISession等抽象级别适合业务层。无需包裹它。
你怎么认为?
编辑:
请参阅“存储库是新的单例” 和 “在 DAL 中封装数据访问的错误神话”,作者:Ayende Rahien,用于密切相关的讨论。
Given:
- You have an architecture with the layers presentation, business and data.
- You are applying domain-driven design.
- You are using an object-relational mapper that lets you create object-oriented queries (e.g., NHibernate which lets you create HQL queries).
Question:
Into which layer should you put the object-oriented queries?
My thoughts:
I think putting them into the presentation layer will usually make no sense. But I don't know whether to put them into business or data layer.
Example (NHibernate):
Say your business logic needs some method GetCustomersPossiblyInterestedIn(Product p). You might then create a complex HQL query that selects customer objects where the customer has already bought a product that is in the same category as p.
Argument a)
On the one hand, I'd say this query is clearly business logic, because the decision that a customer is treated as possibly interested in a product based on whether she has bought a product in the same category is a business decision. You might as well select customers who have bought multiple products in the same category with a similar price, e.g.
Argument b)
On the other hand, the business layer should not depend upon the data layer, so directly using NHibernate in the business layer rings an alarm bell.
Possible solution 1)
Create your own object-oriented query language that you use in the business layer and translate to HQL in the data layer.
I think this would cause a lot of overhead. If you use a query language based on query objects instead of a parsed query language, you could probably safe some effort, but my objection still applies.
Possible solution 2)
Directly using NHibernate in the business layer is O.K., because the abstraction level that NHibernate is able to provide with HQL, ISession etc. fits the business layer. There is no need to wrap it.
What do you think?
Edits:
See "Repository is the new Singleton" and "The false myth of encapsulating data access in the DAL" by Ayende Rahien for closely related discussions.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
当然,避免将面向对象的查询放入表示层。它应该只显示/使用从业务逻辑层(BLL)接收的数据。没有任何询问。如果您需要查询从 BLL 收到的结果,那么您的 BLL 需要扩展以提供不需要查询的数据。
您使用“面向对象的查询语言”的想法似乎很好。通常,这种“语言”就是您的 DAL :) 我想说“面向对象查询语言”的一个很好的例子是正确实现的数据访问层 (DAL)。
从我的角度来看,您 DAL 应该实现 80- 90% 的功能并提供一组函数,例如:
这些函数提供了不需要查询的大部分功能
。所有其他 10-20% 很少使用的查询(您将它们命名为“面向对象”)您的 DAL 应该实现返回 IQueryable 结果的一个或多个方法,我会说至少是“GetAll()”方法,可能还需要一些自定义:
在这种情况下,如果您需要查找今年在您的 BLL 上注册的国家/地区的客户,您将调用:
接口。
猜猜,您知道如何使用 Linq 在 NHibernate 下:Linq to NHibernate。
另一项提示:我建议您使用“存储库”模式来实现 DAL。前段时间我用这个作为一般想法: http://habrahabr.ru/blogs/net/52173 / (如果您无法使用谷歌阅读俄语翻译整个页面 - 它应该是可读的)。
希望有帮助。
Definitely, avoid putting object-oriented queries into presentation layer. It should ONLY display/use data received from business logic layer (BLL). Without any querying. If you need to query results received from you BLL, then your BLL needs to be extended to provided such data that don't need to be queried.
Your idea to use 'object oriented query language' seams like a good. Usually, this "language' is your DAL :) I would say good example of "object oriented query language" is a properly implemented Data Access Layer (DAL).
From my perspective you DAL should implement 80-90% of all functionality and provide set of functions like that:
These functions provide the biggest part of required functionality that don't need to be queried.
For all other 10-20% of rarely used queries (you named them "object oriented") your DAL should implement method/methods that return IQueryable result, I would say at least 'GetAll()' method and probably few customizations:
in this case if you will need to find a customer in a country registered this year on you BLL you will call:
Guess, you know what provide IQueryable<> interface.
How to work with Linq under NHibernate: Linq to NHibernate.
One additional hint: I would recommend to use 'Repository' pattern for you DAL implementation. Some time ago i used this for general idea: http://habrahabr.ru/blogs/net/52173/ (if you can't read Russian translate whole page with google - it should be readable).
Hope that helps.
我更喜欢使用某种存储库来包装 NHibernate(或其他 ORM)。例如。对于 NHibernate,存储库将包装 NHibernate 会话。该存储库可以是每个类(例如 CustomerRepository 和 OrderRepository),或者如果您的域中没有太多类,您也可以从单个存储库开始。
这是放置 Criteria 查询(LoadAllByName、LoadCustomerWithOrder 等)的完美位置。如果您稍后需要切换到不同的 ORM 甚至不同的持久性机制(我认为非常罕见),您可以交换整个数据层,包括存储库。
I prefer to wrap NHibernate (or other ORM) using some sort of a Repository. For eg. in the case of NHibernate the Repository would wrap the NHibernate session. This repository could be per class (So CustomerRepository and OrderRepository) or if you don't have too many classes in your domain, you could start with a single Repository as well.
This is then the perfect place to put Criteria queries (LoadAllByName, LoadCustomerWithOrder, etc.). If you later need to switch to a different ORM or even a different persistence mechanism (very rare, I would think), you can swap out the whole Data layer including the Repository.
查询属于存储库。您可以在任何需要的地方拥有 GetCustomersPossibilityInterestedIn(Product p) 的函数签名,但查询本身应该只位于存储库类中
Queries belong in the repository. You may have a function signature for GetCustomersPossiblyInterestedIn(Product p) anywhere it is necessary, but the query itself should only be in a repository class