I am not currently using a lot of Hibernate specific functionality. The ones that occur to me at the moment is:
- Hibernate Filters
- Hibernate DELETE_ORPHAN
Filters
Filters are, as far as I know, currently not a part of the JPA Specification. Every ORM has its own implementation of dealing with it.Below are the two different (very different!) implementations for Hibernate and EclipseLink. I find the Hibernate one to be more powerful.
Hibernate
Definition of the filter:@FilterDef(name = "activePersons", defaultCondition="active = 1")
package mmud.database.entities;
Using the Filter on Entities:package mmud.database.entities;
import org.hibernate.annotations.Filter;
import org.hibernate.annotations.Filters;
@Entity
@Filters({ @Filter(name = "activePersons") })
public class Person implements Serializable { ...
import org.hibernate.annotations.Filters;
@Entity
@Filters({ @Filter(name = "activePersons") })
public class Person implements Serializable { ...
@Entity
public class Room implements Serializable {
@OneToMany(cascade = CascadeType.ALL, mappedBy = "room")
@Filter(name = "activePersons")
private Set<Person> persons = new HashSet<>();
Enabling the Filter, upon starting a session:public class Room implements Serializable {
@OneToMany(cascade = CascadeType.ALL, mappedBy = "room")
@Filter(name = "activePersons")
private Set<Person> persons = new HashSet<>();
// Hibernate specific
Session session =
((org.hibernate.ejb.EntityManagerImpl)em.getDelegate()).getSession();// JPA1.0
// Session session = getEntityManager().unwrap(Session.class); // JPA2.0
session.enableFilter("activePersons");
Session session =
((org.hibernate.ejb.EntityManagerImpl)em.getDelegate()).getSession();// JPA1.0
// Session session = getEntityManager().unwrap(Session.class); // JPA2.0
session.enableFilter("activePersons");
EclipseLink
EclipseLink uses the AdditionalCriteria2 3 annotation on Entity level.@Entity
@AdditionalCriteria("(:activePersonFilter <> 1 or this.active = 1)")
public class Person implements Serializable { ...
...
...
getEntityManager().setProperty("activePersonFilter", 1); // turns filter on
@AdditionalCriteria("(:activePersonFilter <> 1 or this.active = 1)")
public class Person implements Serializable { ...
...
...
getEntityManager().setProperty("activePersonFilter", 1); // turns filter on
Unfortunately, I cannot not set it, as that will trigger the following:
org.eclipse.persistence.exceptions.QueryException.missingContextPropertyForPropertyParameterExpression(QueryException.java:260)
So I am obligated to turn the filter on or off at the boundary where the entityManager (or EntityManagerFactory) is first called.And there is not a convenient way of turning a filter on or off. Right now, the turning on/off is part of the subquery.4
However, I do like the fact that my AdditionalCriteria suddenly works everywhere once I turn it on. I do not have to set specifics on the fields of an Entity. Of course, this does limit the flexibility, but in my case it is not an issue.
Deleting Orphans
Well, Hibernate was one of the first to implement the Delete-orphan functionality and it took a while for it to become meanstream in the JPA specification. But it's there now, and should be supported by all ORMs.Hibernate
@OneToMany(cascade = CascadeType.ALL, mappedBy = "belongsto")
@Cascade({ org.hibernate.annotations.CascadeType.DELETE_ORPHAN })
private Set<item> items;
@Cascade({ org.hibernate.annotations.CascadeType.DELETE_ORPHAN })
private Set<item> items;
JPA 2.0
@OneToMany(cascade = CascadeType.ALL, mappedBy = "belongsto", orphanRemoval = true)
private Set<item> items;
private Set<item> items;
Sha1
Hibernate
Apparently JPA doesn't have an sha1 function, yet mysql does. Hibernate had no problems with it, so I looked for a solution from EclipseLink5.@NamedQuery(name = "User.authorise", query = "select p from Person p WHERE p.name = :name and p.password = sha1(:password)")
JPA 2.1
It turns out JPA5 has a specific reserved word called "FUNCTION" to support this, that I quite like. It prevents me from having to write a specific MySQL Dialect.Of course, it does tie me to the MySQL implementation, but you cannot have everything.
@NamedQuery(name = "User.authorise", query = "select p from Person p WHERE p.name = :name and p.password = FUNCTION('sha1', :password)")
Notes
I found EclipseLink to be very strict with the interpretation of JPQL.Issue 1 - References
For example, it complains about:SELECT max(id) FROM ItemDefinition i
Wanting something more along the lines of:SELECT max(i.id) FROM ItemDefinition i
Issue 2 - Like statements
Then there's an issue with the following query statement:SELECT s FROM SillyName s WHERE :name like s.name
That gave me the error message "You have attempted to set a value of type class java.lang.String for parameter name with expected type of class java.lang.Boolean". I had to do some voodoo magic to make it work:SELECT s FROM SillyName s WHERE concat('',:name) like s.name
Yikes!Issue 3 - Update statements
Furthermore, I got a warning when creating the following update statement:UPDATE Item i SET i.container = :container WHERE i = :item and i.belongsto = :person
The warning was:“Input parameters can only be used in the WHERE clause or HAVING clause of a query.”Apparently JPQL doesn't allow named parameters (or parameters of any kind) outside a WHERE or HAVING clause.
This was only a warning and the thing does work, but I should heed it.
It is described in Chapter 10.2.5.4. JPQL Input Parameters of the JPQL Language Spec7
Netbeans
I especially liked the fact that in Netbeans, I can mouse over the NamedQueries in the Entities and it tells me in a popup what is wrong.References
- [1] The Java EE 7 Tutorial - Introduction to the Java Persistence API
- http://docs.oracle.com/javaee/7/tutorial/doc/persistence-intro001.htm
- [2] AdditionalCriteria
- http://wiki.eclipse.org/EclipseLink/Development/AdditionalCriteria
- [3] AdditionCriteria
- https://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Mapping/Additional_Criteria
- [4] StackOverflow - Is there a way to disable additionalcriteria in EclipseLink?
- http://stackoverflow.com/questions/15847792/is-there-a-way-to-disable-additionalcriteria-in-eclipselink
- [5] StackOverflow - JPA How to persist column with sha1 encryption
- http://stackoverflow.com/questions/7868939/jpa-how-to-persist-column-with-sha1-encryption
- [6] EclipseLink UserGuide - Support for Native Database Functions
- http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/Support_for_Native_Database_Functions#FUNC
- [7] Oracle - JPQL Language References
- http://docs.oracle.com/cd/E17904_01/apirefs.1111/e13946/ejb3_langref.html
No comments:
Post a Comment