2

鉴于:

  • 你有一个包含表示层、业务层和数据层的架构。
  • 您正在应用领域驱动设计。
  • 您正在使用一个对象关系映射器,它可以让您创建面向对象的查询(例如,NHibernate,它可以让您创建 HQL 查询)。

问题:

您应该将面向对象的查询放在哪一层?

我的想法:

我认为将它们放入表示层通常是没有意义的。但我不知道是否将它们放入业务层或数据层。

示例(NHibernate):

假设您的业务逻辑需要一些方法 GetCustomersPossiblyInterestedIn(Product p)。然后,您可以创建一个复杂的 HQL 查询,该查询选择客户已经购买了与 p 属于同一类别的产品的客户对象。

论点 a)

一方面,我会说这个查询显然是业务逻辑,因为根据客户是否购买了同一类别的产品而将其视为可能对产品感兴趣的决定是一个业务决策。您不妨选择在同一类别中以相似价格购买过多个产品的客户,例如

论点 b)

另一方面,业务层不应该依赖于数据层,所以直接在业务层使用NHibernate敲响了警钟。

可能的解决方案 1)

创建您自己在业务层中使用的面向对象的查询语言,并在数据层中转换为 HQL。我认为这会导致很多开销。如果您使用基于查询对象的查询语言而不是解析的查询语言,您可能会付出一些努力,但我的反对意见仍然适用。

可能的解决方案2)

在业务层直接使用NHibernate 是可以的,因为NHibernate 能够提供HQL、ISession 等的抽象级别适合业务层。没有必要包装它。

你怎么看?

编辑:

有关密切相关的讨论,请参阅Ayende Rahien 的“Repository is the new Singleton”“在 DAL 中封装数据访问的错误神话” 。

4

3 回答 3

1

当然,避免将面向对象的查询放入表示层。它应该只显示/使用从业务逻辑层 (BLL) 接收到的数据。没有任何询问。如果您需要查询从您的 BLL 收到的结果,那么您的 BLL 需要扩展以提供不需要查询的此类数据。

您使用“面向对象的查询语言”的想法很好。通常,这种“语言”是您的 DAL :) 我想说“面向对象查询语言”的好例子是正确实现的数据访问层 (DAL)。

从我的角度来看,你的DAL应该实现 80-90% 的所有功能并提供如下功能集:

  • 客户 GetCustomerById(int customerId);
  • List GetLastRegisteredCustomers(int count);
  • ETC...

这些函数提供了大部分不需要查询的所需功能。

对于所有其他 10-20% 的很少使用的查询(您将它们命名为“面向对象”),您的 DAL 应该实现返回 IQueryable 结果的方法/方法,我会说至少是 'GetAll()' 方法和可能很少的自定义:

  • IQueryable GetAll();
  • IQueryable GetCustomerByCountry(int countryId);

在这种情况下,如果您需要在今年注册 BLL 的国家/地区寻找客户,您将致电:

List<Customer> customers = GetCustomerRepository()
    .GetCustomerByCountry(countryId)
    .Where(customer=>customer.RegisterDate.Year==year)
    .ToList<Customer>()
    ;

猜猜,你知道什么提供了 IQueryable<> 接口。

如何在 NHibernate 下使用 Linq:Linq to NHibernate

另一个提示:我建议您使用“存储库”模式来实现 DAL。前段时间我用这个作为一般的想法:http ://habrahabr.ru/blogs/net/52173/ (如果你不能用谷歌阅读俄语翻译整个页面 - 它应该是可读的)。

希望有帮助。

于 2010-09-23T14:30:49.847 回答
0

我更喜欢使用某种存储库来包装 NHibernate(或其他 ORM)。例如。在 NHibernate 的情况下,存储库将包装 NHibernate 会话。这个存储库可以是每个类(因此 CustomerRepository 和 OrderRepository),或者如果您的域中没有太多类,您也可以从单个存储库开始。

这是放置 Criteria 查询(LoadAllByName、LoadCustomerWithOrder 等)的理想场所。如果您以后需要切换到不同的 ORM 甚至是不同的持久性机制(我认为非常罕见),您可以换掉整个数据层,包括存储库。

于 2010-09-23T14:20:44.520 回答
0

查询属于存储库。您可能在任何需要的地方都有 GetCustomersPossiblyInterestedIn(Product p) 的函数签名,但查询本身应该只在存储库类中

于 2010-09-23T14:23:26.760 回答