EclipseLink has long supported additional criteria being configured on a descriptor (mapping for an entity type). In this blog I just wanted to post some simple example code that illustrates how additional criteria can be applied to a an entity type with parameters that are then specified in the creation of the EntityManager where the criteria is to be applied.
Using either an annotation on the entity class as:
@EntityAlternatively this customizer can be configured in persistence unit properties as well as in the eclipselink-orm.xml mapping file.
@Customizer(AddEmployeeGenderCriteria.class)
public class Employee
This allows for a provided customer to be called and the descriptor for the entity type, Employee in this case, to be customized. Here we'll add the additional criteria (filter) that will later be used.
public static class AddEmployeeGenderCriteria implements DescriptorCustomizer {Note: The SessionPropertyValue class is an extension and is only required if the criteria has a parameter value that will be supplied dynamically per EntityManager.
public void customize(ClassDescriptor descriptor) throws Exception {
ExpressionBuilder eb = new
ExpressionBuilder(descriptor.getJavaClass());
Expression genderExp = eb.get("gender").equal(new
SessionPropertyValue("gender"));
descriptor.getQueryManager().setAdditionalJoinExpression(genderExp);
}
}
Now with the descriptor has been customized with the additional criteria for all Employee queries we simply need to provide the argument value when creating the EntityManager.
properties.put("gender", "M");This will cause all queries such as:
EntityManager em = emf.createEntityManager(properties);
em.createQuery("SELECT e FROM Employee e WHERE e.firstName LIKE 'J%'", Employee.class).getResultList();To have the addtitional criteria added and the SQL generated appears as:
SELECT t0.EMP_ID, t1.EMP_ID, t0.L_NAME, t0.END_TIME, t0.VERSION, t0.START_TIME, t0.GENDER, t1.SALARY, t0.F_NAME, t0.MANAGER_ID, t0.ADDR_ID, t0.START_DATE, t0.END_DATE FROM EMPLOYEE t0, SALARY t1 WHERE (t0.F_NAME LIKE ? AND ((t1.EMP_ID = t0.EMP_ID) AND (t0.GENDER = ?)))The only additional requirement is that the entity types with the EntityManager specific 'filters' be only cached in the EntityManager (isolated/txn cache) instead of the default shared cache to ensure that filtered collections from one context are not incorrectly presented in another where different parameter values are used.
bind => [J%, M]
The use of these types of filters is not all that common in my experience so improving the configuration has not been a priority. If you use these filters and would like to have the usage of them in EclipseLink improved we are eager to get your feedback.
4 comments:
Hi Doug
You mention that SessionPropertyValue is some kind of extra code. Could you please explain how to access Session properties from the Customizer? I'm using EclipseLink as JPA implemenation using transaction-scoped PersistenceContexts
Adrian
Adrian,
Here is a version of PropertyValue.
We have simplified Additional Criteria usage in EclipseLink 2.2 in ER 322008. This support added for EclipseLink 2.2 simplifies config like:
@AdditionalCriteria("this.company=:COMPANY")
Doug
Hi Doug,
thanks a lot! This is great news as this is exactly what we need in combination with EclipseLink's HistoryPolicy to achieve bi-temporality.
Adrian
Hi Doug,
we have a similiar use case.
Instead of having a criteria we would need the EM to add properties from the session in the "SET" part of SQL when using insert or update statements and NOT in the where clause.
Our problem is, that using inheritance we don't see our default attributes like created_by, modiefied_by on the Table which represents the inherited entity, only on the table belonging to its superclass.
I was wondering if we could use the EM also for this use case it would ease some things.
Stefan
Post a Comment