java/Spring Hibernate not updating entities - java

I have read and reread everything here on SO and many other sites but can't seem to figure out why my updated objects are not updating.
The basic overview of what I'm doing:
Service layer asks DAO for some People
Return an ArrayList of People from the DB (DAO / #Repository)
Service Layer manipulates object and adds them to a new arraylist
Service Layers passes new list back to DAO to update
NOTHING GETS Updated
If I throw a log message in my object has the new values, the children are correctly hydrated. I get no errors in the code is just doesn't commit my changes.
Here is some code:
PersonDAO annotated as #Repository
public void updatePeople(List<Person> people) {
log.info("Updating " + people.size() + " people");
try {
Transaction tx = getCurrentSession().beginTransaction();
for (Person person : people){
getCurrentSession().saveOrUpdate(person);
}
getCurrentSession().flush();
tx.commit();
getCurrentSession().close();
} catch (Exception e){
log.error("Exception Updating all people " + e.toString());
e.printStackTrace();
}
}
public List<Person> getAssociatesByStoreId(String storeId) {
try {
List<Person> usersInStore = (List<Person>) getCurrentSession()
.createCriteria(Person.class).createCriteria("store")
.add(Restrictions.eq("storeId", storeId)).list();
return usersInStore;
} catch (Exception e) {
log.error("exception in getAssociatesByStoreId ", e);
}
return null;
}
PersonService annotated as #Service - relevant method
/* I put the people into a map to do some other logic on them */
for (Person person : personDAO.getAllPeople()){
personMap.put(person.getEmployeeId() + "-" + person.getStore().getStoreId(), person);
}
/*
I iterate a list creating new Person objects (based on some random stuff),
including saving any children entities (managementcodes and stores) that need to be created
After I have created a new Person I attempt to find it in the map from above.
If I find it pull it out of the map and put it into an array list
that is eventually passed back into the DAO
*/
Person annotated as #Entity
private int personid;
private String firstName;
private String lastName;
private Store store;
private ManagementCode managementCode;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name = "personid", unique = true, nullable = false)
public int getPersonid() {
return this.personid;
}
/*a bunch of getters and setters*/
#ManyToOne(fetch = FetchType.LAZY, optional = true, cascade = {CascadeType.MERGE, CascadeType.PERSIST})
#org.hibernate.annotations.Cascade( {org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.PERSIST})
#LazyCollection(LazyCollectionOption.EXTRA)
#JoinColumn(name = "managementlevel", nullable = true)
public ManagementCode getManagementCode() {
return this.managementCode;
}
#ManyToOne(fetch = FetchType.LAZY, optional = true, cascade = {CascadeType.MERGE, CascadeType.PERSIST})
// #org.hibernate.annotations.Cascade( {org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.PERSIST})
#JoinColumn(name = "storeid", nullable = false)
public Store getStore() {
return this.store;
}
Store annotated as entity (Managementcode is the same)
/*fields + getters and setter */
#OneToMany(fetch = FetchType.LAZY, mappedBy = "store", cascade = {CascadeType.MERGE, CascadeType.PERSIST})
#LazyCollection(LazyCollectionOption.EXTRA)
#JsonIgnore
public Set<Person> getPersons() {
return this.persons;
}
EDIT I added both sets of Cascade type annotations above and still no luck
EDIT 2 Updated the to show the primary key definition
Someone please help me before I kick a puppy.
Thanks

There are three main types of entity objects with JPA:
Managed. These are the objects that are cached by JPA-provider, so the JPA-provider keeps track of their states, and commits any changes made to them when the transaction commits. These are the objects you get when you query. They have a database id.
New. These are entity objects that are not yet persisted in the database. The JPA-provider knows nothing about them. They do not have a database id.
Detached. These are objects that used to be managed, but no longer are. Typically, objects that are returned to a method that is outside the transaction. These object have a database id, but they are not part of the cache, so the JPA-provider does not know them.
In order to persist a relationship between an entity and another, the referenced entity has to managed. There are multiple ways of achieving this.
Cascade. Cascade from entity A to entity B means that when a cascading operation is performed on entity A by you in your code, the JPA-provider will perform the same operation on entity B. If you add CascadeType.MERGE to the relationship, and have entity A reference a detached entity B, then doing a merge() on entity A will first to a merge() on entity B, making it managed. When entity A is then stored, it has a reference to a managed B, and the relationship is persisted. (If you also want to persist references to objects that are not already in the database, add CascadeType.PERSIST as well.)
Making sure you only reference managed objects. Inside your transaction, load the referenced objects (the managed ones) and replace the references with managed objects, before storing.
Widen your transaction. That way, the referenced objects will never become detached.

It could be the case that you need to have "cascade = {CascadeType.MERGE, CascadeType.PERSIST}" on the ManyToOne annotation. The default behavior does not cascade anything to the associated objects.
/**
* (Optional) The operations that must be cascaded to
* the target of the association.
*
* <p> By default no operations are cascaded.
*/
CascadeType[] cascade() default {};
Eg.
#ManyToOne(optional = true, cascade = {CascadeType.MERGE, CascadeType.PERSIST}, fetch = EAGER)
UPDATE:
In case you are using spring managed transaction manager and have the liberty to use annotation driven transaction demarcation, you can try the spring #Transactional annotation instead of manually starting transaction and committing/flushing.
I have following setup:
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
<property name="persistenceUnitName" value="persistenceUnit"/>
<property name="dataSource" ref="local-dataSource"/>
<property name="packagesToScan" value="X"/>
<property name="persistenceXmlLocation" value="classpath:persistence.xml"/>
</bean>
DAO class:
#Repository
public class EventRepository {
#PersistenceContext
EntityManager entityManager;
#Transactional
public void persist(Event event) {
entityManager.persist(event);
}
}

First of all, make sure that you use the fitting CascadeType on those ManyToOne annotations.
Secondly, a merge Operation in the entityManager/session does not remain object equality by reference. That means, in an update case where a merge is performed, check if a different object is returned. You are supposed to always use the return values of save operations.

Related

#Version annotation causing 'object references an unsaved transient instance - save the transient instance before flushing' exception [duplicate]

I receive following error when I save the object using Hibernate
object references an unsaved transient instance - save the transient instance before flushing
You should include cascade="all" (if using xml) or cascade=CascadeType.ALL (if using annotations) on your collection mapping.
This happens because you have a collection in your entity, and that collection has one or more items which are not present in the database. By specifying the above options you tell hibernate to save them to the database when saving their parent.
I believe this might be just repeat answer, but just to clarify, I got this on a #OneToOne mapping as well as a #OneToMany. In both cases, it was the fact that the Child object I was adding to the Parent wasn't saved in the database yet. So when I added the Child to the Parent, then saved the Parent, Hibernate would toss the "object references an unsaved transient instance - save the transient instance before flushing" message when saving the Parent.
Adding in the cascade = {CascadeType.ALL} on the Parent's reference to the Child solved the problem in both cases. This saved the Child and the Parent.
Sorry for any repeat answers, just wanted to further clarify for folks.
#OneToOne(cascade = {CascadeType.ALL})
#JoinColumn(name = "performancelog_id")
public PerformanceLog getPerformanceLog() {
return performanceLog;
}
Introduction
When using JPA and Hibernate, an entity can be in one of the following 4 states:
New - A newly created object that hasn’t ever been associated with a Hibernate Session (a.k.a Persistence Context) and is not mapped to any database table row is considered to be in the New or Transient state.
To become persisted we need to either explicitly call the persist method or make use of the transitive persistence mechanism.
Persistent - A persistent entity has been associated with a database table row and it’s being managed by the currently running Persistence Context.
Any change made to such an entity is going to be detected and propagated to the database (during the Session flush-time).
Detached - Once the currently running Persistence Context is closed all the previously managed entities become detached. Successive changes will no longer be tracked and no automatic database synchronization is going to happen.
Removed - Although JPA demands that managed entities only are allowed to be removed, Hibernate can also delete detached entities (but only through a remove method call).
Entity state transitions
To move an entity from one state to the other, you can use the persist, remove or merge methods.
Fixing the problem
The issue you are describing in your question:
object references an unsaved transient instance - save the transient instance before flushing
is caused by associating an entity in the state of New to an entity that's in the state of Managed.
This can happen when you are associating a child entity to a one-to-many collection in the parent entity, and the collection does not cascade the entity state transitions.
So, you can fix this by adding cascade to the entity association that triggered this failure, as follows:
The #OneToOne association
#OneToOne(
mappedBy = "post",
orphanRemoval = true,
cascade = CascadeType.ALL)
private PostDetails details;
Notice the CascadeType.ALL value we added for the cascade attribute.
The #OneToMany association
#OneToMany(
mappedBy = "post",
orphanRemoval = true,
cascade = CascadeType.ALL)
private List<Comment> comments = new ArrayList<>();
Again, the CascadeType.ALL is suitable for the bidirectional #OneToMany associations.
Now, in order for the cascade to work properly in a bidirectional, you also need to make sure that the parent and child associations are in sync.
The #ManyToMany association
#ManyToMany(
mappedBy = "authors",
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
}
)
private List<Book> books = new ArrayList<>();
In a #ManyToMany association, you cannot use CascadeType.ALL or orphanRemoval as this will propagate the delete entity state transition from one parent to another parent entity.
Therefore, for #ManyToMany associations, you usually cascade the CascadeType.PERSIST or CascadeType.MERGE operations. Alternatively, you can expand that to DETACH or REFRESH.
This happens when saving an object when Hibernate thinks it needs to save an object that is associated with the one you are saving.
I had this problem and did not want to save changes to the referenced object so I wanted the cascade type to be NONE.
The trick is to ensure that the ID and VERSION in the referenced object is set so that Hibernate does not think that the referenced object is a new object that needs saving. This worked for me.
Look through all of the relationships in the class you are saving to work out the associated objects (and the associated objects of the associated objects) and ensure that the ID and VERSION is set in all objects of the object tree.
Or, if you want to use minimal "powers" (e.g. if you don't want a cascade delete) to achieve what you want, use
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
...
#Cascade({CascadeType.SAVE_UPDATE})
private Set<Child> children;
In my case it was caused by not having CascadeType on the #ManyToOne side of the bidirectional relationship. To be more precise, I had CascadeType.ALL on #OneToMany side and did not have it on #ManyToOne. Adding CascadeType.ALL to #ManyToOne resolved the issue.
One-to-many side:
#OneToMany(cascade = CascadeType.ALL, mappedBy="globalConfig", orphanRemoval = true)
private Set<GlobalConfigScope>gcScopeSet;
Many-to-one side (caused the problem)
#ManyToOne
#JoinColumn(name="global_config_id")
private GlobalConfig globalConfig;
Many-to-one (fixed by adding CascadeType.PERSIST)
#ManyToOne(cascade = CascadeType.PERSIST)
#JoinColumn(name="global_config_id")
private GlobalConfig globalConfig;
This occurred for me when persisting an entity in which the existing record in the database had a NULL value for the field annotated with #Version (for optimistic locking). Updating the NULL value to 0 in the database corrected this.
This isn't the only reason for the error. I encountered it just now for a typo error in my coding, which I believe, set a value of an entity which was already saved.
X x2 = new X();
x.setXid(memberid); // Error happened here - x was a previous global entity I created earlier
Y.setX(x2);
I spotted the error by finding exactly which variable caused the error (in this case String xid). I used a catch around the whole block of code that saved the entity and printed the traces.
{
code block that performed the operation
} catch (Exception e) {
e.printStackTrace(); // put a break-point here and inspect the 'e'
return ERROR;
}
Don't use Cascade.All until you really have to. Role and Permission have bidirectional manyToMany relation. Then the following code would work fine
Permission p = new Permission();
p.setName("help");
Permission p2 = new Permission();
p2.setName("self_info");
p = (Permission)crudRepository.save(p); // returned p has id filled in.
p2 = (Permission)crudRepository.save(p2); // so does p2.
Role role = new Role();
role.setAvailable(true);
role.setDescription("a test role");
role.setRole("admin");
List<Permission> pList = new ArrayList<Permission>();
pList.add(p);
pList.add(p2);
role.setPermissions(pList);
crudRepository.save(role);
while if the object is just a "new" one, then it would throw the same error.
beside all other good answers, this could happen if you use merge to persist an object and accidentally forget to use merged reference of the object in the parent class. consider the following example
merge(A);
B.setA(A);
persist(B);
In this case, you merge A but forget to use merged object of A. to solve the problem you must rewrite the code like this.
A=merge(A);//difference is here
B.setA(A);
persist(B);
If your collection is nullable just try: object.SetYouColection(null);
This issue happened to me when I created a new entity and an associated entity in a method marked as #Transactional, then performed a query before saving. Ex
#Transactional
public someService() {
Entity someEntity = new Entity();
AssocaiatedEntity associatedEntity = new AssocaitedEntity();
someEntity.setAssociatedEntity(associatedEntity);
associatedEntity.setEntity(someEntity);
// Performing any query was causing hibernate to attempt to persist the new entity. It would then throw an exception
someDao.getSomething();
entityDao.create(someEntity);
}
To fix, I performed the query before creating the new entity.
To add my 2 cents, I got this same issue when I m accidentally sending null as the ID. Below code depicts my scenario (and OP didn't mention any specific scenario).
Employee emp = new Employee();
emp.setDept(new Dept(deptId)); // --> when deptId PKID is null, same error will be thrown
// calls to other setters...
em.persist(emp);
Here I m setting the existing department id to a new employee instance without actually getting the department entity first, as I don't want to another select query to fire.
In some scenarios, deptId PKID is coming as null from calling method and I m getting the same error.
So, watch for null values for PK ID
It can also happen when you are having OneToMany relation and you try to add the child entity to the list in parent entity, then retrieve this list through parent entity (before saving this parent entity), without saving child entity itself, e.g.:
Child childEntity = new Child();
parentEntity.addChild(childEntity);
parentEntity.getChildren(); // I needed the retrieval for logging, but one may need it for other reasons.
parentRepository.save(parentEntity);
The error was thrown when I saved the parent entity. If I removed the retrieval in the previous row, then the error was not thrown, but of course that's not the solution.
The solution was saving the childEntity and adding that saved child entity to the parent entity, like this:
Child childEntity = new Child();
Child savedChildEntity = childRepository.save(childEntity);
parentEntity.addChild(savedChildEntity);
parentEntity.getChildren();
parentRepository.save(parentEntity);
If you're using Spring Data JPA then addition #Transactional annotation to your service implementation would solve the issue.
I also faced the same situation. By setting following annotation above the property made it solve the exception prompted.
The Exception I faced.
Exception in thread "main" java.lang.IllegalStateException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.model.Car_OneToMany
To overcome, the annotation I used.
#OneToMany(cascade = {CascadeType.ALL})
#Column(name = "ListOfCarsDrivenByDriver")
private List<Car_OneToMany> listOfCarsBeingDriven = new ArrayList<Car_OneToMany>();
What made Hibernate throw the exception:
This exception is thrown at your console because the child object I attach to the parent object is not present in the database at that moment.
By providing #OneToMany(cascade = {CascadeType.ALL}) , it tells Hibernate to save them to the database while saving the parent object.
i get this error when i use
getSession().save(object)
but it works with no problem when I use
getSession().saveOrUpdate(object)
For the sake of completeness: A
org.hibernate.TransientPropertyValueException
with message
object references an unsaved transient instance - save the transient instance before flushing
will also occur when you try to persist / merge an entity with a reference to another entity which happens to be detached.
One other possible reason: in my case, I was attempting to save the child before saving the parent, on a brand new entity.
The code was something like this in a User.java model:
this.lastName = lastName;
this.isAdmin = isAdmin;
this.accountStatus = "Active";
this.setNewPassword(password);
this.timeJoin = new Date();
create();
The setNewPassword() method creates a PasswordHistory record and adds it to the history collection in User. Since the create() statement hadn't been executed yet for the parent, it was trying to save to a collection of an entity that hadn't yet been created. All I had to do to fix it was to move the setNewPassword() call after the call to create().
this.lastName = lastName;
this.isAdmin = isAdmin;
this.accountStatus = "Active";
this.timeJoin = new Date();
create();
this.setNewPassword(password);
There is another possibility that can cause this error in hibernate. You may set an unsaved reference of your object A to an attached entity B and want to persist object C. Even in this case, you will get the aforementioned error.
There are so many possibilities of this error some other possibilities are also on add page or edit page. In my case I was trying to save a object AdvanceSalary. The problem is that in edit the AdvanceSalary employee.employee_id is null Because on edit I was not set the employee.employee_id. I have make a hidden field and set it. my code working absolutely fine.
#Entity(name = "ic_advance_salary")
#Table(name = "ic_advance_salary")
public class AdvanceSalary extends BaseDO{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "employee_id", nullable = false)
private Employee employee;
#Column(name = "employee_id", insertable=false, updatable=false)
#NotNull(message="Please enter employee Id")
private Long employee_id;
#Column(name = "advance_date")
#DateTimeFormat(pattern = "dd-MMM-yyyy")
#NotNull(message="Please enter advance date")
private Date advance_date;
#Column(name = "amount")
#NotNull(message="Please enter Paid Amount")
private Double amount;
#Column(name = "cheque_date")
#DateTimeFormat(pattern = "dd-MMM-yyyy")
private Date cheque_date;
#Column(name = "cheque_no")
private String cheque_no;
#Column(name = "remarks")
private String remarks;
public AdvanceSalary() {
}
public AdvanceSalary(Integer advance_salary_id) {
this.id = advance_salary_id;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
public Long getEmployee_id() {
return employee_id;
}
public void setEmployee_id(Long employee_id) {
this.employee_id = employee_id;
}
}
I think is because you have try to persist an object that have a reference to another object that is not persist yet, and so it try in the "DB side" to put a reference to a row that not exists
Case 1:
I was getting this exception when I was trying to create a parent and saving that parent reference to its child and then some other DELETE/UPDATE query(JPQL). So I just flush() the newly created entity after creating parent and after creating child using same parent reference. It Worked for me.
Case 2:
Parent class
public class Reference implements Serializable {
#Id
#Column(precision=20, scale=0)
private BigInteger id;
#Temporal(TemporalType.TIMESTAMP)
private Date modifiedOn;
#OneToOne(mappedBy="reference")
private ReferenceAdditionalDetails refAddDetails;
.
.
.
}
Child Class:
public class ReferenceAdditionalDetails implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#OneToOne
#JoinColumn(name="reference",referencedColumnName="id")
private Reference reference;
private String preferedSector1;
private String preferedSector2;
.
.
}
In the above case where parent(Reference) and child(ReferenceAdditionalDetails) having OneToOne relationship and when you try to create Reference entity and then its child(ReferenceAdditionalDetails), it will give you the same exception. So to avoid the exception you have to set null for child class and then create the parent.(Sample Code)
.
.
reference.setRefAddDetails(null);
reference = referenceDao.create(reference);
entityManager.flush();
.
.
In my case , issue was completely different. I have two classes let's say c1 & c2. Between C1 & C2 dependency is OneToMany. Now if i am saving C1 in DB it was throwing above error.
Resolution of this problem was to get first C2's id from consumer request and find C2 via repository call.Afterwards save c2 into C1 object .Now if i am saving C1, it's working fine.
I was facing the same error for all PUT HTTP transactions, after introducing optimistic locking (#Version)
At the time of updating an entity it is mandatory to send id and version of that entity. If any of the entity fields are related to other entities then for that field also we should provide id and version values, without that the JPA try to persist that related entity first as a new entity
Example: we have two entities --> Vehicle(id,Car,version) ; Car(id, version, brand); to update/persist Vehicle entity make sure the Car field in vehicle entity has id and version fields provided
Simple way of solving this issue is save the both entity.
first save the child entity and then save the parent entity.
Because parent entity is depend on child entity for the foreign key value.
Below simple exam of one to one relationship
insert into Department (name, numOfemp, Depno) values (?, ?, ?)
Hibernate: insert into Employee (SSN, dep_Depno, firstName, lastName, middleName, empno) values (?, ?, ?, ?, ?, ?)
Session session=sf.openSession();
session.beginTransaction();
session.save(dep);
session.save(emp);
One possible cause of the error is the inexistence of the setting of the value of the parent entity ; for example for a department-employees relationship you have to write this in order to fix the error :
Department dept = (Department)session.load(Department.class, dept_code); // dept_code is from the jsp form which you get in the controller with #RequestParam String department
employee.setDepartment(dept);
I faced this exception when I did not persist parent object but I was saving the child. To resolve the issue, with in the same session I persisted both the child and parent objects and used CascadeType.ALL on the parent.
My problem was related to #BeforeEach of JUnit. And even if I saved the related entities (in my case #ManyToOne), I got the same error.
The problem is somehow related to the sequence that I have in my parent.
If I assign the value to that attribute, the problem is solved.
Ex.
If I have the entity Question that can have some categories (one or more) and entity Question has a sequence:
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "feedbackSeq")
#Id
private Long id;
I have to assign the value question.setId(1L);
Just make Constructor of your mapping in your base class.
Like if you want One-To-One relation in Entity A, Entity B.
if your are taking A as base class, then A must have a Constructor have B as a argument.

Spring Boot object references an unsaved transient instance error from method [duplicate]

I receive following error when I save the object using Hibernate
object references an unsaved transient instance - save the transient instance before flushing
You should include cascade="all" (if using xml) or cascade=CascadeType.ALL (if using annotations) on your collection mapping.
This happens because you have a collection in your entity, and that collection has one or more items which are not present in the database. By specifying the above options you tell hibernate to save them to the database when saving their parent.
I believe this might be just repeat answer, but just to clarify, I got this on a #OneToOne mapping as well as a #OneToMany. In both cases, it was the fact that the Child object I was adding to the Parent wasn't saved in the database yet. So when I added the Child to the Parent, then saved the Parent, Hibernate would toss the "object references an unsaved transient instance - save the transient instance before flushing" message when saving the Parent.
Adding in the cascade = {CascadeType.ALL} on the Parent's reference to the Child solved the problem in both cases. This saved the Child and the Parent.
Sorry for any repeat answers, just wanted to further clarify for folks.
#OneToOne(cascade = {CascadeType.ALL})
#JoinColumn(name = "performancelog_id")
public PerformanceLog getPerformanceLog() {
return performanceLog;
}
Introduction
When using JPA and Hibernate, an entity can be in one of the following 4 states:
New - A newly created object that hasn’t ever been associated with a Hibernate Session (a.k.a Persistence Context) and is not mapped to any database table row is considered to be in the New or Transient state.
To become persisted we need to either explicitly call the persist method or make use of the transitive persistence mechanism.
Persistent - A persistent entity has been associated with a database table row and it’s being managed by the currently running Persistence Context.
Any change made to such an entity is going to be detected and propagated to the database (during the Session flush-time).
Detached - Once the currently running Persistence Context is closed all the previously managed entities become detached. Successive changes will no longer be tracked and no automatic database synchronization is going to happen.
Removed - Although JPA demands that managed entities only are allowed to be removed, Hibernate can also delete detached entities (but only through a remove method call).
Entity state transitions
To move an entity from one state to the other, you can use the persist, remove or merge methods.
Fixing the problem
The issue you are describing in your question:
object references an unsaved transient instance - save the transient instance before flushing
is caused by associating an entity in the state of New to an entity that's in the state of Managed.
This can happen when you are associating a child entity to a one-to-many collection in the parent entity, and the collection does not cascade the entity state transitions.
So, you can fix this by adding cascade to the entity association that triggered this failure, as follows:
The #OneToOne association
#OneToOne(
mappedBy = "post",
orphanRemoval = true,
cascade = CascadeType.ALL)
private PostDetails details;
Notice the CascadeType.ALL value we added for the cascade attribute.
The #OneToMany association
#OneToMany(
mappedBy = "post",
orphanRemoval = true,
cascade = CascadeType.ALL)
private List<Comment> comments = new ArrayList<>();
Again, the CascadeType.ALL is suitable for the bidirectional #OneToMany associations.
Now, in order for the cascade to work properly in a bidirectional, you also need to make sure that the parent and child associations are in sync.
The #ManyToMany association
#ManyToMany(
mappedBy = "authors",
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
}
)
private List<Book> books = new ArrayList<>();
In a #ManyToMany association, you cannot use CascadeType.ALL or orphanRemoval as this will propagate the delete entity state transition from one parent to another parent entity.
Therefore, for #ManyToMany associations, you usually cascade the CascadeType.PERSIST or CascadeType.MERGE operations. Alternatively, you can expand that to DETACH or REFRESH.
This happens when saving an object when Hibernate thinks it needs to save an object that is associated with the one you are saving.
I had this problem and did not want to save changes to the referenced object so I wanted the cascade type to be NONE.
The trick is to ensure that the ID and VERSION in the referenced object is set so that Hibernate does not think that the referenced object is a new object that needs saving. This worked for me.
Look through all of the relationships in the class you are saving to work out the associated objects (and the associated objects of the associated objects) and ensure that the ID and VERSION is set in all objects of the object tree.
Or, if you want to use minimal "powers" (e.g. if you don't want a cascade delete) to achieve what you want, use
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
...
#Cascade({CascadeType.SAVE_UPDATE})
private Set<Child> children;
In my case it was caused by not having CascadeType on the #ManyToOne side of the bidirectional relationship. To be more precise, I had CascadeType.ALL on #OneToMany side and did not have it on #ManyToOne. Adding CascadeType.ALL to #ManyToOne resolved the issue.
One-to-many side:
#OneToMany(cascade = CascadeType.ALL, mappedBy="globalConfig", orphanRemoval = true)
private Set<GlobalConfigScope>gcScopeSet;
Many-to-one side (caused the problem)
#ManyToOne
#JoinColumn(name="global_config_id")
private GlobalConfig globalConfig;
Many-to-one (fixed by adding CascadeType.PERSIST)
#ManyToOne(cascade = CascadeType.PERSIST)
#JoinColumn(name="global_config_id")
private GlobalConfig globalConfig;
This occurred for me when persisting an entity in which the existing record in the database had a NULL value for the field annotated with #Version (for optimistic locking). Updating the NULL value to 0 in the database corrected this.
This isn't the only reason for the error. I encountered it just now for a typo error in my coding, which I believe, set a value of an entity which was already saved.
X x2 = new X();
x.setXid(memberid); // Error happened here - x was a previous global entity I created earlier
Y.setX(x2);
I spotted the error by finding exactly which variable caused the error (in this case String xid). I used a catch around the whole block of code that saved the entity and printed the traces.
{
code block that performed the operation
} catch (Exception e) {
e.printStackTrace(); // put a break-point here and inspect the 'e'
return ERROR;
}
Don't use Cascade.All until you really have to. Role and Permission have bidirectional manyToMany relation. Then the following code would work fine
Permission p = new Permission();
p.setName("help");
Permission p2 = new Permission();
p2.setName("self_info");
p = (Permission)crudRepository.save(p); // returned p has id filled in.
p2 = (Permission)crudRepository.save(p2); // so does p2.
Role role = new Role();
role.setAvailable(true);
role.setDescription("a test role");
role.setRole("admin");
List<Permission> pList = new ArrayList<Permission>();
pList.add(p);
pList.add(p2);
role.setPermissions(pList);
crudRepository.save(role);
while if the object is just a "new" one, then it would throw the same error.
beside all other good answers, this could happen if you use merge to persist an object and accidentally forget to use merged reference of the object in the parent class. consider the following example
merge(A);
B.setA(A);
persist(B);
In this case, you merge A but forget to use merged object of A. to solve the problem you must rewrite the code like this.
A=merge(A);//difference is here
B.setA(A);
persist(B);
If your collection is nullable just try: object.SetYouColection(null);
This issue happened to me when I created a new entity and an associated entity in a method marked as #Transactional, then performed a query before saving. Ex
#Transactional
public someService() {
Entity someEntity = new Entity();
AssocaiatedEntity associatedEntity = new AssocaitedEntity();
someEntity.setAssociatedEntity(associatedEntity);
associatedEntity.setEntity(someEntity);
// Performing any query was causing hibernate to attempt to persist the new entity. It would then throw an exception
someDao.getSomething();
entityDao.create(someEntity);
}
To fix, I performed the query before creating the new entity.
To add my 2 cents, I got this same issue when I m accidentally sending null as the ID. Below code depicts my scenario (and OP didn't mention any specific scenario).
Employee emp = new Employee();
emp.setDept(new Dept(deptId)); // --> when deptId PKID is null, same error will be thrown
// calls to other setters...
em.persist(emp);
Here I m setting the existing department id to a new employee instance without actually getting the department entity first, as I don't want to another select query to fire.
In some scenarios, deptId PKID is coming as null from calling method and I m getting the same error.
So, watch for null values for PK ID
It can also happen when you are having OneToMany relation and you try to add the child entity to the list in parent entity, then retrieve this list through parent entity (before saving this parent entity), without saving child entity itself, e.g.:
Child childEntity = new Child();
parentEntity.addChild(childEntity);
parentEntity.getChildren(); // I needed the retrieval for logging, but one may need it for other reasons.
parentRepository.save(parentEntity);
The error was thrown when I saved the parent entity. If I removed the retrieval in the previous row, then the error was not thrown, but of course that's not the solution.
The solution was saving the childEntity and adding that saved child entity to the parent entity, like this:
Child childEntity = new Child();
Child savedChildEntity = childRepository.save(childEntity);
parentEntity.addChild(savedChildEntity);
parentEntity.getChildren();
parentRepository.save(parentEntity);
If you're using Spring Data JPA then addition #Transactional annotation to your service implementation would solve the issue.
I also faced the same situation. By setting following annotation above the property made it solve the exception prompted.
The Exception I faced.
Exception in thread "main" java.lang.IllegalStateException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.model.Car_OneToMany
To overcome, the annotation I used.
#OneToMany(cascade = {CascadeType.ALL})
#Column(name = "ListOfCarsDrivenByDriver")
private List<Car_OneToMany> listOfCarsBeingDriven = new ArrayList<Car_OneToMany>();
What made Hibernate throw the exception:
This exception is thrown at your console because the child object I attach to the parent object is not present in the database at that moment.
By providing #OneToMany(cascade = {CascadeType.ALL}) , it tells Hibernate to save them to the database while saving the parent object.
i get this error when i use
getSession().save(object)
but it works with no problem when I use
getSession().saveOrUpdate(object)
For the sake of completeness: A
org.hibernate.TransientPropertyValueException
with message
object references an unsaved transient instance - save the transient instance before flushing
will also occur when you try to persist / merge an entity with a reference to another entity which happens to be detached.
One other possible reason: in my case, I was attempting to save the child before saving the parent, on a brand new entity.
The code was something like this in a User.java model:
this.lastName = lastName;
this.isAdmin = isAdmin;
this.accountStatus = "Active";
this.setNewPassword(password);
this.timeJoin = new Date();
create();
The setNewPassword() method creates a PasswordHistory record and adds it to the history collection in User. Since the create() statement hadn't been executed yet for the parent, it was trying to save to a collection of an entity that hadn't yet been created. All I had to do to fix it was to move the setNewPassword() call after the call to create().
this.lastName = lastName;
this.isAdmin = isAdmin;
this.accountStatus = "Active";
this.timeJoin = new Date();
create();
this.setNewPassword(password);
There is another possibility that can cause this error in hibernate. You may set an unsaved reference of your object A to an attached entity B and want to persist object C. Even in this case, you will get the aforementioned error.
There are so many possibilities of this error some other possibilities are also on add page or edit page. In my case I was trying to save a object AdvanceSalary. The problem is that in edit the AdvanceSalary employee.employee_id is null Because on edit I was not set the employee.employee_id. I have make a hidden field and set it. my code working absolutely fine.
#Entity(name = "ic_advance_salary")
#Table(name = "ic_advance_salary")
public class AdvanceSalary extends BaseDO{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "employee_id", nullable = false)
private Employee employee;
#Column(name = "employee_id", insertable=false, updatable=false)
#NotNull(message="Please enter employee Id")
private Long employee_id;
#Column(name = "advance_date")
#DateTimeFormat(pattern = "dd-MMM-yyyy")
#NotNull(message="Please enter advance date")
private Date advance_date;
#Column(name = "amount")
#NotNull(message="Please enter Paid Amount")
private Double amount;
#Column(name = "cheque_date")
#DateTimeFormat(pattern = "dd-MMM-yyyy")
private Date cheque_date;
#Column(name = "cheque_no")
private String cheque_no;
#Column(name = "remarks")
private String remarks;
public AdvanceSalary() {
}
public AdvanceSalary(Integer advance_salary_id) {
this.id = advance_salary_id;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
public Long getEmployee_id() {
return employee_id;
}
public void setEmployee_id(Long employee_id) {
this.employee_id = employee_id;
}
}
I think is because you have try to persist an object that have a reference to another object that is not persist yet, and so it try in the "DB side" to put a reference to a row that not exists
Case 1:
I was getting this exception when I was trying to create a parent and saving that parent reference to its child and then some other DELETE/UPDATE query(JPQL). So I just flush() the newly created entity after creating parent and after creating child using same parent reference. It Worked for me.
Case 2:
Parent class
public class Reference implements Serializable {
#Id
#Column(precision=20, scale=0)
private BigInteger id;
#Temporal(TemporalType.TIMESTAMP)
private Date modifiedOn;
#OneToOne(mappedBy="reference")
private ReferenceAdditionalDetails refAddDetails;
.
.
.
}
Child Class:
public class ReferenceAdditionalDetails implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#OneToOne
#JoinColumn(name="reference",referencedColumnName="id")
private Reference reference;
private String preferedSector1;
private String preferedSector2;
.
.
}
In the above case where parent(Reference) and child(ReferenceAdditionalDetails) having OneToOne relationship and when you try to create Reference entity and then its child(ReferenceAdditionalDetails), it will give you the same exception. So to avoid the exception you have to set null for child class and then create the parent.(Sample Code)
.
.
reference.setRefAddDetails(null);
reference = referenceDao.create(reference);
entityManager.flush();
.
.
In my case , issue was completely different. I have two classes let's say c1 & c2. Between C1 & C2 dependency is OneToMany. Now if i am saving C1 in DB it was throwing above error.
Resolution of this problem was to get first C2's id from consumer request and find C2 via repository call.Afterwards save c2 into C1 object .Now if i am saving C1, it's working fine.
I was facing the same error for all PUT HTTP transactions, after introducing optimistic locking (#Version)
At the time of updating an entity it is mandatory to send id and version of that entity. If any of the entity fields are related to other entities then for that field also we should provide id and version values, without that the JPA try to persist that related entity first as a new entity
Example: we have two entities --> Vehicle(id,Car,version) ; Car(id, version, brand); to update/persist Vehicle entity make sure the Car field in vehicle entity has id and version fields provided
Simple way of solving this issue is save the both entity.
first save the child entity and then save the parent entity.
Because parent entity is depend on child entity for the foreign key value.
Below simple exam of one to one relationship
insert into Department (name, numOfemp, Depno) values (?, ?, ?)
Hibernate: insert into Employee (SSN, dep_Depno, firstName, lastName, middleName, empno) values (?, ?, ?, ?, ?, ?)
Session session=sf.openSession();
session.beginTransaction();
session.save(dep);
session.save(emp);
One possible cause of the error is the inexistence of the setting of the value of the parent entity ; for example for a department-employees relationship you have to write this in order to fix the error :
Department dept = (Department)session.load(Department.class, dept_code); // dept_code is from the jsp form which you get in the controller with #RequestParam String department
employee.setDepartment(dept);
I faced this exception when I did not persist parent object but I was saving the child. To resolve the issue, with in the same session I persisted both the child and parent objects and used CascadeType.ALL on the parent.
My problem was related to #BeforeEach of JUnit. And even if I saved the related entities (in my case #ManyToOne), I got the same error.
The problem is somehow related to the sequence that I have in my parent.
If I assign the value to that attribute, the problem is solved.
Ex.
If I have the entity Question that can have some categories (one or more) and entity Question has a sequence:
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "feedbackSeq")
#Id
private Long id;
I have to assign the value question.setId(1L);
Just make Constructor of your mapping in your base class.
Like if you want One-To-One relation in Entity A, Entity B.
if your are taking A as base class, then A must have a Constructor have B as a argument.

How to solve object references an unsaved transient instance - save the transient instance before flushing [duplicate]

I receive following error when I save the object using Hibernate
object references an unsaved transient instance - save the transient instance before flushing
You should include cascade="all" (if using xml) or cascade=CascadeType.ALL (if using annotations) on your collection mapping.
This happens because you have a collection in your entity, and that collection has one or more items which are not present in the database. By specifying the above options you tell hibernate to save them to the database when saving their parent.
I believe this might be just repeat answer, but just to clarify, I got this on a #OneToOne mapping as well as a #OneToMany. In both cases, it was the fact that the Child object I was adding to the Parent wasn't saved in the database yet. So when I added the Child to the Parent, then saved the Parent, Hibernate would toss the "object references an unsaved transient instance - save the transient instance before flushing" message when saving the Parent.
Adding in the cascade = {CascadeType.ALL} on the Parent's reference to the Child solved the problem in both cases. This saved the Child and the Parent.
Sorry for any repeat answers, just wanted to further clarify for folks.
#OneToOne(cascade = {CascadeType.ALL})
#JoinColumn(name = "performancelog_id")
public PerformanceLog getPerformanceLog() {
return performanceLog;
}
Introduction
When using JPA and Hibernate, an entity can be in one of the following 4 states:
New - A newly created object that hasn’t ever been associated with a Hibernate Session (a.k.a Persistence Context) and is not mapped to any database table row is considered to be in the New or Transient state.
To become persisted we need to either explicitly call the persist method or make use of the transitive persistence mechanism.
Persistent - A persistent entity has been associated with a database table row and it’s being managed by the currently running Persistence Context.
Any change made to such an entity is going to be detected and propagated to the database (during the Session flush-time).
Detached - Once the currently running Persistence Context is closed all the previously managed entities become detached. Successive changes will no longer be tracked and no automatic database synchronization is going to happen.
Removed - Although JPA demands that managed entities only are allowed to be removed, Hibernate can also delete detached entities (but only through a remove method call).
Entity state transitions
To move an entity from one state to the other, you can use the persist, remove or merge methods.
Fixing the problem
The issue you are describing in your question:
object references an unsaved transient instance - save the transient instance before flushing
is caused by associating an entity in the state of New to an entity that's in the state of Managed.
This can happen when you are associating a child entity to a one-to-many collection in the parent entity, and the collection does not cascade the entity state transitions.
So, you can fix this by adding cascade to the entity association that triggered this failure, as follows:
The #OneToOne association
#OneToOne(
mappedBy = "post",
orphanRemoval = true,
cascade = CascadeType.ALL)
private PostDetails details;
Notice the CascadeType.ALL value we added for the cascade attribute.
The #OneToMany association
#OneToMany(
mappedBy = "post",
orphanRemoval = true,
cascade = CascadeType.ALL)
private List<Comment> comments = new ArrayList<>();
Again, the CascadeType.ALL is suitable for the bidirectional #OneToMany associations.
Now, in order for the cascade to work properly in a bidirectional, you also need to make sure that the parent and child associations are in sync.
The #ManyToMany association
#ManyToMany(
mappedBy = "authors",
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
}
)
private List<Book> books = new ArrayList<>();
In a #ManyToMany association, you cannot use CascadeType.ALL or orphanRemoval as this will propagate the delete entity state transition from one parent to another parent entity.
Therefore, for #ManyToMany associations, you usually cascade the CascadeType.PERSIST or CascadeType.MERGE operations. Alternatively, you can expand that to DETACH or REFRESH.
This happens when saving an object when Hibernate thinks it needs to save an object that is associated with the one you are saving.
I had this problem and did not want to save changes to the referenced object so I wanted the cascade type to be NONE.
The trick is to ensure that the ID and VERSION in the referenced object is set so that Hibernate does not think that the referenced object is a new object that needs saving. This worked for me.
Look through all of the relationships in the class you are saving to work out the associated objects (and the associated objects of the associated objects) and ensure that the ID and VERSION is set in all objects of the object tree.
Or, if you want to use minimal "powers" (e.g. if you don't want a cascade delete) to achieve what you want, use
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
...
#Cascade({CascadeType.SAVE_UPDATE})
private Set<Child> children;
In my case it was caused by not having CascadeType on the #ManyToOne side of the bidirectional relationship. To be more precise, I had CascadeType.ALL on #OneToMany side and did not have it on #ManyToOne. Adding CascadeType.ALL to #ManyToOne resolved the issue.
One-to-many side:
#OneToMany(cascade = CascadeType.ALL, mappedBy="globalConfig", orphanRemoval = true)
private Set<GlobalConfigScope>gcScopeSet;
Many-to-one side (caused the problem)
#ManyToOne
#JoinColumn(name="global_config_id")
private GlobalConfig globalConfig;
Many-to-one (fixed by adding CascadeType.PERSIST)
#ManyToOne(cascade = CascadeType.PERSIST)
#JoinColumn(name="global_config_id")
private GlobalConfig globalConfig;
This occurred for me when persisting an entity in which the existing record in the database had a NULL value for the field annotated with #Version (for optimistic locking). Updating the NULL value to 0 in the database corrected this.
This isn't the only reason for the error. I encountered it just now for a typo error in my coding, which I believe, set a value of an entity which was already saved.
X x2 = new X();
x.setXid(memberid); // Error happened here - x was a previous global entity I created earlier
Y.setX(x2);
I spotted the error by finding exactly which variable caused the error (in this case String xid). I used a catch around the whole block of code that saved the entity and printed the traces.
{
code block that performed the operation
} catch (Exception e) {
e.printStackTrace(); // put a break-point here and inspect the 'e'
return ERROR;
}
Don't use Cascade.All until you really have to. Role and Permission have bidirectional manyToMany relation. Then the following code would work fine
Permission p = new Permission();
p.setName("help");
Permission p2 = new Permission();
p2.setName("self_info");
p = (Permission)crudRepository.save(p); // returned p has id filled in.
p2 = (Permission)crudRepository.save(p2); // so does p2.
Role role = new Role();
role.setAvailable(true);
role.setDescription("a test role");
role.setRole("admin");
List<Permission> pList = new ArrayList<Permission>();
pList.add(p);
pList.add(p2);
role.setPermissions(pList);
crudRepository.save(role);
while if the object is just a "new" one, then it would throw the same error.
beside all other good answers, this could happen if you use merge to persist an object and accidentally forget to use merged reference of the object in the parent class. consider the following example
merge(A);
B.setA(A);
persist(B);
In this case, you merge A but forget to use merged object of A. to solve the problem you must rewrite the code like this.
A=merge(A);//difference is here
B.setA(A);
persist(B);
If your collection is nullable just try: object.SetYouColection(null);
This issue happened to me when I created a new entity and an associated entity in a method marked as #Transactional, then performed a query before saving. Ex
#Transactional
public someService() {
Entity someEntity = new Entity();
AssocaiatedEntity associatedEntity = new AssocaitedEntity();
someEntity.setAssociatedEntity(associatedEntity);
associatedEntity.setEntity(someEntity);
// Performing any query was causing hibernate to attempt to persist the new entity. It would then throw an exception
someDao.getSomething();
entityDao.create(someEntity);
}
To fix, I performed the query before creating the new entity.
To add my 2 cents, I got this same issue when I m accidentally sending null as the ID. Below code depicts my scenario (and OP didn't mention any specific scenario).
Employee emp = new Employee();
emp.setDept(new Dept(deptId)); // --> when deptId PKID is null, same error will be thrown
// calls to other setters...
em.persist(emp);
Here I m setting the existing department id to a new employee instance without actually getting the department entity first, as I don't want to another select query to fire.
In some scenarios, deptId PKID is coming as null from calling method and I m getting the same error.
So, watch for null values for PK ID
It can also happen when you are having OneToMany relation and you try to add the child entity to the list in parent entity, then retrieve this list through parent entity (before saving this parent entity), without saving child entity itself, e.g.:
Child childEntity = new Child();
parentEntity.addChild(childEntity);
parentEntity.getChildren(); // I needed the retrieval for logging, but one may need it for other reasons.
parentRepository.save(parentEntity);
The error was thrown when I saved the parent entity. If I removed the retrieval in the previous row, then the error was not thrown, but of course that's not the solution.
The solution was saving the childEntity and adding that saved child entity to the parent entity, like this:
Child childEntity = new Child();
Child savedChildEntity = childRepository.save(childEntity);
parentEntity.addChild(savedChildEntity);
parentEntity.getChildren();
parentRepository.save(parentEntity);
If you're using Spring Data JPA then addition #Transactional annotation to your service implementation would solve the issue.
I also faced the same situation. By setting following annotation above the property made it solve the exception prompted.
The Exception I faced.
Exception in thread "main" java.lang.IllegalStateException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.model.Car_OneToMany
To overcome, the annotation I used.
#OneToMany(cascade = {CascadeType.ALL})
#Column(name = "ListOfCarsDrivenByDriver")
private List<Car_OneToMany> listOfCarsBeingDriven = new ArrayList<Car_OneToMany>();
What made Hibernate throw the exception:
This exception is thrown at your console because the child object I attach to the parent object is not present in the database at that moment.
By providing #OneToMany(cascade = {CascadeType.ALL}) , it tells Hibernate to save them to the database while saving the parent object.
i get this error when i use
getSession().save(object)
but it works with no problem when I use
getSession().saveOrUpdate(object)
For the sake of completeness: A
org.hibernate.TransientPropertyValueException
with message
object references an unsaved transient instance - save the transient instance before flushing
will also occur when you try to persist / merge an entity with a reference to another entity which happens to be detached.
One other possible reason: in my case, I was attempting to save the child before saving the parent, on a brand new entity.
The code was something like this in a User.java model:
this.lastName = lastName;
this.isAdmin = isAdmin;
this.accountStatus = "Active";
this.setNewPassword(password);
this.timeJoin = new Date();
create();
The setNewPassword() method creates a PasswordHistory record and adds it to the history collection in User. Since the create() statement hadn't been executed yet for the parent, it was trying to save to a collection of an entity that hadn't yet been created. All I had to do to fix it was to move the setNewPassword() call after the call to create().
this.lastName = lastName;
this.isAdmin = isAdmin;
this.accountStatus = "Active";
this.timeJoin = new Date();
create();
this.setNewPassword(password);
There is another possibility that can cause this error in hibernate. You may set an unsaved reference of your object A to an attached entity B and want to persist object C. Even in this case, you will get the aforementioned error.
There are so many possibilities of this error some other possibilities are also on add page or edit page. In my case I was trying to save a object AdvanceSalary. The problem is that in edit the AdvanceSalary employee.employee_id is null Because on edit I was not set the employee.employee_id. I have make a hidden field and set it. my code working absolutely fine.
#Entity(name = "ic_advance_salary")
#Table(name = "ic_advance_salary")
public class AdvanceSalary extends BaseDO{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "employee_id", nullable = false)
private Employee employee;
#Column(name = "employee_id", insertable=false, updatable=false)
#NotNull(message="Please enter employee Id")
private Long employee_id;
#Column(name = "advance_date")
#DateTimeFormat(pattern = "dd-MMM-yyyy")
#NotNull(message="Please enter advance date")
private Date advance_date;
#Column(name = "amount")
#NotNull(message="Please enter Paid Amount")
private Double amount;
#Column(name = "cheque_date")
#DateTimeFormat(pattern = "dd-MMM-yyyy")
private Date cheque_date;
#Column(name = "cheque_no")
private String cheque_no;
#Column(name = "remarks")
private String remarks;
public AdvanceSalary() {
}
public AdvanceSalary(Integer advance_salary_id) {
this.id = advance_salary_id;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
public Long getEmployee_id() {
return employee_id;
}
public void setEmployee_id(Long employee_id) {
this.employee_id = employee_id;
}
}
I think is because you have try to persist an object that have a reference to another object that is not persist yet, and so it try in the "DB side" to put a reference to a row that not exists
Case 1:
I was getting this exception when I was trying to create a parent and saving that parent reference to its child and then some other DELETE/UPDATE query(JPQL). So I just flush() the newly created entity after creating parent and after creating child using same parent reference. It Worked for me.
Case 2:
Parent class
public class Reference implements Serializable {
#Id
#Column(precision=20, scale=0)
private BigInteger id;
#Temporal(TemporalType.TIMESTAMP)
private Date modifiedOn;
#OneToOne(mappedBy="reference")
private ReferenceAdditionalDetails refAddDetails;
.
.
.
}
Child Class:
public class ReferenceAdditionalDetails implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#OneToOne
#JoinColumn(name="reference",referencedColumnName="id")
private Reference reference;
private String preferedSector1;
private String preferedSector2;
.
.
}
In the above case where parent(Reference) and child(ReferenceAdditionalDetails) having OneToOne relationship and when you try to create Reference entity and then its child(ReferenceAdditionalDetails), it will give you the same exception. So to avoid the exception you have to set null for child class and then create the parent.(Sample Code)
.
.
reference.setRefAddDetails(null);
reference = referenceDao.create(reference);
entityManager.flush();
.
.
In my case , issue was completely different. I have two classes let's say c1 & c2. Between C1 & C2 dependency is OneToMany. Now if i am saving C1 in DB it was throwing above error.
Resolution of this problem was to get first C2's id from consumer request and find C2 via repository call.Afterwards save c2 into C1 object .Now if i am saving C1, it's working fine.
I was facing the same error for all PUT HTTP transactions, after introducing optimistic locking (#Version)
At the time of updating an entity it is mandatory to send id and version of that entity. If any of the entity fields are related to other entities then for that field also we should provide id and version values, without that the JPA try to persist that related entity first as a new entity
Example: we have two entities --> Vehicle(id,Car,version) ; Car(id, version, brand); to update/persist Vehicle entity make sure the Car field in vehicle entity has id and version fields provided
Simple way of solving this issue is save the both entity.
first save the child entity and then save the parent entity.
Because parent entity is depend on child entity for the foreign key value.
Below simple exam of one to one relationship
insert into Department (name, numOfemp, Depno) values (?, ?, ?)
Hibernate: insert into Employee (SSN, dep_Depno, firstName, lastName, middleName, empno) values (?, ?, ?, ?, ?, ?)
Session session=sf.openSession();
session.beginTransaction();
session.save(dep);
session.save(emp);
One possible cause of the error is the inexistence of the setting of the value of the parent entity ; for example for a department-employees relationship you have to write this in order to fix the error :
Department dept = (Department)session.load(Department.class, dept_code); // dept_code is from the jsp form which you get in the controller with #RequestParam String department
employee.setDepartment(dept);
I faced this exception when I did not persist parent object but I was saving the child. To resolve the issue, with in the same session I persisted both the child and parent objects and used CascadeType.ALL on the parent.
My problem was related to #BeforeEach of JUnit. And even if I saved the related entities (in my case #ManyToOne), I got the same error.
The problem is somehow related to the sequence that I have in my parent.
If I assign the value to that attribute, the problem is solved.
Ex.
If I have the entity Question that can have some categories (one or more) and entity Question has a sequence:
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "feedbackSeq")
#Id
private Long id;
I have to assign the value question.setId(1L);
Just make Constructor of your mapping in your base class.
Like if you want One-To-One relation in Entity A, Entity B.
if your are taking A as base class, then A must have a Constructor have B as a argument.

How to refresh updated entity data without restarting the server

I am using EclipseLink JPA as ORM and web logic 10.3 as an application server in my project. Everything working fine until i got a bug for data refresh. Here is the case one of my entity table row is updated to new value but my entity manager or JPA did not pick that value. For this we have lite rely re started the server. then it picked up the value.
Here is my persistence.xml file and here is the way i am using entity manager in my class.
<persistence-unit name="BasePersistenceUnit" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/CTH_DS</jta-data-source>
<class>org.test.partyrequest.model.dataobject.RqstTrc</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="eclipselink.target-server" value="WebLogic_10" />
<!-- Logging level is set to INFO, Need to change in Production -->
<property name="eclipselink.logging.level" value="FINE" />
<property name="eclipselink.persistence-context.flush-mode" value="COMMIT" />
<property name="eclipselink.persistence-context.close-on-commit" value="true" />
<property name="eclipselink.cache.shared.default" value="false" />
</properties>
</persistence-unit>
SPRING JPA XML FILE
<context:load-time-weaver aspectj-weaving="on" />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="BasePersistenceUnit" />
</bean>
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter" />
<bean id="transactionManager" class="org.springframework.transaction.jta.WebLogicJtaTransactionManager" />
<!-- ========================= BUSINESS OBJECT DEFINITIONS ========================= -->
<!-- Instruct Spring to perform declarative transaction management automatically on annotated classes. -->
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
<!-- Post-processor to perform exception translation on #Repository classes
(from native exceptions such as JPA PersistenceExceptions to Spring's DataAccessException hierarchy).
-->
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
My Entity calss
#Entity
#Table(name = "PRTY_RQST")
public class PrtyRqst implements Serializable {
private static final long serialVersionUID = -4679712398918736694L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "PRTY_RQST_PRTYRQSTID_GENERATOR")
#SequenceGenerator(name = "PRTY_RQST_PRTYRQSTID_GENERATOR", allocationSize = 1, sequenceName = "PRTY_RQST_SEQ")
#Column(name = "PRTY_RQST_ID")
private Long prtyRqstId;
#Column(name = "CHLD_RQST_IND")
private String chldRqstInd;
#Column(name = "PARNT_PRTY_RQST_ID")
private BigDecimal parntPrtyRqstId;
#Column(name = "PROCES_REFR")
private String procesRefr;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "RQST_DT_TM")
private Date rqstDtTm;
#Column(name = "UPDT_BY")
private String updtBy;
// bi-directional many-to-one association to PrtyKey
#OneToMany(mappedBy = "prtyRqst", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<PrtyKey> prtyKeys;
// bi-directional many-to-one association to PrtyRqstHist
#OneToMany(mappedBy = "prtyRqst", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#OrderBy("rqstDtTm DESC")
private List<PrtyRqstHist> prtyRqstHists;
#OneToOne(mappedBy = "prtyRqst", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private RqstPayload rqstPayload;
// bi-directional many-to-one association to RqstTrc
#OneToMany(mappedBy = "prtyRqst", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<RqstTrc> rqstTrcs;
// bi-directional many-to-one association to AddtnRqstInfo
#OneToMany(mappedBy = "prtyRqst", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<AddtnRqstInfo> addtnRqstInfos;
// bi-directional many-to-one association to BusnApplc
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.REFRESH)
#JoinColumn(name = "BUSN_APPLC_ID")
private BusnApplc busnApplc;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.REFRESH)
#JoinColumn(name = "INTN_PROCES_TYP_ID")
private IntnProcesTyp intnProcesTyp;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.REFRESH)
#JoinColumn(name = "INTN_STATS_ID")
private IntnStat intnStat;
#Column(name = "ORCHESTRATION_ID")
private String orchestrationId;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.REFRESH)
#JoinColumn(name = "ALLW_CHNL_ID")
private AllwChnl allwChnl;
// bi-directional many-to-one association to RqstTyp
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.REFRESH)
#JoinColumn(name = "RQST_TYP_ID")
private RqstTyp rqstTyp;
#Column(name = "TRACK_RQST_IND")
private String trackRqstInd;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "SUBMIT_DT_TM")
private Date submitDtTm;
#Temporal(TemporalType.DATE)
#Column(name = "EFFECTIVE_DT")
private Date effectiveDt;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "RQST_CREATE_DT_TM")
private Date rqstCreateDtTm;
In my DAO IMPL class I have this.persist(prtyRqstDO);
#Transactional(readOnly = true, propagation=Propagation.REQUIRED)
private PartyRequestBO createRequest(PartyRequestBO partyRequestBO, boolean isParent) throws RuntimeException {
if (log.isDebugEnabled()) {
log.debug("Enter: PartyRequestsDAOImpl:createRequest()");
}
partyRequestBO.setOrchestrationID(generateOrchestrationId());
PrtyRqst prtyRqstDO = PartyRequestEntityMapper.partyRequestMapper(partyRequestBO, isParent, true);
try {
this.persist(prtyRqstDO);
partyRequestBO.setRequestIdentifier(prtyRqstDO.getPrtyRqstId());
} catch (Exception e) {
if(log.isDebugEnabled()) {
log.debug("PartyRequestsDAOImpl:createRequest : " + PartyRequestConstants.UNABLE_TO_INSERT, e);
}
throw new PartyRequestDataException(PartyRequestConstants.UNABLE_TO_INSERT, e);
}
if (log.isDebugEnabled()) {
log.debug("Exit: PartyRequestsDAOImpl:createRequest()");
}
return partyRequestBO;
}
#Transactional(readOnly = true, propagation=Propagation.REQUIRED)
public void persist(T entity) {
if (log.isDebugEnabled()) {
log.debug("Enter: BaseDAO:persist() : " + entity);
}
this.getEntityManager().persist(entity);
if (log.isDebugEnabled()) {
log.debug("Exit: BaseDAO:persist()");
}
}
public EntityManager getEntityManager() {
if (log.isDebugEnabled()) {
log.debug("Enter: BaseDAO:getEntityManager() : " + this.entityManager);
}
return this.entityManager;
}
Here the problem is, if i update the row in one of the table through back end my application container is not picking the change.
Can any one Tell me? thank you in advance.
EDIT:
Thank you both of you. I have modified according to your comments added following lines of code.
this.entityManager.clear();
this.entityManager.close();
//this.getEntityManager().refresh(entityManager);
Here i could able to get the update value what i have done it through backend with out restarting server. But the problem is it hold all the changed values.
for example i have changed value to FulOrderWSA it was working. changed to FulorderWSB it was working again.Now i have tried for FulOrderWSZ it didn't work(DB values is FulorderWSB ).
Finally i tried here with old value that is FulorderWSA as per DB it should not work but it worked for me. what i noticed that it is holding all the DB changed values here.
How to get ride of this. I have used both clear and close for entityManager. can any one help me on this.
thank you.
Vijay.
You have turned off the EclipseLink shared cache (AKA second level cache), so the issue is likely that you are holding onto long lived EntityManagers. Once an entity becomes managed by the EM, JPA requires that EM to return that exact instance from every find/query operation as it was when first read and any changes your app might have made to it.
There are a number of options. The best is to look at your EntityManager lifecycle and only obtain an EntityManager when needed, and close it when done. Or, just call em.clear() at points to prevent them from filling up, which will detach all entities associated to the em. Make sure to flush changes though if you wish to keep the changes before calling clear.
If there is a specific entity you need to refresh, em.refresh(entity) will work. This will clear any changes the application might have made though, and can be dangerous with cascade refresh settings mixed with lazy access - so use carefully or you may unintentionally wipe out changes to a whole tree at a later time.
You have caching disabled, so you should see any database changes.
My guess is that you are hold onto a single EntityManager in your DAO. This is very bad, as an EntityManger should be created per transaction, or per request, not held for the duration of the application. It is also not thread safe, so holding onto a single one does not make sense, as it is a transactional object.
You seem to also be using Spring, so it might be proxying the EntityManager underneath and creating one per transaction, but perhaps you have not configured Spring or your transactions correctly.
Include the code the creating/configures the EntityManager.
Thanks,
for all your support. Basically we are not using Cache from EclipseLink. we had bean that handles all the metadata initialization as init method. what we have done is, used JDK Timer to reload the particular Bean to refresh the data. It was working fine.
I have checked the time taking to refresh the all the methods are less than 500 milliseconds. I can foresee only issue when this thread is executing and there is a request.since it is taking less than 500 millisecs its ok for us.
I hope this will be helpful if someone is not using cache you can try this approach.
Thank you.

Is there a way to pass detached object to JPA persist? (detached entity passed to persist)

I have 2 entities : Account and AccountRole.
public class Account {
private AccountRole accountRole;
#ManyToOne(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
public AccountRole getAccountRole() {
return accountRole;
}
.
public class AccountRole {
private Collection<Account> accounts = new ArrayList<Account>();
#OneToMany(mappedBy = "accountRole", fetch = FetchType.EAGER)
public Collection<Account> getAccounts() {
return accounts;
}
Problem comes when I take the accountRole from database and try to persist my Account. At this point I just created my account and role already exists in db.
AccountRole role = accountService.getRoleFromDatabase(AccountRoles.ROLE_USER);
account.setAccountRole(role);
//setting both ways, as suggested
public void setAccountRole(AccountRole accountRole) {
accountRole.addAccount(this);
this.accountRole = accountRole;
}
entityManager.persist(account); // finally in my DAO
I read this : JPA/Hibernate: detached entity passed to persist And what I understood, I must set the entities values from both direction, so that what I am doing in my setter.
Still getting error.
org.hibernate.PersistentObjectException: detached entity passed to persist: foo.bar.pojo.AccountRole
Just replace the
entityManager.persist(account);
with:
entityManager.merge(account);
And allow merge cascading:
#ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE }, fetch = FetchType.EAGER)
public AccountRole getAccountRole() {
return accountRole;
}
Because merge does this:
If your entity is new, it's the same as a persist().
But if your entity already exists, it will update it.
It looks like you leave the transaction during your processing, so the accountRole gets detached, or it is already detached for other reasons.
A call to entityManager.merge(accountRole) before calling entityManager.persist(account) should fix it.
EDIT: Unfortunately, if you cannot be sure if the accountRole already exists in the DB, you will have to check it by querying. If it exists - merge, if not - persist. It is indeed a hassle, but I have not yet seen a better workaround.
EDIT2: The entity you pass to the merge method will remain detached - the managed entity will be returned by the merge, so you would need to merge first, then set the reference on the account to the return value of the merge.
You cannot pass a datached entity to persist, there is no way. But you don't need to.
You want to persist an Account independently of the AccountRole(which is already persisted). In order to achieve this, simply remove cascading from #ManyToOne in the child entity (Account in this case):
public class Account {
private AccountRole accountRole;
#ManyToOne // no cascading here!
public AccountRole getAccountRole() {
return accountRole;
}
See my explanation here, why: https://stackoverflow.com/a/54271569/522578

Categories

Resources