Я получаю следующую ошибку при сохранении объекта с помощью Hibernate
object references an unsaved transient instance - save the transient instance before flushing
Я получаю следующую ошибку при сохранении объекта с помощью Hibernate
object references an unsaved transient instance - save the transient instance before flushing
Вы должны включить cascade="all"
(если используете xml) или cascade=CascadeType.ALL
(если используете аннотации) в своем сопоставлении коллекции.
Это происходит потому, что у вас есть коллекция в вашей сущности, и эта коллекция имеет один или несколько элементов, которых нет в базе данных. Задав указанные выше параметры, вы указываете спящий режим сохранять их в базе данных при сохранении их родительского элемента.
Я считаю, что это может быть просто повторный ответ, но для уточнения я получил это на картинке @OneToOne
, а также @OneToMany
. В обоих случаях это был тот факт, что объект Child
, который я добавлял в Parent
, еще не был сохранен в базе данных. Поэтому, когда я добавил Child
в Parent
, а затем сохранил Parent
, Hibernate будет бросать сообщение "object references an unsaved transient instance - save the transient instance before flushing"
при сохранении родителя.
Добавление в cascade = {CascadeType.ALL}
ссылки Parent's
на Child
решило проблему в обоих случаях. Это сохранили Child
и Parent
.
Извините за любые повторные ответы, просто хотел прояснить для людей.
@OneToOne(cascade = {CascadeType.ALL})
@JoinColumn(name = "performancelog_id")
public PerformanceLog getPerformanceLog() {
return performanceLog;
}
Это происходит при сохранении объекта, когда Hibernate считает, что ему нужно сохранить объект, связанный с тем, который вы сохраняете.
У меня была эта проблема и я не хочу сохранять изменения для объекта, на который ссылается, поэтому я хотел, чтобы тип каскада был NONE.
Трюк заключается в том, чтобы убедиться, что идентификатор и VERSION в указанном объекте установлены так, чтобы Hibernate не думал, что ссылочный объект является новым объектом, который требует сохранения. Это сработало для меня.
Просмотрите все отношения в классе, который вы сохраняете, для разработки связанных объектов (и связанных объектов связанных объектов) и убедитесь, что ID и VERSION установлены во всех объектах дерева объектов.
Или, если вы хотите использовать минимальные "полномочия" (например, если вы не хотите каскадное удаление) для достижения желаемого, используйте
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
...
@Cascade({CascadeType.SAVE_UPDATE})
private Set<Child> children;
В моем случае это было вызвано отсутствием CascadeType
на стороне @ManyToOne
двунаправленного отношения. Чтобы быть более точным, я имел CascadeType.ALL
на стороне @OneToMany
и не имел его на @ManyToOne
. Добавление CascadeType.ALL
в @ManyToOne
разрешило проблему.
Сторона "один-ко-многим" :
@OneToMany(cascade = CascadeType.ALL, mappedBy="globalConfig", orphanRemoval = true)
private Set<GlobalConfigScope>gcScopeSet;
Многосторонняя сторона (вызвала проблему)
@ManyToOne
@JoinColumn(name="global_config_id")
private GlobalConfig globalConfig;
Много-к-одному (исправлено добавлением CascadeType.PERSIST
)
@ManyToOne(cascade = CascadeType.PERSIST)
@JoinColumn(name="global_config_id")
private GlobalConfig globalConfig;
Это произошло для меня при сохранении объекта, в котором существующая запись в базе данных имела значение NULL для поля, аннотированного с помощью @Version (для оптимистической блокировки). Обновление значения NULL до 0 в базе данных исправило это.
Это не единственная причина ошибки. Я столкнулся с этим только сейчас для ошибки опечатки в моей кодировке, которая, как я полагаю, установила значение объекта, который уже был сохранен.
X x2 = new X();
x.setXid(memberid); // Error happened here - x was a previous global entity I created earlier
Y.setX(x2);
Я обнаружил ошибку, обнаружив точно, какая переменная вызвала ошибку (в данном случае String xid
). Я использовал catch
вокруг всего блока кода, который сохранил объект и напечатал трассировки.
{
code block that performed the operation
} catch (Exception e) {
e.printStackTrace(); // put a break-point here and inspect the 'e'
return ERROR;
}
Если ваша коллекция имеет значение NULL, просто попробуйте: object.SetYouColection(null);
Не используйте Cascade.All
, пока вам не понадобится. Role
и Permission
имеют двунаправленное отношение manyToMany
. Тогда следующий код будет работать нормально
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, если объект является просто "новым", тогда он будет вызывать ту же ошибку.
Чтобы добавить мои 2 цента, у меня возникла такая же проблема, когда я случайно отправил null
в качестве идентификатора. Ниже кода изображен мой сценарий (и OP не упоминает какой-либо конкретный сценарий).
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);
Здесь я устанавливаю существующий идентификатор отдела на новый экземпляр сотрудника без фактического получения элемента отдела сначала, так как я не хочу, чтобы другой запрос был выбран.
В некоторых сценариях deptId
PKID приходит как null
из метода вызова, и я получаю ту же ошибку.
Итак, обратите внимание на значения null
для PK ID
Я получаю эту ошибку, когда я использую
getSession().save(object)
но он работает без проблем, когда я использую
getSession().saveOrUpdate(object)
Помимо всех других хороших ответов, это может произойти, если вы используете merge
для сохранения объекта и случайно забываете использовать объединенную ссылку объекта в родительском классе. рассмотрим следующий пример
merge(A);
B.setA(A);
persist(B);
В этом случае вы объединяете A
, но забудьте использовать объединенный объект A
. для решения проблемы вы должны переписать код следующим образом.
A=merge(A);//difference is here
B.setA(A);
persist(B);
Еще одна возможная причина: в моем случае я пытался сохранить ребенка перед сохранением родителя на совершенно новом объекте.
В модели User.java код был примерно таким:
this.lastName = lastName;
this.isAdmin = isAdmin;
this.accountStatus = "Active";
this.setNewPassword(password);
this.timeJoin = new Date();
create();
Метод setNewPassword() создает запись в формате PasswordHistory и добавляет ее в коллекцию истории в User. Поскольку оператор create() еще не был выполнен для родителя, он пытался сохранить коллекцию объекта, который еще не был создан. Все, что мне нужно было сделать, чтобы исправить это, было перемещение вызова setNewPassword() после вызова create().
this.lastName = lastName;
this.isAdmin = isAdmin;
this.accountStatus = "Active";
this.timeJoin = new Date();
create();
this.setNewPassword(password);
Есть еще одна возможность, которая может вызвать эту ошибку в спящем режиме. Вы можете установить несохраненную ссылку вашего объекта A
на прикрепленный объект B
и хотите сохранить объект C
. Даже в этом случае вы получите вышеупомянутую ошибку.
Если вы используете Spring Data JPA, то добавление аннотации @Transactional
к вашей реализации сервиса решит проблему.
Ради полноты: A
org.hibernate.TransientPropertyValueException
с сообщением
object references an unsaved transient instance - save the transient instance before flushing
также произойдет, когда вы попытаетесь сохранить/объединить сущность со ссылкой на другую сущность, которая оказывается отсоединенной.
Я тоже столкнулся с такой же ситуацией. Установив следующую аннотацию над свойством, оно решает вопрос об исключении.
Исключение, с которым я столкнулся.
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
Чтобы преодолеть, аннотации я использовал.
@OneToMany(cascade = {CascadeType.ALL})
@Column(name = "ListOfCarsDrivenByDriver")
private List<Car_OneToMany> listOfCarsBeingDriven = new ArrayList<Car_OneToMany>();
Что заставило Hibernate бросить исключение:
Это исключение выдается на вашей консоли, потому что дочерний объект, который я присоединяю к родительскому объекту, в данный момент отсутствует в базе данных.
Предоставляя @OneToMany(cascade = {CascadeType.ALL})
, он сообщает Hibernate о сохранении их в базе данных при сохранении родительского объекта.
Простым способом решения этой проблемы является сохранение обоих объектов. сначала сохраните дочерний объект, а затем сохраните родительский объект. Поскольку родительский объект зависит от дочернего объекта для значения внешнего ключа.
Ниже простого изучения отношения "один к одному"
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);
Одной из возможных причин ошибки является отсутствие установки значения родительского объекта; например, для отношений между отделом и сотрудниками вы должны написать это, чтобы исправить ошибку:
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);
Существует так много возможностей этой ошибки, некоторые другие возможности также можно добавить на странице или странице редактирования. В моем случае я пытался сохранить объект AdvanceSalary. Проблема в том, что в редакции AdvanceSalary employee.employee_id имеет значение null. Поскольку при редактировании я не был установлен employee.employee_id. Я создал скрытое поле и установил его. мой код работает абсолютно нормально.
@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;
}
}
Я столкнулся с этим исключением, когда я не сохранил родительский объект, но я сохранял дочерний объект. Чтобы решить эту проблему, в одном сеансе я сохранил как дочерний, так и родительский объекты и использовал CascadeType.ALL для родительского объекта.
Я думаю, потому что вы пытаетесь сохранить объект, который имеет ссылку на другой объект, который еще не сохранен, и поэтому он пытается в "стороне БД" поместить ссылку на несуществующую строку
Случай 1: я получал это исключение, когда пытался создать родителя и сохранить эту родительскую ссылку на его потомка, а затем какой-то другой запрос DELETE/UPDATE (JPQL). Поэтому я просто сбрасываю() вновь созданную сущность после создания родителя и после создания дочернего элемента, используя ту же родительскую ссылку. Это сработало для меня.
Случай 2:
Родительский класс
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;
.
.
.
}
Детский класс:
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;
.
.
}
В приведенном выше случае, когда родительский объект (Reference) и дочерний элемент (ReferenceAdditionalDetails) имеют отношение OneToOne, а также при попытке создания ссылочного объекта, а затем его дочернего элемента (ReferenceAdditionalDetails), вы получите одно и то же исключение. Поэтому, чтобы избежать исключения, вы должны установить значение null для дочернего класса, а затем создать родительский. (Пример кода)
.
.
reference.setRefAddDetails(null);
reference = referenceDao.create(reference);
entityManager.flush();
.
.
Эта проблема возникла у меня, когда я создал новую сущность и связанную сущность в методе, помеченном как @Transactional
, а затем выполнил запрос перед сохранением. бывший
@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);
}
Чтобы исправить, я выполнил запрос перед созданием новой сущности.