这更像是一个设计而不是实现问题,而且它会很长,所以请耐心等待.最好用一个例子来解释:
假设我有一个名为Product的业务实体,其中包含许多属性(名称,价格,供应商等).
它由接口(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")product.vendor.name = "Microsoft",则上面的(2)中的查询应生成空结果集. 因此,问题是这种方法使用的QueryCriteria接口应该是什么样的?我可以想到3个解决方案,我不喜欢其中任何一个:
任何关于上述方法的有效性的评论或 - 手指交叉 - 我没有想到的简单优雅的解决方案将受到高度赞赏.
PS在我的具体情况下,所有的API客户端都是内部的,并且是"半可信的" - 这就是我不太关心有人试图故意破坏某些东西,因为糟糕的编程导致了5个表的笛卡尔积:-)但是,能够提供一种能够承受公众API暴露的解决方案会很不错.
我实施的实际解决方案使用混合方法。
使用明确定义的查询的方法(例如其他服务内部使用的方法、预定义的报告等)具有类似于 HibernateTemplate 的 findBy 方法的签名:
public List<Entity> findEntities(String queryName, QueryParameters parameters);
Run Code Online (Sandbox Code Playgroud)
其中QueryParameters是一个方便类,用于显式指定命名参数或从 bean 中获取它们。示例用法是:
List<Product> products = findProducts("latestUpdates",
new QueryParameters()
.add("vendor", "Oracle")
.add("price", "50.0")
);
Run Code Online (Sandbox Code Playgroud)
或者
List<Product> products = findProducts("latestUpdates",
new QueryParameters(product, "vendor", "price"));
Run Code Online (Sandbox Code Playgroud)
对此类方法的访问仅限于“可信”代码;显然使用的查询必须在 Hibernate 映射中定义。过滤器内置于查询中或定义为会话过滤器。好处是更干净的代码(没有类似 Criteria 的东西分布在半页上)和明确定义的 HQL(如果需要,更容易优化和处理缓存)。
暴露给 UI 的方法或需要更加动态地使用Hibernate-Generic-DAO项目中的搜索接口的方法。它有点类似于 Hibernate 的 DetachedCriteria,但有几个优点:
它可以在不依赖于特定实体的情况下创建。这对我来说很重要,因为实体接口(用户可见的 API 的一部分)和实现(Hibernate 中映射的 POJO)是两个不同的类,并且实现在编译时对用户不可用。
这是一个经过深思熟虑的开放接口;与 DetachedCriteria 完全不同,几乎不可能从中提取任何内容(是的,我知道 DC 不是为此设计的;但仍然如此)
内置分页/结果与总数/一堆其他小细节。
与 Hibernate 没有明确的联系(尽管我个人并不真正关心这一点;明天我不会突然放弃 Hibernate 并使用 EclipseLink);有 Hibernate 和通用 JPA 实现可用。
服务端搜索可添加过滤器;那也是指定实体类的时候。唯一缺少的是如果指定了无效的属性名称,客户端会快速失败,这可以通过编写我自己的 ISearch / IMutableSearch 实现来解决,但我还没有做到这一点。
| 归档时间: |
|
| 查看次数: |
2698 次 |
| 最近记录: |