Clear object on ViewScope destroy - java

Well, I changed my application FlushMode from AUTO to COMMIT, because i don't want to update or insert new objects from dirty-check hibernate.
I will try explain my problem with a scenario:
I have a ManagedBean (CustomerMB) linked with a XHTML (customer.xhtml) page, this ManagedBean is "ViewScoped" and have a object called "bean" (Customer.class type).
User starts to change information about Customer (like name, age, address and others), and this values are set into "bean" object. But for some unknown reason, user decide to click "F5" (refresh browser) and ViewScoped is destroyed and another is created (i think so).
In this moment i expect that all informations about "Customer" was lost (this is correct for me) and user must start again the changes of this Customer. But the opposite happens, the "bean" object continue with all information in cache, and if i change my XHTML page to another managedBean the "bean" object also continue in cache and i don't want this.
I tried to set "bean = null" in my ManagedBean but when i do a "SELECT * FROM Customer c WHERE c.id = :id" the "customer" object is returned with new value (typed by user) and not equal Database as i expected, i don't know why.

Related

Hibernate Update Exception: a different object with the same identifier value was already associated with the session [duplicate]

I have two user Objects and while I try to save the object using
session.save(userObj);
I am getting the following error:
Caused by: org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session:
[com.pojo.rtrequests.User#com.pojo.rtrequests.User#d079b40b]
I am creating the session using
BaseHibernateDAO dao = new BaseHibernateDAO();
rtsession = dao.getSession(userData.getRegion(),
BaseHibernateDAO.RTREQUESTS_DATABASE_NAME);
rttrans = rtsession.beginTransaction();
rttrans.begin();
rtsession.save(userObj1);
rtsession.save(userObj2);
rtsession.flush();
rttrans.commit();
rtsession.close(); // in finally block
I also tried doing the session.clear() before saving, still no luck.
This is for the first I am getting the session object when a user request comes, so I am getting why is saying that object is present in session.
Any suggestions?
I have had this error many times and it can be quite hard to track down...
Basically, what hibernate is saying is that you have two objects which have the same identifier (same primary key) but they are not the same object.
I would suggest you break down your code, i.e. comment out bits until the error goes away and then put the code back until it comes back and you should find the error.
It most often happens via cascading saves where there is a cascade save between object A and B, but object B has already been associated with the session but is not on the same instance of B as the one on A.
What primary key generator are you using?
The reason I ask is this error is related to how you're telling hibernate to ascertain the persistent state of an object (i.e. whether an object is persistent or not). The error could be happening because hibernate is trying to persist an object that is already persistent. In fact, if you use save hibernate will try and persist that object, and maybe there is already an object with that same primary key associated with the session.
Example
Assuming you have a hibernate class object for a table with 10 rows based on a primary key combination (column 1 and column 2). Now, you have removed 5 rows from the table at some point of time. Now, if you try to add the same 10 rows again, while hibernate tries to persist the objects in database, 5 rows which were already removed will be added without errors. Now the remaining 5 rows which are already existing, will throw this exception.
So the easy approach would be checking if you have updated/removed any value in a table which is part of something and later are you trying to insert the same objects again
This is only one point where hibernate makes more problems than it solves.
In my case there are many objects with the same identifier 0, because they are new and don't have one. The db generates them. Somewhere I have read that 0 signals Id not set. The intuitive way to persist them is iterating over them and saying hibernate to save the objects. But You can't do that - "Of course You should know that hibernate works this and that way, therefore You have to.."
So now I can try to change Ids to Long instead of long and look if it then works.
In the end it's easier to do it with a simple mapper by your own, because hibernate is just an additional intransparent burden.
Another example: Trying to read parameters from one database and persist them in another forces you to do nearly all work manually. But if you have to do it anyway, using hibernate is just additional work.
USe session.evict(object); The function of evict() method is used to remove instance from the session cache. So for first time saving the object ,save object by calling session.save(object) method before evicting the object from the cache. In the same way update object by calling session.saveOrUpdate(object) or session.update(object) before calling evict().
This can happen when you have used same session object for read & write. How?
Say you have created one session.
You read a record from employee table with primary key Emp_id=101
Now You have modified the record in Java.
And you are going to save the Employee record in database.
we have not closed session anywhere here.
As the object that was read also persist in the session. It conflicts with the object that we wish to write. Hence this error comes.
As somebody already pointed above i ran into this problem when i had cascade=all on both ends of a one-to-many relationship, so let's assume A --> B (one-to-many from A and many-to-one from B) and was updating instance of B in A and then calling saveOrUpdate(A) , it was resulting in a circular save request i.e save of A triggers save of B that triggers save of A... and in the third instance as the entity( of A) was tried to be added to the sessionPersistenceContext the duplicateObject exception was thrown. I could solve it by removing cascade from one end.
You can use session.merge(obj), if you are doing save with different sessions with same identifier persistent object.
It worked, I had same issue before.
I ran into this problem by:
Deleting an object (using HQL)
Immediately storing a new object with the same id
I resolved it by flushing the results after the delete, and clearing the cache before saving the new object
String delQuery = "DELETE FROM OasisNode";
session.createQuery( delQuery ).executeUpdate();
session.flush();
session.clear();
This problem occurs when we update the same object of session, which we have used to fetch the object from database.
You can use merge method of hibernate instead of update method.
e.g. First use session.get() and then you can use session.merge (object). This method will not create any problem. We can also use merge() method to update object in database.
I also ran into this problem and had a hard time to find the error.
The problem I had was the following:
The object has been read by a Dao with a different hibernate session.
To avoid this exception, simply re-read the object with the dao that is going to save/update this object later on.
so:
class A{
readFoo(){
someDaoA.read(myBadAssObject); //Different Session than in class B
}
}
class B{
saveFoo(){
someDaoB.read(myBadAssObjectAgain); //Different Session than in class A
[...]
myBadAssObjectAgain.fooValue = 'bar';
persist();
}
}
Hope that save some people a lot of time!
Get the object inside the session, here an example:
MyObject ob = null;
ob = (MyObject) session.get(MyObject.class, id);
By default is using the identity strategy but I fixed it by adding
#ID
#GeneratedValue(strategy = GenerationType.IDENTITY)
Are your Id mappings correct? If the database is responsible for creating the Id through an identifier, you need to map your userobject to that ..
Check if you forgot to put #GenerateValue for #Id column.
I had same problem with many to many relationship between Movie and Genre. The program threw
Hibernate Error: org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session
error.
I found out later that I just have to make sure you have #GenerateValue to the GenreId get method.
I encountered this problem with deleting an object, neither evict nor clear helped.
/**
* Deletes the given entity, even if hibernate has an old reference to it.
* If the entity has already disappeared due to a db cascade then noop.
*/
public void delete(final Object entity) {
Object merged = null;
try {
merged = getSession().merge(entity);
}
catch (ObjectNotFoundException e) {
// disappeared already due to cascade
return;
}
getSession().delete(merged);
}
before the position where repetitive objects begin , you should close the session
and then you should start a new session
session.close();
session = HibernateUtil.getSessionFactory().openSession();
so in this way in one session there is not more than one entities that have the same identifier.
I had a similar problem. In my case I had forgotten to set the increment_by value in the database to be the same like the one used by the cache_size and allocationSize. (The arrows point to the mentioned attributes)
SQL:
CREATED 26.07.16
LAST_DDL_TIME 26.07.16
SEQUENCE_OWNER MY
SEQUENCE_NAME MY_ID_SEQ
MIN_VALUE 1
MAX_VALUE 9999999999999999999999999999
INCREMENT_BY 20 <-
CYCLE_FLAG N
ORDER_FLAG N
CACHE_SIZE 20 <-
LAST_NUMBER 180
Java:
#SequenceGenerator(name = "mySG", schema = "my",
sequenceName = "my_id_seq", allocationSize = 20 <-)
Late to the party, but may help for coming users -
I got this issue when i select a record using getsession() and again update another record with same identifier using same session causes the issue. Added code below.
Customer existingCustomer=getSession().get(Customer.class,1);
Customer customerFromUi;// This customer details comiong from UI with identifer 1
getSession().update(customerFromUi);// Here the issue comes
This should never be done . Solution is either evict session before update or change business logic.
just check the id whether it takes null or 0 like
if(offersubformtwo.getId()!=null && offersubformtwo.getId()!=0)
in add or update where the content are set from form to Pojo
I'm new to NHibernate, and my problem was that I used a different session to query my object than I did to save it. So the saving session didn't know about the object.
It seems obvious, but from reading the previous answers I was looking everywhere for 2 objects, not 2 sessions.
#GeneratedValue(strategy=GenerationType.IDENTITY), adding this annotation to the primary key property in your entity bean should solve this issue.
I resolved this problem .
Actually this is happening because we forgot implementation of Generator Type of PK property in the bean class. So make it any type like as
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
when we persist the objects of bean ,every object acquired same ID ,so first object is saved ,when another object to be persist then HIB FW through this type of Exception: org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session.
The problem happens because in same hibernate session you are trying to save two objects with same identifier.There are two solutions:-
This is happening because you have not configured your mapping.xml file correctly for id fields as below:-
<id name="id">
<column name="id" sql-type="bigint" not-null="true"/>
<generator class="hibernateGeneratorClass"</generator>
</id>
Overload the getsession method to accept a Parameter like isSessionClear,
and clear the session before returning the current session like below
public static Session getSession(boolean isSessionClear) {
if (session.isOpen() && isSessionClear) {
session.clear();
return session;
} else if (session.isOpen()) {
return session;
} else {
return sessionFactory.openSession();
}
}
This will cause existing session objects to be cleared and even if hibernate doesn't generate a unique identifier ,assuming you have configured your database properly for a primary key using something like Auto_Increment,it should work for you.
Otherwise than what wbdarby said, it even can happen when an object is fetched by giving the identifier of the object to a HQL. In the case of trying to modify the object fields and save it back into DB(modification could be insert, delete or update) over the same session, this error will appear. Try clearing the hibernate session before saving your modified object or create a brand new session.
Hope i helped ;-)
I have the same error I was replacing my Set with a new one get from Jackson.
To solve this I keep the existing set, I remove from the old set the element unknown into the new list with retainAll.
Then I add the new ones with addAll.
this.oldSet.retainAll(newSet);
this.oldSet.addAll(newSet);
No need to have the Session and manipulate it.
Try this. The below worked for me!
In the hbm.xml file
We need to set the dynamic-update attribute of class tag to true:
<class dynamic-update="true">
Set the class attribute of the generator tag under unique column to identity:
<generator class="identity">
Note: Set the unique column to identity rather than assigned.
I just had the same problem .I solve it by adding this line:
#GeneratedValue(strategy=GenerationType.IDENTITY)
Another thing that worked for me was to make the instance variable Long in place of long
I had my primary key variable long id;
changing it to Long id; worked
All the best
You always can do a session flush.
Flush will synchronize the state of all your objects in session (please, someone correct me if i'm wrong), and maybe it would solve your problem in some cases.
Implementing your own equals and hashcode may help you too.
You can check your Cascade Settings. The Cascade settings on your models could be causing this. I removed Cascade Settings (Essentially not allowing Cascade Inserts/Updates) and this solved my problem
I found this error as well. What worked for me is to make sure that the primary key (that is auto-generated) is not a PDT (i.e. long, int, ect.), but an object (i.e. Long, Integer, etc.)
When you create your object to save it, make sure you pass null and not 0.

Grails: getting old instance after persisting

I'm facing a weird issue in Grails. When I make a findBy call after changing and saving values of a domain, I am still getting the old values even after the values get persisted to the database. I can see the values are changed in my table.
My code is something like this:
Car car = Car.findByCarId(carId)
car.modelName = "some_model_name"
car.save() // Not flushing here
Tire tire = Tire.findByIdAndCarId(tireId,carId)
tire.manufacturer = "some_manufacturer"
tire.save()
Light light = Light.findByIdAndCarId(lightId,carId)
light.manufacturer = "some_manufacturer"
light.save()
Mirror mirror = Mirror.findByIdAndCarId(mirrorId,carId)
mirror.manufacturer = "some_manufacturer"
mirror.save()
My domain also has a few one-to-many associations. Let's say something like this:
class Car {
String modelName
static hasMany = [tires : Tire, mirrors : Mirror, lights : Light]
}
After these changes, when I make a DB call for the Car domain, I still get the older values:
Car car = Car.findById(carId)
println car.modelName // This gives older value
I know this is because the values are yet to be persisted to the database. I want to know if I use car.save(flush: true) in the above code, will it cause collection was not processed by flush() error? However, I am also getting the older values even after the values are persisted to the database. (e.g. when I make the above query after a long time) I can see the values are changed in my tables, but when I do the above query, it gives me the old values. Does Hibernate cache this query automatically? I use the above query quite a lot of times.
When I use withNewSession, it retrieves the new values:
Car car
Car.withNewSession {
car = Car.findById(carId,[readOnly : true])
}
println car.modelName // Gives new value
I want to know how this is giving the new values everytime, since I'm not flushing the current session. Instead, I'm only using a new Hibernate session. Does readOnly command flush the current session? The above code works fine for me. Should I use withNewSession instead of flushing while saving?
Thanks.
All your business logic has to be inside a transactional service. All services in grails are transactional by default. Take care about notations as #Transactional or #NotTransactional
If you want to manage data in a controller (not recommended) you should surround your code into a Transaction. An allow hibernate to manage the transaction, not breaking it with flush.
All changes are commited after a transaction finishes.
Remember that you could also use the refresh method which re-reads the state of the given instance from the underlying database.
domainInstance.refresh()

Change update insert attributes programmatically

I would like to know if it's posible to change the insert and update attributes of a property defined in the mapping of a Class.
This is because in one scenario I need to update a property (or properties), but not in another, it's posible?
Thanks in advance
EDIT: Lets say that I've the Class User(with name, surname and loginDate), when the user logs into the app, I need to update only loginDate. But the administrator of the system must be able to edit the name and the surname of the User.
The only other solution that ocurrs to me is to use HQL for a Update (or in the worst case SQL), but I want if it's posible to modify that attributes.
EDIT 2: after reading Java persistence with hibernate and some forum threads I found that once the sessionFactory is created the mappings are immutables, and though You can change the properties programmatically, You need to create a new sessionFactory
// this is what the login screen calls
void updateLoginDate(Date date)
{
User user = session.get(User.class);
user.setDate(date);
session.Flush();
}
and in the mapping you could specify dynamicUpdate = true on the class so that the generated sql only updates columns which have changed

object is an unsaved transient instance - save the transient instance before merging

I have a form to add new Appartments, and in this form I have a dropdown where the user can choose what Person is responsible.
Apparantly my application thinks that the Person is modified when you select from the dropdown and try to save the Appartment. And it gives me the error below indicating i should save the Person first. But the Person is not modified. It is only the Appartment that should be saved with a reference to a different Person.
object is an unsaved transient instance - save the transient instance before merging
How can I make my application understand that the Person himself has not been modified. Only the Appartment?
Here is my code:
#Entity
#Table(name = "Person")
public class Person{
#Id
private Long id;
private String fullName;
....
}
#Entity
#Table(name = "Appartment")
public class Appartment{
....
#ManyToOne (fetch = FetchType.LAZY)
#JoinColumn (name = "client_contact_person_id")
private Person clientResponsiblePerson;
}
The action loads all Persons into a List responsiblePersons.
And the JSP:
<s:select name="appartment.clientResponsiblePerson.id" list="responsiblePersons"
listKey="id" listValue="fullName" headerKey="-1"
label="%{getText('appartment.clientContact.ourContact')}" headerValue="%{getText('person.choose')}"
required="true" cssClass="select medium" />
Any ideas? I've been searching and debugging for hours without any solution... :(
UPDATE:
Steven suggested that i remove the id from appartment.clientResponsiblePerson.id. This is a reasonable suggestion. I did just try it, but then it seems like my Application dont know how to map the value submitted by the form to a Person-object. As im setting listKey="id" the value submitted is the Person's ID.
I recieve the following errors:
Invalid field value for field "appartment.clientResponsiblePerson".
tag 'select', field 'list', name 'appartment.clientResponsiblePerson': The requested list key 'responsiblePeople' could not be resolved as a collection/array/map/enumeration/iterator type. Example: people or people.{name} - [unknown location]
So my initial thought was that maybe i should delete the listKey and listValue from my s:select. Maybe struts automagically detects the id from the object and uses toString for value? But I tried this as well without any more luck.
Another really strange thing is that I do the exact same thing in another form. In that form i am selecting Areas from a dropdown. And I am using appartment.area.id for name. And it works perfectly there. Strange.. I also checked that the Area - Appartment reference was not set up to automaticly persist or merge.
It strikes me that what i am trying to achive should be really straigh forward. What is it that i am not getting here?
Apparantly my application thinks that the Person is modified when you select from the dropdown and try to save the Appartment.
That's exactly what your code is doing. The following line is the culprit:
appartment.clientResponsiblePerson.id
That is telling the Struts2 framework to take the id of the person you selected in your drop down and pass it to getAppartment().getClientResponsiblePerson().setId(id). That doesn't change to a new responsible person, it changes the primary key for the existing person. Calling setClientResponsiblePerson(Person) would change the person.
Try using appartment.clientResponsiblePerson instead and see how that works for you.
Update
Another really strange thing is that I do the exact same thing in another form.
I don't see how that would work either.
Struts2 doesn't know what a Person is, so you have a few options:
Create a type converter to tell Struts2 how to convert from "1" (or whatever is passed in from your dropdown) to an instance of a Person.
Add a setPerson(Integer) method on your action which will look up the appropriate Person entity based on the Integer primary key passed in and then update your s:select to <s:select name="person" list="responsiblePersons" .../>
Personally, I use #1.

Hibernate cascade + composite id's issue

I'm currently learning Hibernate, and I've stumbled into this issue:
I have defined 3 entities: User, Module, Permission. Both user and module have a one-to-many relationship with Permission, so that Permission's composite id consists of idUser and idModule. The user class has a property that is a set of Permission's and it is appropriately annotated with #OneToMany, cascade=CascadeType.ALL, etc.
Now, I generated the classes with MyEclipse's reverse engineering feature. The id of permission was created as a separate class that has an idUser and idModule property. I thought I could create a User, add some new permissions to it, and thus saving the user would cascade the operation, and permissions would be saved automatically. This is true except that the operation causes an exception. I run the following code:
Permission p = new Permission();
p.setId(new PermissionId(null, module.getId());
user.getPermissions().add(p);
session.save(user);
The problem I have is that, even though the SQL is being generated correctly (first saves User, then Permission), I get an error from the database driver (Firebird) which states that it can't insert a null value for idUser, which is true, but shouldn't hibernate be passing the newly created user id to the second query?
This particular scenario feels very counter-intuitive to me since I'm inclined to pass a null id to the Permission object since it is new and I want it to be created, but on other hand, I have to set the idModule property since the module already exists, so I don't really understand how an operation like this is supposed to work.
Does anyone know what I'm doing wrong? Thanks
You need to specify a cascade action for Hibernate to perform when you save a User with an attached transient (meaning not-yet-saved) Permission.
By the way, you might want to consider using a different ID strategy for the Permission object, such as a generated ID value - how can the primary key of the permission row in the database contain a null value?

Categories