How to overcome the limitations of Hibernate criteria and API examples?

I am in a position where our company has a database search service that is very customizable, for which it is very useful to configure queries programmatically. The Criteria API is very efficient, but when one of our developers reorganizes one of the data objects, criteria restrictions will not signal that they are broken until we do our unit tests or, even worse, we don’t live in our work environment. Recently, we had a refactoring project, which unexpectedly shrunk during working hours due to this problem - a gap in project planning, which, if we knew how long it really would take, we would probably use an alternative approach.

I would like to use an example API to solve this problem. The Java compiler may loudly indicate that our requests are being processed if we specify "where" conditions for real POJO properties. However, the examples API has so much functionality, and this limits it in many ways. Take the following example

Product product = new Product(); product.setName("P%"); Example prdExample = Example.create(product); prdExample.excludeProperty("price"); prdExample.enableLike(); prdExample.ignoreCase(); 

The property “name” is requested here (where the name is of type “P%”), and if I have to delete or rename the field “name”, we will immediately find out. But what about the price property? It is excluded due to the fact that the Product object has a default value for it, so we pass the name of the property “price” to the exclusion filter. Now, if the "price" is deleted, this request will be syntactically invalid, and you will not recognize it before execution. LAME

Another problem is that if we added a where where clause:

  product.setPromo("Discounts up to 10%"); 

Due to the call to enableLike (), this example will correspond to the promo text “Discounts up to 10%”, but also “Discounts up to 10,000,000 dollars” or anything else that matches. In general, modifications to the Object for the Example, such as enableLike () or ignoreCase (), will not always apply to all checked properties.

Here's the third and main problem - what about other special criteria? There is no way to get each product priced at more than $ 10 using the standard sample structure. There is no way to order results by promo, in descending order. If the Product object is connected to some manufacturers, there is no way to add criteria to the corresponding manufacturer object. There is no way to safely specify FetchMode on the criteria for the Manufacturer either (although this is a problem with the Criteria API in general - invalid retrieved relationships fail, even more from a time bomb)

For all the examples above, you will need to go back to the Criteria API and use string property representations for the request - again, eliminating the greatest advantage of example requests.

What alternatives exist in the example API that can get the required compile-time advice?

+6
java hibernate hibernate-criteria upgrade
source share
3 answers

My company provides developers with days when we can experiment and work on pet projects (a la Google), and I spent some time working with the framework to use the Query Examples, bypassing the restrictions described above. I came up with something that might be useful for other people interested in sample queries. The following is an example structure using an example product.

  Criteria criteriaQuery = session.createCriteria(Product.class); Restrictions<Product> restrictions = Restrictions.create(Product.class); Product example = restrictions.getQueryObject(); example.setName(restrictions.like("N%")); example.setPromo("Discounts up to 10%"); restrictions.addRestrictions(criteriaQuery); 

Here's an attempt to fix problems in the sample code from the question - the problem of the default value for the "price" field no longer exists, because this structure requires that the criteria be explicitly specified. The second problem related to the inclusion of the enableLike () method is absent - the match is only in the "name" field.

Other issues mentioned in this question have also gone away in this context. Here are implementation examples.

  product.setPrice(restrictions.gt(10)); // price > 10 product.setPromo(restrictions.order(false)); // order by promo desc Restrictions<Manufacturer> manufacturerRestrictions = Restrictions.create(Manufacturer.class); //configure manuf restrictions in the same manner... product.setManufacturer(restrictions.join(manufacturerRestrictions)); /* there are also joinSet() and joinList() methods for one-to-many relationships as well */ 

Even more complex restrictions are available.

  product.setPrice(restrictions.between(45,55)); product.setManufacturer(restrictions.fetch(FetchMode.JOIN)); product.setName(restrictions.or("Foo", "Bar")); 

After introducing the structure to a colleague, he mentioned that many data display objects have private setters, which makes this type of configuration difficult (another problem with the API example!). So, I also explained it. Instead of using setters, getters can also be requested.

  restrictions.is(product.getName()).eq("Foo"); restrictions.is(product.getPrice()).gt(10); restrictions.is(product.getPromo()).order(false); 

I also added extra object checking to provide better type safety - for example, do relative criteria (gt, ge, le, lt) all require value? extends Match for a parameter. In addition, if you use a getter in the above style, and there is an @Transient annotation present on the receiver, it will cause a runtime error.

But wait, there still!

If you like that this built-in Hibernate constraint utility can be statically imported so you can do things like criteria.addRestriction (eq ("name", "foo")) without making your code really verbose, there is an option for this also.

  Restrictions<Product> restrictions = new Restrictions<Product>(){ public void query(Product queryObject){ queryObject.setPrice(gt(10)); queryObject.setPromo(order(false)); //gt() and order() inherited from Restrictions } } 

That he is at the moment - many thanks for any feedback! We sent the code to Sourceforge for those who are interested. http://sourceforge.net/projects/hqbe2/

+5
source share

The API looks great!

Restrictions.order (boolean) smells like a control link. It is not clear what the values ​​of the logical argument represent.

I suggest replacing or supplementing orderAscending () and orderDescending ().

+1
source share

Take a look at Querydsl . Their JPA / Hibernate module requires code generation. Their Java compilation module uses proxies, but cannot be used with JPA / Hibernate at this time.

+1
source share

All Articles