【发布时间】:2010-11-07 10:12:33
【问题描述】:
这更像是一个设计而不是实现问题,而且它会很长,所以请耐心等待。最好用一个例子来解释:
假设我有一个名为 Product 的业务实体,它具有一堆属性(name、price、vendor 等...)。
它由一个接口(Product)和实现(ProductImpl,映射到Hibernate)以及基本的CRUD服务接口(ProductService)和实现来表示(ProductServiceImpl)。
Product 和 ProductService 作为 API 公开,它们的实现不是。
我想向 ProductService 添加一个 List findProducts(QueryCriteria criteria) 方法,该方法将返回满足给定条件的产品列表。 要求是:
- 通过直接产品属性查询(例如
product.price gt 50.0) - 按关联查询(例如
product.vendor.name = "Oracle") - 对结果进行排序(例如
order by product.vendor.name desc, product.price asc") - 应用其他过滤器。与以上 3 项均由 API 客户端指定的项目不同,服务可能会根据客户端的身份应用额外的过滤器(例如,调用此方法的客户端可能仅限于查看给定供应商生产的产品)。此类过滤器优先于客户端指定的任何条件(例如,如果过滤器设置为
product.vendor.name = "Microsoft",则上面(2)中的查询应该产生空结果集。
因此,问题是,这种方法使用的 QueryCriteria 接口应该是什么样的?我能想到 3 种解决方案,但我不喜欢其中任何一种:
- 允许客户端直接指定 HQL(以“where”子句开头)。 这是最直接的解决方案,但在安全方面也是最有问题的。即使假设过滤器(上面的#4)足够简单,可以通过 Hibernate 的会话过滤器实现,HQL 仍然需要被解析为 - 至少 - 确保查询参数被指定为参数而不是内联。
- 使用薄包装的 Hibernate 的 DetachedCriteria 代替 QueryCriteria。 “精简包装”是因为不允许客户端直接创建 DetachedCriteria,因为无法控制创建它的映射实体。 此外,对于某些无法通过 Criteria API 轻松(或根本)表达的查询,这不会像 HQL 那样灵活。与 HQL 方法一样,过滤器(上面的#4)将仅限于 Hibernate 会话过滤器。
- 编写我自己的 QueryCriteria 接口/实现,它将在幕后形成 DetachedCriteria 或 HQL。 虽然可能是最灵活的解决方案,但这将不得不从 Criteria API 复制大量代码,这似乎不太理想。
任何关于上述方法有效性的 cmets 或 - 祈祷 - 我没有想到的简单优雅的解决方案将不胜感激。
附:在我的具体情况下,所有 API 客户端都是内部的并且是“半可信的”——也就是说,我并不关心有人试图故意破坏某些东西,而是因为糟糕的编程导致 5 个表的笛卡尔积 :-) 但是,它如果能想出一个能够承受 API 向公众公开的解决方案,那就太好了。
【问题讨论】:
-
这个问题好像有两个月了;我很好奇你选择了什么?我想我会采用 #3,“编写我自己的......”方法,并尝试将我需要的信息片段“扁平化”到 ProductService/criteria API 上,作为可查询的属性,具体取决于使用情况。
-
@RMorrisey - 我添加了一个描述我的解决方案的答案。