通过服务API公开Hibernate条件 [英] Exposing Hibernate criteria via service API

查看:279
本文介绍了通过服务API公开Hibernate条件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


这是一个更多的设计而不是实现的问题,这将是很长的,所以忍受我。最好用一个例子来解释:

This is more of a design than implementation question and it's going to be long so bear with me. It's best explained with an example:


假设我有一个名为 Product 的商业实体,属性(名称价格供应商等)。

Let's say I have a business entity called Product with a bunch of properties (name, price, vendor, etc...).


它由一个接口( Product )和实现( ProductImpl 映射到Hibernate)以及基本的CRUD服务接口( ProductService )和实现( ProductServiceImpl )。

产品 ProductService 作为API公开,其实现不是。

It's represented by an interface (Product) and implementation (ProductImpl, mapped in Hibernate) as well as basic CRUD service interface (ProductService) and implementation (ProductServiceImpl).
Product and ProductService are exposed as API, their implementations are not.


我想添加一个将findProducts(QueryCriteria条件)方法添加到 ProductService 将返回满足给定标准的产品列表。
要求是:

I want to add a List findProducts(QueryCriteria criteria) method to ProductService that would return a list of products satisfying given criteria. The requirements are:


  1. 直接查询产品属性(例如 product.price gt 50.0

  2. 按关联查询(例如 product.vendor.name =Oracle code>)

  3. 排序结果(例如 order by product.vendor.name desc,product.price asc

  4. 应用其他过滤器与API客户端指定的上述3项不同,服务可以根据客户端的身份应用其他过滤器(例如,客户端调用此方法可能仅限于这些过滤器优先于客户指定的任何标准(例如,如果过滤器设置为 product.vendor.name =Microsoft

  1. Query by direct Product properties (e.g. product.price gt 50.0)
  2. Query by association (e.g. product.vendor.name = "Oracle")
  3. Sort results (e.g. order by product.vendor.name desc, product.price asc")
  4. Apply additional filters. Unlike the above 3 items which are all specified by API client, additional filters may be applied by the service based on client's identity (e.g. client invoking this method may be limited to only seeing products manufactured by given vendor). Such filters take precedence over any criteria specified by the client (e.g. if the filter is set to product.vendor.name = "Microsoft", query in (2) above should produce empty result set.

因此,问题应该是:如何查询(b)QueryCriteria 接口使用这样的方法看起来像?我可以想到3个解决方案,我不会l我们中的任何一个:

The question, therefore, is what should QueryCriteria interface used by such a method look like? I can think of 3 solutions and I don't like either one of them:


  • 允许客户端直接指定HQL(以where子句开头)。
    这是最简单的解决方案,但也是最有问题的安全方面。即使假设过滤器(上面的#4)足够简单,可以通过Hibernate的会话过滤器来实现,HQL仍然需要被解析为至少 - 确保查询参数被指定为参数而不是内联。


  • 使用薄薄的Hibernate的 DetachedCriteria 代替 QueryCriteria
    薄包装,因为客户端不能直接创建 DetachedCriteria ,因为没有办法控制其创建的映射实体。
    此外,这不会像一些查询的HQL那样灵活,通过Criteria API不容易(或者根本不能)表达。与HQL方法一样,过滤器(上面的#4)将仅限于Hibernate会话过滤器。


  • 编写自己的 QueryCriteria 接口/实现在幕后形成DetachedCriteria或HQL。
    虽然可能是最灵活的解决方案,但这将不得不复制Criteria API中的大量代码,这似乎不太理想。

  • Allow clients to specify HQL (starting with "where" clause) directly. This is the most straightforward solution, but also the most problematic security-wise. Even assuming that filters (#4 above) are simple enough to be implemented via Hibernate's session filters, HQL still needs to be parsed to - at the very least - ensure that query parameters are specified as parameters and not inlined.
  • Use thinly wrapped Hibernate's DetachedCriteria in place of QueryCriteria. "Thinly wrapped" because client can not be allowed to create DetachedCriteria directly for there would be no way to control what mapped entity it was created for. Also, this would not as flexible as HQL for some queries are not easily (or at all) expressible via Criteria API. As with HQL approach, filters (#4 above) will be limited to Hibernate session filters.
  • Write my own QueryCriteria interface / implementation which will form either DetachedCriteria or HQL behind the scenes. While probably the most flexible solution, this will have to duplicate a lot of code from Criteria API which seems less than ideal.

对上述方法的有效性的任何评论或 - 手指交叉 - 我没有发生的简单优雅的解决方案将受到高度赞赏。

Any comments on the validity of the above approaches or - fingers crossed - simple elegant solutions that didn't occur to me would be highly appreciated.

在我的具体情况下,所有的API客户端都是内部的和半信任的 - 那就是我不太在意一个人试图用糟糕的编程来打破某些东西,导致5个表的笛卡尔乘积:-)然而,它很高兴能提出一种可以承受API暴露于公众的解决方案。

P.S. In my specific case, all API clients are internal and "semi-trusted" - that is I'm not as much concerned with someone trying to deliberately break something as with poor programming resulting in Cartesian product of 5 tables :-) However, it'd be nice to come up with a solution that would withstand API exposure to public.

推荐答案

我实现的实际解决方案使用混合方法。

The actual solution I've implemented uses a hybrid approach.

使用定义良好的查询(例如其他服务内部使用的方法,预定义报告等)的方法具有类似于HibernateTemplate的findBy的签名方法:

Methods that use well-defined queries (e.g. methods that are used internally by other services, predefined reports, etc.) have signature similar to HibernateTemplate's findBy methods:

public List<Entity> findEntities(String queryName, QueryParameters parameters);

其中 QueryParameters 是一个方便的类来指定明确命名参数或从一个bean中获取它们。示例用法是:

where QueryParameters is a convenience class for specifying named parameters explicitly or taking them from a bean. Sample usage is:

List<Product> products = findProducts("latestUpdates",
 new QueryParameters()
  .add("vendor", "Oracle")
  .add("price", "50.0")
);

List<Product> products = findProducts("latestUpdates",
 new QueryParameters(product, "vendor", "price"));

访问此类方法仅限于可信代码;显然,在Hibernate映射中必须明确定义查询。过滤器内置于查询中或定义为会话过滤器。优点是更清晰的代码(没有类似标准的东西分布在半个页面上)和清晰定义的HQL(如果需要,更容易优化和处理缓存)。

Access to such methods is limited to "trusted" code; queries used obviously must obviously be defined in Hibernate mappings. Filters are built into query or defined as session filters. The benefits are cleaner code (no Criteria-like stuff spread across half a page) and clearly defined HQL (easier to optimize and deal with cache if necessary).

暴露于UI或以其他方式需要更加动态使用的方法 Hibernate-Generic-DAO的rel =nofollow noreferrer>搜索界面项目。它有点类似于Hibernate的DetachedCriteria,但有几个优点:

Methods that are exposed to UI or otherwise need to be more dynamic use Search interface from Hibernate-Generic-DAO project. It's somewhat similar to Hibernate's DetachedCriteria but has several advantages:


  1. 它可以创建而不被绑定到特定的实体。对我来说这是一个很大的事情,因为实体接口(用户可见的API的一部分)和实现(在Hibernate中映射的POJO)是两个不同的类,在编译时,实现不可用于用户。

  1. It can be created without being tied to particular entity. It's a big deal for me because entity interface (part of API visible to users) and implementation (POJO mapped in Hibernate) are two different classes and implementation is not available to user at compile time.

这是一个深思熟虑的开放界面;非常不同于DetachedCriteria,几乎不可能提取任何东西(是的,我知道DC不是为那个设计的,但仍然)

It's a well thought out open interface; quite unlike DetachedCriteria from which it's nearly impossible to extract anything (yes, I know DC wasn't designed for that; but still)

内置分页/结果与其他小细节的总数/束。

Built-in pagination / results with total count / bunch of other little niceties.

没有明确的关系Hibernate(虽然我个人不太在乎这个;我不是明天就要休息一下Hibernate并去EclipseLink);可以使用Hibernate和通用JPA实现。

No explicit ties to Hibernate (though I personally don't really care about this; I'm not going to suddenly drop Hibernate and go with EclipseLink tomorrow); there are both Hibernate and generic JPA implementations available.

过滤器可以添加到服务端搜索;那就是实体类也被指定了。唯一缺少的是客户端快速失败,如果指定了无效的属性名称,并且可以通过编写自己的ISearch / IMutableSearch实现来解决,但是我还没有得到。

Filters can be added to Search on service side; that's when entity class is specified as well. The only thing's missing is quick-fail on client side if invalid property name is specified and that can be resolved by writing my own ISearch / IMutableSearch implementation but I didn't get to that yet.

这篇关于通过服务API公开Hibernate条件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆