Does anyone have a good example for how to do a findByExample in JPA that will work within a generic DAO via reflection for any entity type? I know I can do it via my provider (Hibernate), but I don't want to break with neutrality...
Seems like the criteria API might be the way to go....but I am not sure how to handle the reflection part of it.
Spring Data JPA Query By Example Query by Example (QBE) is a user-friendly querying technique with a simple interface. It allows dynamic query creation. We do not need to write queries with store-specific query language. We work with three objects.
A derived query method name has two main components separated by the first By keyword: The introducer clause like find , read , query , count , or get which tells Spring Data JPA what you want to do with the method.
Its findById method retrieves an entity by its id. The return value is Optional<T> . Optional<T> is a container object which may or may not contain a non-null value. If a value is present, isPresent returns true and get returns the value.
Actually, Query By Example (QBE) has been considered for inclusion in the JPA 2.0 specification but is not included, even if major vendors support it. Quoting Mike Keith:
I'm sorry to say that we didn't actually get to do QBE in JPA 2.0. Criteria API does not have any special operators for it so entity equality is just like in JP QL, based on PK value. Sorry, but hopefully we'll be more successful on that front in the next go-round. For now it is one of those vendor features that every vendor supports, but is not in the spec yet.
Just in case, I've added (non generic) sample code for the major vendors below for documentation purposes.
Here is a sample of using QBE in the EclipseLink JPA 2.0 reference implementation:
// Create a native EclipseLink query using QBE policy QueryByExamplePolicy policy = new QueryByExamplePolicy(); policy.excludeDefaultPrimitiveValues(); ReadObjectQuery q = new ReadObjectQuery(sampleEmployee, policy); // Wrap the native query in a standard JPA Query and execute it Query query = JpaHelper.createQuery(q, em); return query.getSingleResult();
OpenJPA supports this style of query through its extended OpenJPAQueryBuilder
interface:
CriteriaQuery<Employee> q = cb.createQuery(Employee.class); Employee example = new Employee(); example.setSalary(10000); example.setRating(1); q.where(cb.qbe(q.from(Employee.class), example);
And with Hibernate's Criteria API:
// get the native hibernate session Session session = (Session) getEntityManager().getDelegate(); // create an example from our customer, exclude all zero valued numeric properties Example customerExample = Example.create(customer).excludeZeroes(); // create criteria based on the customer example Criteria criteria = session.createCriteria(Customer.class).add(customerExample); // perform the query criteria.list();
Now, while it should be possible to implement something approaching in a vendor neutral way with JPA 2.0 Criteria API and reflection, I really wonder if it's worth the effort. I mean, if you make any of the above snippets generic and put the code in a DAO method, it would be quite easy to switch from one vendor to another if the need should arise. I agree it's not ideal, but still.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With