0

I have a method in my controller which accepts a list of Employee as arguments. They are the updated objects which I want to update to the DB.

public static void save(Project project, List<ClientEmployee> clientEmployees){
   ...
   //project is currently associated with current hibernate session.
   //no clientEmployees are associated with current session, however all have id's.

   for(ClientEmployee newClientEmployee : clientEmployees){
      if(newClientEmployee != null){
          ClientEmployee clientEmployee = JPA.em().merge(newClientEmployee);
          //clientEmployee.role = newClientEmployee.role;
          project.addClientEmployee(clientEmployee);
      }
   }

}

When I call merge, the returned object clientEmployee does not have the updated information from newClientEmployee. Why is that? From what I know, hibernate will try to find object with same identifier, and load it after copying fields over?

So I thought it might be that the information is only updated after I save. But even after project.save(); It does not update the object nor the row in the db.

Example..

clientEmployee.name = "John Snow"; //Current id = 1, not attached to session.
ClientEmployee persitedEmployee = JPA.em().merge(clientEmployee) //DB row has id 1, but name is null

At this point persitedEmployee.name is still null.

SpartanElite
  • 624
  • 4
  • 13
  • Probably [this](http://stackoverflow.com/questions/1069992/jpa-entitymanager-why-use-persist-over-merge) will answer why... – gtgaxiola Jan 13 '14 at 20:25
  • Yes, according to that as well as other answers, `persistedEmployee .name` should be updated! but it isnt. – SpartanElite Jan 13 '14 at 20:29
  • What does your object graph look like? This might occur if newClientEmployee references something that references a different instance of the same newClientEmployee data - one that doesn't have changes to it, such that A->B->A', and the relationships all have cascade merge set. This would cause the changes merged from A to be reset when A' gets merged. – Chris Jan 14 '14 at 14:02

2 Answers2

0

Do not use public access to properties such as clientEmployee.name = "John Snow";, this does not work. Make the property private or protected and create the getters/setters, set the property via the setter like this: clientEmployee.setName("John Snow");.

See here from the Hibernate proxy pitfalls post:

Proxy Pitfall 1: Field Access

Coming to the first pitfall with proxies: When a proxy is loaded, the data is not stored in thr proxy object, but in the "target" object. The fields in the proxy object will remain null forever (or any value that they have been initialized with), since all methods invoked on the proxy will be delegated to the target object.

...

To prevent this, use getters and setters in these occasions. The proxy will be loaded when the getter is invoked and the data will be accessible.

Angular University
  • 42,341
  • 15
  • 74
  • 81
  • Im using the Play! framework, and this is normal. Play! uses Properties simulation to change access modifiers, and uses reflection to generate setter and getters. This is done at runtime. – SpartanElite Jan 13 '14 at 21:31
0

Detached Entity

What you are working with is a detached entity.

For new Entities you must use .persist().

For existing Entities you need to .merge() your entity into the EntityManager context, it will automatically persist the updated data.

NOTE: The reference you pass in will not be managed, .merge() creates a copy and adds the copy to the context.

Transactions

You must do the .merge() inside a transaction for it to work.

JPA.em().startTransaction();
ClientEmployee clientEmployee = JPA.em().merge(newClientEmployee);
JPA.em().commitTransaction();

Of course you need to do this inside a try/catch/finally block and call JPA.em().rollbackTransaction() on a failure and JPA.em().close() in the finally block.

Refresh

You can also do a JPA.em().refresh(newClientEmployee); to make sure you pull any dynamically created fields from the data store. This does not have to be done in a transaction.

Community
  • 1
  • 1
  • Yea, when I do `JPA.em().merge(newClientEmployee);`, no changes from `newClientEmployee` are present in clientEmployee (the returned object). This is all happening within the transaction. – SpartanElite Jan 14 '14 at 14:14
  • the reference you pass in will not bu udpated, because the `.merge()` creates a copy and manages the copy. –  Jan 14 '14 at 14:42
  • ik ref passed in will not be updated. But what is returned should be updated, ie `clientEmployee` (which is managed). But in my case it is not being updated. – SpartanElite Jan 14 '14 at 14:45
  • use `.persist()` for new entities –  Jan 14 '14 at 14:46