Hibernate two versions of the same object - java

I have an entity that has been loaded from the database in a previous request, that is now modified. It is still detached in the persistence context.
When I'm submitting and entering my save() method, first entityManager.load() gets called to get the previous state of the object, make some comparisons, computations etc. (Im now working with entity and entityBefore)
Saving entity now results in an error. I'm trying to save a different object with the same id.
The solution at the moment is to just detach entityBefore and then use saveOrUpdate. Seemed to work like a charm.
However it only leads to another problem. The entity contains a list of other objects (1-n). Removing one of those from the list returns an error, they've previously been detached aswell.
At the moment I'm not sure what's the best approach to solve this whole thing. How can I manage 2 different versions of the same object, without storing both in the database? Is there a way I can get the old State from the database without modifying the context? Do I need to refresh every object in the list one by one?...
Thanks for any suggestions.

Related

How do I refresh hibernate object after changes made by stored procedure

In my grails application, we are calling a stored procedure that may update several thousands of records. After the stored-proc call, I need to send many of these records back to the UI in json format. But, hibernate continues to see the old object after the stored proc is complete. I have tried evict() on each of those objects and loaded those again using HQL, but no avail.
What is the best way out of this problem.
Answer lies in the question. :) Use refresh(). Refer this.
If you want to clear the hibernate session altogether then you can use session.clear(). Refer clear.
For that you would need to get hold of the current session, which you do in two ways:
Get hold of sessionFactory, get current session and clear the same.
grailsApplication.mainContext.sessionFactory.currentSession.clear()
Use withSession closure.
DomainABC.withSession{s-> s.clear()}

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

Merge or update persistence objects

I've got a hibernate interfaced mysql database with a load of different types of objects, some of which are periodically retrieved and altered by other pieces of code, which are operating in JADE agents. Because of the way the objects are retrieved (in queries, returning collections of objects) they don't seem to be managed by the entity manager, and definitely aren't managed when they're passed to agents without an entity manager factory or manager.
The objects from the database are passed about between agents, before arriving back at the database, at this point, I want to update the version of the object in the database - but each time I merge the object, it creates a new object in the database.
I'm fairly sure that I'm not using the merge method properly. Can anyone suggest a good way that I can combine the updated object with the existing database object without knowing in advance which properties of the object have changed? Possibly something along the lines of searching for the existing object and deleting it, then adding the new one, but I'm not sure how to do this without messing up PKeys etc
Hibernate has saveOrUpdate-method which either saves the object or updates it depending if an object with a same ID already exists:
http://docs.jboss.org/hibernate/core/3.3/reference/en/html/objectstate.html#objectstate-saveorupdate

StaleObjectstateException row was updated or deleted by

I am getting this exception in a controller of a web application based on spring framework using hibernate. I have tried many ways to counter this but could not resolve it.
In the controller's method, handleRequestInternal, there are calls made to the database mainly for 'read', unless its a submit action.
I have been using, Spring's Session but moved to getHibernateTemplate() and the problem still remains.
basically, this the second call to the database throws this exception. That is:
1) getEquipmentsByNumber(number) { firstly an equipment is fetched from the DB based on the 'number', which has a list of properties and each property has a list of values. I loop through those values (primitive objects Strings) to read in to variables)
2) getMaterialById(id) {fetches materials based on id}
I do understand that the second call, most probably, is making the session to "flush", but I am only 'reading' objects, then why does the second call throws the stale object state exception on the Equipment property if there is nothing changed?
I cannot clear the cache after the call since it causes LazyExceptions on objects that I pass to the view.
I have read this:
https://forums.hibernate.org/viewtopic.php?f=1&t=996355&start=0
but could not solve the problem based on the suggestions provided.
How can I solve this issue? Any ideas and thoughts are appreciated.
UPDATE:
What I just tested is that in the function getEquipmentsByNumber() after reading the variables from list of properties, I do this: getHibernateTemplate().flush(); and now the exception is on this line rather then the call to fetch material (that is getMaterialById(id)).
UPDATE:
Before explicitly calling flush, I am removing the object from session cache so that no stale object remains in the cache.
getHibernateTemplate().evict(equipment);
getHibernateTemplate().flush();
OK, so now the problem has moved to the next fetch from DB after I did this. I suppose I have to label the methods as synchronized and evict the Objects as soon as I am finished reading their contents! it doesn't sound very good.
UPDATE:
Made the handleRequestInternal method "synchronized". The error disappeared. Ofcourse, not the best solution, but what to do!
Tried in handleRequestInternal to close the current session and open a new one. But it would cause other parts of the app not to work properly. Tried to use ThreadLocal that did not work either.
You're mis-using Hibernate in some way that causes it to think you're updating or deleting objects from the database.
That's why calling flush() is throwing an exception.
One possibility: you're incorrectly "sharing" Session or Entities, via member field(s) of your servlet or controller. This is the main reason 'synchronized' would change your error symptoms.. Short solution: don't ever do this. Sessions and Entities shouldn't & don't work this way -- each Request should get processed independently.
Another possibility: unsaved-value defaults to 0 for "int" PK fields. You may be able to type these as "Integer" instead, if you really want to use 0 as a valid PK value.
Third suggestion: use Hibernate Session explicitly, learn to write simple correct code that works, then load the Java source for Hibernate/ Spring libraries so you can read & understand what these libraries are actually doing for you.
I also have been struggling with this exception, but when it continued to recur even when I put a lock on the object (and in a test environment, where I knew I was the only process touching the object), I decided to give the parenthetical in the stack trace its due consideration.
org.hibernate.StaleObjectStateException: Row was updated or deleted by
another transaction (or unsaved-value mapping was incorrect):
[com.rc.model.mexp.MerchantAccount#59132]
In our case it turned out that the mapping was wrong; we had type="text" in the mapping for one field that was a mediumtext type in the database, and it seems that Hibernate really hates that, at least under certain circumstances. We removed the type specification altogether from the mapping for this field, and the problem was resolved.
Now the weird thing is that in our production environment, with the supposedly problematic mapping in place, we do NOT get this exception. Does anybody have any idea why this might be? We are using the same version of MySQL - "5.0.22-log" (I don't know what the "-log" means) - in dev and production envs.
Here are 3 possibilities (as I do not know exactly, which kind of hibernate session handling you are using). Add one after another and test:
Use bi-directional mapping with inverse=true between parent object and child object, so the change in parent or child will get propagate to the other end of relation properly.
Add support for Optimistic Locking using TimeStamp or Version column
Use join query to fetch the whole object graph [ parent+children] together to avoid the second call altogether.
Lastly, if and only if nothing works:
Load the parent again by Id (you have that already) and populate modified data then update.
Life will be good! :)
This problem was something that I had experienced and was quite frustrating, although there has to be something a little odd going on in your DAO/Hibernate calls, because if you're doing a lookup by ID there is no reason to get a stale state, since that is just a simple lookup for an object.
First, make sure all your methods are annotated with #Transaction(required=true) // you'll have to look up the exact syntax
However, this exception is usually thrown when you try to make changes to an object that has been detached from the session it was retrieved from. The solution to this is often not simple and would require more code posted so we can see exactly what is going on; my general suggestion would be to create a #Service that performs these kinds of things within a single transaction

updating "nested" objects with JDO on Google App Engine

I'm having trouble figuring out the proper way to update "nested" data using Google App Engine
and JDO. I have a RecipeJDO and an IngredientJDO.
I want to be able to completely replace the ingredients in a given recipe instance with a new list of ingredients. Then, when that recipe is (re)persisted, any previously attached ingredients will be deleted totally from the datastore, and the new ones will be persisted and associated with the recipe.
Something like:
// retrieve from GAE datastore
RecipeJDO recipe = getRecipeById();
// fetch new ingredients from the user
List<IngredientJDO> newIngredients = getNewIngredients();
recipe.setIngredients(newIngredients);
// update the recipe w/ new ingredients
saveUpdatedRecipe(recipe);
This works fine when I update (detached) recipe objects directly, as returned from the datastore. However if I copy a RecipeJDO, then make the aforementioned updates, it ends up appending the new ingredients, which are then returned along with the old ingredients when the recipe is then re-fetched from the datastore. (Why bother with the copy at all? I'm using GWT on the front end, so I'm copying the JDO objects to DTOs, the user edits them on the front end, and then they are sent to the backend for updating the datastore.)
Why do I get different results with objects that I create by hand (setting all the fields, including the id) vs operating on instances returned by the PersistenceManager? Obviously
JDO's bytecode enhancement is involved somehow.
Am I better off just explicitly deleting the old ingredients before persisting the updated
recipe?
(Side question- does anyone else get frustrated with ORM and wish we could go back to plain old RDBMS? :-)
Short answer. Change RecipeJDO.setIngredients() to this:
public void setIngredients(List<IngredientJDO> ingredients) {
this.ingredients.clear();
this.ingredients.addAll(ingredients);
}
When you fetch the RecipeJDO, the ingredients list is not a real ArrayList, it is a dynamic proxy that handles the persistence of the contained elements. You shouldn't replace it.
While the persistence manager is open, you can iterate through the ingredients list, add items or remove items, and the changes will be persisted when the persistence manager is closed (or the transaction is committed, if you are in a transaction). Here's how you would do the update without a transaction:
public void updateRecipe(String id, List<IngredientDTO> newIngredients) {
List<IngredientJDO> ingredients = convertIngredientDtosToJdos(newIngredients);
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
RecipeJDO recipe = pm.getObjectById(RecipeJDO.class, id);
recipe.setIngredients(ingredients);
} finally {
pm.close();
}
}
If you never modify the IngredientJDO objects (only replace them and read them), you might want to make them Serializable objects instead of JDO objects. If you do that, you may be able to reuse the Ingredient class in your GWT RPC code.
Incidentally, even if Recipe was not a JDO object, you would want to make a copy in the setIngredients() method, otherwise someone could do this:
List<IngredientJDO> ingredients = new ArrayList<IngredientJDO>;
// add items to ingredients
recipe.setIngredients(ingredients);
ingredients.clear(); // Woops! Modifies Recipe!
I am facing the same problem!
I would like to update an existing entity by calling makePersistent() and assigning an existent id/key! the update works fine except for nested objects! The nested objects are appended to the old ones instead of being replaced? I don't know if this is the intended behaviour or if this is a bug? I expect overwriting to have the same effect as inserting a new entity!
How about first deleting the old entity and persisting the new one in the same transaction? Does this work? I tried this but it resulted in deleting the entity completely?! I don't know why (even though I tried flushing directly after deleting)!
#NamshubWriter, not sure if you'll catch this post... regarding your comment,
(if you used Stripes and JSP, you could avoid the GWT RPC and GWT model representations of Recipe and Ingredient)
I am using Stripes and JSP, but I face the same problem. When the user submits the form back, Stripes instantiates my entity objects from scratch, and so JDO is completely ignorant of them. When I call PersistenceManager.makePersistent on the root object, the previous version is correctly overwritten - with one exception, its child objects are appended to the List<child> of the previous version.
If you could suggest any solution (better than manually copying the object fields) I would greatly appreciate.
(seeing as Stripes is so pluggable, I wonder if I can override how it instantiates the entity objects...)

Categories