I have one class with specific columns, say
Class A
{
private String A;
private String B;
private String C;
// Getter Setter of respectives
}
Now what happened I have same value of column A and column B only column C's value change. So I do something like below
A a = new A();
a.setA(..);
a.setB(..);
for(i=0;i<length;i++){
a.setC(..);
getHibernateTemplate.saveOrUpdate(a);
// or something like this
// A a1 = new A();
// a1 = a;
// a1. setC(..);
// getHibernateTemplate.saveOrUpdate(a1);
}
My issue is it does not store length number of records, it only updates that single record.
I know the reason that hibernate access it as persistent object and even if I change value and again save it will update existing record and it can be resolve by taking new object every time and setting it all values. But I don't want it, is there any way to tell hibernate to save that record instead of updating?
You haven't described actual entity details. If you want to save entity with the same values, set the identifier property as null.
From Documentation -
saveOrUpdate()
if the object is already persistent in this session, do nothing
if another object associated with the session has the same
identifier, throw an exception
if the object has no identifier property, save() it
if the object's identifier has the value assigned to a newly
instantiated object, save() it
if the object is versioned by a or , and the
version property value is the same value assigned to a newly
instantiated object, save() it
otherwise update() the object
saveOrUpdateAll()
Save or update all given persistent instances, according to its id (matching the configured "unsaved-value"?). Associates the instances with the current Hibernate Session.
[If it works, can try this for your other query]
Edit : It's mine oversight, I haven't checked your code carefully.
You have defined object A outside for loop, therefore the same object was being updated in each iteration. Try the below code, might help.
for(i=0;i<length;i++){
A a = new A(); //-- Create new object for each iteration
a.setA(..);
a.setB(..);
a.setC(..);
getHibernateTemplate.saveOrUpdate(a);
}
Yes.Try save(a) instead of saveOrUpdate(a)
getHibernateTemplate.save(a); //each time a new object saves.
Related
I am facing a scenario where, I need to update the parameter and want to retrieve the modified value within same transaction
For example :
#Transactional(propagation = Propagation.REQUIRED)
public void modifiyParameter(Object object, BigInteger attribute_id) {
...
Attribute attrValue = object.getParameter(attribute_id);
attrValue.setValue("new_value");
object.setParameter(attr_id, attrValue);
...
object.getParameter(attribute_id); //getting old value instead of modified value
}
In the above case, It would return the old value itself, but I tried to wrap in separate transaction and I could able to retrieve the modified value.
My question is that, can't we retrieve the modified value from the bean itself within same transaction, instead of committing the inner transaction (i.e new transaction) and retrieving it from DB?
If you have the value then why you want to fetch the value from DB, Use the same value. That is a good design from a performance and maintainability perspective.
for(int index=0; index<10; index++) {
Session session = hibernateTemplate.getSessionFactory().openSession();
session.save(object);
}
Does this code store the passed object in save(object) in DB 10 times or it will be overridden every time?
It depends on the object's state.
If you create a new object each time, new object is in the transient state: it is not mapped to a database record and not managed by any persistence context. So, calling Hibernate's save() method will create a new record in the database.
But if you call save() method with a managed object which is already attached to the current persistence context and mapped to a database record: the same object will be updated.
save method in hibernate:
*Persist the given transient instance, first assigning a generated identifier. (Or
using the current value of the identifier property if the assigned
generator is used.) This operation cascades to associated instances if the
association is mapped with cascade="save-update"
Accept parameters :#param object a transient instance of a persistent class
Return Prameters : #return the generated identifier*
In summary, the save() method saves records into the database by INSERT SQL query, Generates a new identifier, and returns the Serializable identifier back. So you will have 10 Object record in your database with different Ids
Read more: https://javarevisited.blogspot.com/2012/09/difference-hibernate-save-vs-persist-and-saveOrUpdate.html#ixzz6F8Hiy8fF
Hope it helps.
I would like to know how Hibernate session identifies whether an object is already present in DB or not.
Because in my case a new record is always saved and not updated.
As of I know, hibernate Session will get identify the object based on the Primary Key column. Let's say for example, ID is the primary key column in a table and you have set some value to the ID parameter of passing object. Session will check in the mapped table ID value exist or not. If exists, it will call the update(object) otherwise save(object) methods accordingly.
For more information refer this documentation link.
The reason why, you always end up with a save on a new record is because the persistence provider is always treating that object as TRANSIENT. And when one is passsed to save or update, it is not yet in the persistence context and hibernate tries to generate an id for it (if #GeneratedValue is used) and add that object / entity to the persistence context from which point it has become managed.
This is the snippet from the 5.x hibernate impl:
public class DefaultSaveEventListener extends DefaultSaveOrUpdateEventListener {
protected Serializable performSaveOrUpdate(SaveOrUpdateEvent event) {
EntityEntry entry = event.getSession().getPersistenceContext().getEntry( event.getEntity() );
if ( entry!=null && entry.getStatus() != Status.DELETED ) {
return entityIsPersistent(event);
}
else {
return entityIsTransient(event);
}
}
in your case the EntityEntry entry is resolved as null and entityIsTransient(event); is invoked. Which contains this:
Serializable id = saveWithGeneratedOrRequestedId( event );
source.getPersistenceContext().reassociateProxy( event.getObject(), id );
which is exactly what i pointed out before.
I have several classes, all of which have an ID field declared as Integer the next way:
#Expose
#DatabaseField(columnName = "_id", id = true)
private Integer idField;
Everything compiles and runs correctly, but when I simply try to check if a record exists:
Integer idField = 1;
result = DBHelper.getHelper().getClassDAO().idExists(idField);
I get the exception:
java.sql.SQLException: Field '_id' is of data type null which can not be compared
The thing is that with one class (let's name it A) the method works properly, but with the others fail and I don't know which is the cause because all the classes have its ID field declared the same way.
I'm getting this exception too if I try to createOrUpdate the object of any class, except the refered class A.
Any helping hand would be appreciated.
NOTE. The project uses an ormlite_config.txt file, which is updated.
After a few hours debugging I came into that the mentioned exception comes only when the class to be saved has one o more collections. As far as I know, the exception is thrown inside the idExists method of the Dao class. Having in mind that the createOrSave method surely must call it, that's why I get the SQLException in both cases.
And now, the workaround to solve this. Rather than invoking the idExists method, I had to create my own like this:
return DBHelper.getHelper().getMyDAO().queryForId(idField) != null;
And instead of calling the createOrUpdate method, first I check if the record exists and then, depending on the result, I call the create or update method of the Dao class I want to persist.
I have the following simple code:
#Test
public void saveExpense() {
// Create dummy Expense object i.e. { "description": "Short Description", "date": etc }
Expense expenseToSave = ExpenseHelper.createExpense("Short Description", new Date(), user);
Expense savedExpense = expenseService.save(expenseToSave);
// What is strange, is that here, both expenseToSave and savedExpense have id set to 1 for example; after save the expense should have an id;
Expense expected = ExpenseHelper.createExpense("Short Description", new Date(), user);
// Check if expected object is equal to the saved one
Assert.assertTrue(expected.equals(expenseService.findByDescription("Short Description")));
}
Normally I would expect that expenseToSave to be without id and savedExpense with id, but both have id after save. Why?
That made another variable to be necessary and complicate the test.
Thanks.
That's just how the Hibernate Session.save() method is specified. From the documentation:
Persist the given transient instance, first assigning a generated
identifier. (Or using the current value of the identifier property if
the assigned generator is used.) This operation cascades to associated
instances if the association is mapped with cascade="save-update".
IDs are the mechanism how Hibernate differentiates between persisted and transient objects, and how it identifies specific objects. Therefore, the ID is set early in the persistence step, as for example cyclic references in an object tree are resolved via IDs while persisting.
What differentiates the returned object vs. the original object is that the returned object is attached to the Hibernate session. For example, with active cascading, contained entities (e.g. in a one-to-many collection) are now persistent instances as well in the returned object.
Please be aware that
void EntityManager#persist(java.lang.Object entity)
(http://docs.oracle.com/javaee/6/api/javax/persistence/EntityManager.html#persist%28java.lang.Object%29)
Persists the given object by changing the object passed in and does not return a persisted copy - I suspect your ExpenseHelper to return the original object additionally so that you receive the same object via return as you already have by passing it in.
This follows a common anti-pattern for a kind of unified behaviour of DAO to be something like
public T create(T entity) {
this.entityManager.persist(entity);
return entity;
}
to get a kind of synchronicity with saving something
public T save(T entity) {
return this.entityManager.merge(entity);
}
Where
<T> T EntityManager#merge(T entity)
does indeed merge and pass you the merged entity.
It can depend on Hibernate mapping of the Expense entity, or implementation of ExpenseHelper class.
Also, take a look on Expense.equals() implementation.
Based on this statement:
Expense savedExpense = expenseService.save(expenseToSave);
the value of the savedExpense object will depend on what your are doing in the save method. Usually save methods don't return an object. You already have a reference to the object that you just saved (expenseToSave) available to you. And you are trying to assert that your expected object equals the object that was saved, which is fine. So I am not sure what the purpose of returning an object in expenseService.save(expenseToSave)
Also, note that the id of the object expenseToSave would have been populated by your ORM (Hibernate, I assume) based on your configuration, when you save it. There is no need to return this object or another object in the save method.