samedi 21 mai 2011

Why I prefer Hibernate Session API to JPA EntityManager

In one of my projects, I needed to integrate @prePersist and @PreUpdate to take care of LastModified field (insert and update) using hibernate implementation of JPA with sessionFactory.

I was using spring framework with hibernate (sessionFactory), and it seems that is impossible, because these are JPA callbacks that won't work with Session API, and to catch them we must use JPA implementation.

See http://stackoverflow.com/questions/4133287/preupdate-and-prepersist-in-hibernate-jpa-using-session

Hum, it seems that is time to move to full JPA and using standards seems to be a good thing. My application will be more portable (I never had an intention to switch from my good lightweight tomcat server to any of these big application server). What other? Ah, I can at anytime change the implementation (even if I really don't have any intention to move from Hibernation to TopLink or any other ORM).

Anyway, standard is standard and we all love standards (We will see that this is not always true)

So, I started working on a new branch: refact/entityManager and after 4 days refactoring the services/dao classes from Hibernate (Hibernate/SessionFactory) to JPA (Hibernate/EntityManager),
I just discovered that when inserting a duplicate entry, the transaction is rolled back and a TransactionSystemException is thrown and there is no mean to what was the culprit (the original cause). With session API I was able to know exactly what happened. ConstraintViolationException or DataIntegrityViolationException if spring exception translation is tuned on.

As I don't want to add a try-catch clause to the top-level method calling my transactional service method, and I don't want an extra select to check if a the entry already exists, I prefer the session API behavior and I will move back to Session API.

See thread on http://stackoverflow.com/questions/6040787/spring-exception-translation-isnt-working-with-jpa

So, how did you solved your problem then?

The solution is to use @Version as described here: http://notatube.blogspot.com/2010/03/hibernate-using-event-listener-to-set.html

private Timestamp lastModified;
 @Version
 public Timestamp getLastModified() {
  return lastModified;
 }
 public void setLastModified(Timestamp lastModified) {
  this.lastModified = lastModified;
 }
 
Be sure to not have a method named onUpdate, as it is never called but make @Version fail silently. Change the method name, drop the table and create if you want @Version to work again"


Now, I'm happy with my good Hibernate/sessionFactory. May be one day, I'll try JDO, but I'll never play again with JPA/entityManager.

Extra Bonus: I don't want to loose my work

When in refact/entityManager branch, I have created a lot of test classes and I don't want to loose them.

Hopefully, git was there, suppose you are in master, just use:
git checkout refact/entityManager path/to/files ... 
sometimes we can check content of files from other branchs :
git show refact/entityManager:file
Source: http://stackoverflow.com/questions/449541/how-do-you-merge-selective-files-with-git-merge/1355990#1355990

Aucun commentaire:

Enregistrer un commentaire