Altering an Object after I Merge it (Persistence Context) breaks update - java

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;

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.

Related

How to persist Entity twice JPA

I have an entity, that represent order sent by the customer , this order might be updated after some discussion with the customer on phone, but the initial order sent by the customer must be persisted without update.
how i can persist same entity twice , is it efficient to use deep cloning.
i have tried to detach the the entity in order for persistence context to persist a new one , but still the persistence context is updating the first entry.
You can not persist one object twice in one session, so you need copy your order and save (persist) it again.
hibernate copy object values into new object with new generated ID
That's an interesting question. I think the quickest solution would probably be to use a multi-part ID. The first part would be the original order number and then every change increments the second part of the key. In your code you'd just need to find the object, make sure it's detached, alter the second part of the key and then persist it. As long as it's been detached it should then be saved away as a new order.
This post shows you how to use a composite key.
You need to clone/copy the object, ensure it has a unique id (or null if generated).
In EclipseLink there is an API to copy objects,
http://wiki.eclipse.org/EclipseLink/Examples/JPA/AttributeGroup#Copy_Examples

Unique contraint violation whien trying to delete and add a row using Hibernate

I have a project which which has hibernate classes mapped to the underlying tables. There is table which has a composite key.I am deleting the unique row and adding the same row in my hibernate object. Both these objects are part of another object which I am persisting into db. The program throws "UNIQUE CONSTRAINT VIOLATION" error which is presume is because insert is happening before delete operation. Is there way to resolve this using some setting in hibernate or should I have the necessary logic [outside hibernate object manipulation] in place to ensure this does not happen.
You shall ensure that object deletion is flushed to database before you attempt to
create another object with the same key. But in your case it would be better to just replace
data inside of object to be remover with new one. From hibernate point of view, same PC means same object.
When I have used Hibernate in the past, 90% of the time it makes no difference what order you call the insert or delete statement, or even the commit. In most cases, it matters where the session actually closes the Transaction unless you are managing your transaction yourself.
But one great thing about hibernate is that you shouldn't be removing a row that has the same key, you should just update its object instance with the relevant data and persist the update instance. Hibernate will take care of the rest...

What are JPA entities?

I am starting to use JPA and I always get confused with the term of entities and their usage, I have read a lot but I still don't quite get it.
I read the Oracle documentation of it but it does not really explain its role in the transaction.
What are JPA enities? does they actually hold the data for each row, I mean, are they stored instances that hold the row data? or they just map tables of the db and then insert and delete in them?
for example if I use this:
entity.setUserName("michel");
Then persisting it, then changing the user name, and persisitig it again (i.e merging it)
Does this change the previously entered user name? or does it create a new row in the db?
An Entity is roughly the same thing as an instance of a class when you are thinking from a code perspective or a row in a table (basically) when you are thinking from a database perspective.
So, it's essentially a persisted / persistable instance of a class. Changing values on it works just like changing values on any other class instance. The difference is that you can persist those changes and, in general, the current state of the class instance (entity) will overwrite the values the row for that instance (entity) had in the database, based on the primary key in the database matching the "id" or similar field in the class instance (entity).
There are exceptions to this behavior, of course, but this is true in general.
It's a model. It's a domain object that can be persisted. Don't over think it. Akin to a Rails model. And remember, models (in this paradigm) are mutable!

JPA EntityManager: merge() is trying to create a new row in the db - why?

I'm using JPA through the Play Framework.
I'm checking to see if a User object is cached, and if so I retrieve it and merge() it such that I can update fields and save the changes later:
user = (User) Cache.get("user-auth-" + sessionAuthToken);
if (user != null) {
user = user.merge(); // I believe this is the same as EntityManager.merge()
}
However when I do this I get the following error:
PersistenceException occured :
org.hibernate.exception.ConstraintViolationException:
could not insert: [models.User]
...
Caused by: com.mysql.jdbc.exceptions.jdbc4.
MySQLIntegrityConstraintViolationException:
Duplicate entry '1235411688335416533' for key 'authToken'
It seems like its trying to insert a new user, even though this user should be, and is already in the database. Why would merge() do that?
Or perhaps I'm going about this entirely the wrong way - advice would be appreciated.
I think it may be a poblem with hashCode() and equals(). If there are not implemented correctly, a new entity my be inserted instead of updateing an existing one.
I believe your problem is the way Play manages the JPA environment (and transactions).
Once you receive a request the framework immediately creates the JPA manager and a transaction. From that moment onwards all your Model entities are automatically linked to the manager.
Play facilitates working with this model in 2 ways:
You have to explicitly indicate that you want to save changes to an object (via save())
Transaction is committed automatically unless there is an exception or you flag it for rollback (JPA.setRollbackOnly())
By running "merge" you are trying to add to the Manager an entity which is already there, which causes the unique key exception. If you just load the entity from the cache, you will be able to modify and call save() once done, and it will work.
See What is the proper way to re-attach detached objects in Hibernate?. Merge tries to write the stale state to the db in order to overwrite possible other concurrent updates. The linked question mentions session.lock(entity, LockMode.NONE); as a possible solution, I haven't tried it though.
If authToken is not a primary key, then perhaps primary key of the User instance being merged doesn't match the primary key of its counterpart in the database, therefore merge() thinks that it's a new User and tries to insert it.
So, check the primary key of the User, perhaps it have been corrupted or lost somehow.
It's an entity definition problem; specifically with regard to primary key/ unsaved values.
The entity definition needs to be correct, for Hibernate to recognize it as 'already saved'. For example, having 'null' in a nullable version field can cause Hibernate to disregard any existing ID & regard it as unsaved.
This is a Hibernate question, not just JPA. JPA is the interface -- you're having trouble with a specific implementation.

Need to update the primary key on existing objects in GAE Java

I am building a web app using GAE Java. I have a class that uses a Long ID (generated by appengine) as its primary key.
I now want to create a new class that would be the parent class to this original class (a one to many relationship) however the child needs to have a primary key of type "key", not the Long ID I have now.
What is the best way to change the primary key to be type "key" instead of long for the existing persisted entities? Should I create a new class with primary key of type "key" and instantiate and persist new objects that copy the field values from the old ones? Or can I somehow just update the existing class?
Thanks
In fact, the Key of a persisted Entity is considered to be immutable. Changing the key will, without a doubt, be equivalent to changing the used instance. What I suggest you is to link your initial object to a child of you created parent.
You could store the existing Long IDs in a list in the parent class: that would create the necessary one-to-many parent-child relationship.
You would have to manage consistency yourself though (which may not be too difficult if your site doesn't have very high traffic), and the parent and child classes would not be in the same entity group (implications for transactions).
Changing the key means changing the Entity itself (and also its entity group).
Ultimately, the solution that works for you will depend on the specifics of your problem. For example, is there already a lot of existing data? Is this a live application (i.e., is it already being used)?
Another solution could be to migrate your app over to a different (better suited) data model, and do so account-by-account (by locking out the account for a brief period of time). This way only a few individuals will be affected by the change (if they happen to access the app when you are migrating their account) rather than the whole app being down.

Categories