11

I am using Hibernate 4.1.7 and trying to update object, but theres no documentation how it should be done. Currently, I am doing this:

    Person person = personDao.getPersonById(1);
    person.setAge(23);
    person.setLastname("McName");
    person = personDao.update(person);

In PersonDao update looks like:

    public Person update(Person person) {
      return entityManager.merge(person);
    }

In PersonDao getPersonById is:

    public Person getPersonById(int id) {
      personQuery = entityManager.createNamedQuery("Person.findPerson", Person.class);
      personQuery.setParameter("id", id);
      return personQuery.getSingleResult();
    }

Also I have defined named query inside Person class and is here:

    @NamedQuery(name="Person.findPerson", query="SELECT p FROM Person p WHERE p.id = :id")

By using that my Person won't be updated, how should I implement update using hibernate?

Buhake Sindi
  • 87,898
  • 29
  • 167
  • 228
Timo
  • 141
  • 1
  • 2
  • 6
  • The above code is OK, except that the call to `personDao.update()` is completely unnecessary if everything is run in a single transaction: the state of an entity is automatically made persistent by JPA/Hibernate at the end of the transaction. The getPersonById method could also be reduced to `em.find(Person.class, id)`, which would be simpler, and more efficient, since it wouldn't execute any query if the entity is loaded already. – JB Nizet Oct 27 '12 at 18:18
  • Addendum: this is definitely explained in the documentation. See http://docs.jboss.org/hibernate/orm/4.1/devguide/en-US/html_single/#d5e772 – JB Nizet Oct 27 '12 at 18:20

3 Answers3

12

Two scenarios might pop up for you.

You may want to change a property of the object, and only that property.

If this is the case you want to use the method: find, modify, flush, commit.

em.find(Person.class, person.getId())
person.setStatus("ACTIVE");
em.commit();//implicitly flushes if flush mode is COMMIT or AUTO.

You may want to use the objects properties to update the item.

If this is the case you want to use the method: merge, optionally modify, flush, commit.

em.merge(person);
//modify person if you wish.
em.commit();//implicitly flushes if flush mode is COMMIT or AUTO.
dseibert
  • 1,319
  • 9
  • 19
  • Found my solution, finally I used entityManager.getTrasaction().begin(); person = entityManager.find(Person.class, id); entityManager.merge(person); // modify person data entityManager.getTransaction().commit(); – Timo Oct 28 '12 at 11:33
  • Glad you found a solution. If the id used during find(Person.class, id) is the person.id used when doing merge(person), then the merge might not be necessary. Once you do the find, your entity is managed and you can modify and commit your changes. – dseibert Oct 28 '12 at 15:40
1

Hibernate and also other JPA implementations automatically manage state of entities and save it to database if modification is enclosed in transaction. You do not need to explicitly call merge or update methods.

If you are using resource-local transactions (not managed by JTA transaction manager) try something like this:

EntityTransaction tx = entityManager.getTransaction();
tx.begin();
Person person = personDao.getPersonById(1);
person.setAge(23);
person.setLastname("McName");
tx.commit();

and all your modifications will be automatically saved in database.

If you are using JTA then you have to mark the transaction boundaries in some other way, for example by using Spring AOP @Transactional annotation.

Jarek
  • 141
  • 2
  • I am using hsqldb (resource-local) and by useing this code I get exception: org.hibernate.PersistentObjectException: detached entity passed to persist: com.application.model.Person – Timo Oct 28 '12 at 11:09
  • Probably you are using two distinct instances of EntityManager. – Jarek Oct 28 '12 at 13:10
0

I don't know what you're asking exactly, but in your method, Person.getPersonById(int id), you can simplify your code with the following:

return entityManager.find(Person.class, id);
Buhake Sindi
  • 87,898
  • 29
  • 167
  • 228