0

I have two consecutive operations that need to happen. First, I insert a new record (I'm using JPA), to use as a historical record, and then I run an update to a record that is always used as the most "current" with information coming in on the call.

The problem is that the object has a composite key, which I need to insert it, but I don't want it returned in the JSON that I return after the update. JPA has a real problem with altering the composite keys, but I found the .detach method which has worked for me in the past. The fields I want to be null are marked as @Transient in the actual object, and no error is thrown. It performs the insert fine, but the update fails if I try to move the primary keys at ALL. Even after the insert is called, and even using the .detach method. Any ideas what I'm missing?

I would think I could do it like so:

          em.merge(contract); //Object to be saved
          em.detach(contract); // allows me to manipulate it

          policy.setContractNum(policy.getId().getContractNum());
          policy.setCustNum(policy.getId().getCustNum());

          returnPolicyAsList.add(policy);

          customer.setPolicies(returnPolicyAsList);
          status.setFamCustomer(customer);
          status.setStatus(Message.SUCCESS);
          status.setStatusMessage(Message.SUCCESS);

          return status;
Josh
  • 115
  • 1
  • 15
  • 1
    `detach` is for cross-session operations. Don't use `detach` just so you can manipulate objects in ways Hibernate is not expecting. Hibernate is not expecting it! Also, your code doesn't use `contract` anywhere after the `detach`, so I don't know what it is you're trying to do. – João Mendes Dec 20 '16 at 15:35
  • Sorry I could've maybe been more clear. I will edit in a second. I have an embedded id which I use for the inserts, but I don't want them returned in the actual JSON. So I have two transient fields with the same name, and I just move them - but after I do the update. I don't want the key returned in the JSON, is essentially my goal. I'll post more code samples to give you a better idea. – Josh Dec 20 '16 at 15:38
  • 2
    You need to provide more code. You have a contract variable referencing an entity, but I see no other use of this variable. Also are you sure you want to use merge ? I never use my Entities for generating JSON, but have a separate set of DTO classes for this, that way you have more control over the JSON. Also modifying the primary key of an Entity is a recipe for disaster. – Klaus Groenbaek Dec 20 '16 at 15:40
  • 1
    Also remember that it is the return value from merge that is a managed entity, not the input to merge. – Klaus Groenbaek Dec 20 '16 at 15:44
  • 1
    I'm with Klaus, you shouldn't be generating JSON directly and automatically from your entities. Either generate by hand or have some sort of intermediate DTO. – João Mendes Dec 20 '16 at 15:46
  • Well if I don't alter the keys, then it works fine. Altering the keys causes the update to fail. So the merge operation seems to be working fine. I don't like altering the keys either, but I'm not sure how to use them for the update, and then not have them in the JSON. I was under the impression the .detach operation let you do whatever you want as the beans are no longer managed? – Josh Dec 20 '16 at 15:47
  • A DTO actually sounds good! That may work. I'm interested to know why .detach breaks my update however. – Josh Dec 20 '16 at 15:48
  • DTO Worked like a charm! Much better. Thanks everyone. – Josh Dec 20 '16 at 16:27

1 Answers1

3

You seem not to quite be in tune with JPA's model of the world. An entity's primary key is its identity. As such, you should never modify the primary key of a persistent entity.

That conflicts a bit with Java's view, which attributes a separate identity to each object. You work with the Java view with entities that are not persistent -- i.e. those that are new, detached, or removed. That's why you can twiddle an entity's PK once you detach it, but you have to understand that doing so changes its identity from JPA's viewpoint. If you later try to merge such an entity then JPA sees only its new identity, not its old one.

If you need to change an entity's PK (generally a bad idea) then you should delete it, change the PK, and then persist it again. On the other hand, if your PK comprises information that may change over time, then you really ought to choose a different PK. Indeed, JPA works most smoothly when you use surrogate PKs instead of PKs comprising business data.

Community
  • 1
  • 1
John Bollinger
  • 160,171
  • 8
  • 81
  • 157