使用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
Answers:
您应该在集合映射中包括cascade="all"
(如果使用xml)或cascade=CascadeType.ALL
(如果使用注释)。
发生这种情况是因为您的实体中有一个集合,并且该集合具有一个或多个数据库中不存在的项。通过指定以上选项,您可以告诉hibernate在保存其父项时将它们保存到数据库中。
我相信这可能只是重复的答案,但为了澄清起见,我在@OneToOne
映射和上都得到了这个@OneToMany
。在这两种情况下,都是Child
我要添加到的对象Parent
尚未保存在数据库中的事实。因此,当我将,添加Child
到Parent
,然后保存时Parent
,"object references an unsaved transient instance - save the transient instance before flushing"
在保存Parent时,Hibernate会抛出该消息。
在这两种情况下,都cascade = {CascadeType.ALL}
将Parent's
参考文献添加到已Child
解决的问题中。这保存了Child
和Parent
。
对于任何重复的回答,我们深表歉意,只是想为大家进一步澄清。
@OneToOne(cascade = {CascadeType.ALL})
@JoinColumn(name = "performancelog_id")
public PerformanceLog getPerformanceLog() {
return performanceLog;
}
new MyEntity
(而不是将其同步到数据库-刷新)来创建您的实体对象,而不是从数据库中获取了它的同步实例。使用该实例进行Hibernate查询会通知您,数据库中的预期内容与应用程序内存中的内容有所不同。在这种情况下,只需从DB同步/获取实体不稳定并使用它即可。则不需要CascadeType.ALL。
当Hibernate认为需要保存与要保存的对象关联的对象时,在保存对象时会发生这种情况。
我遇到了这个问题,不想保存对引用对象的更改,因此我希望级联类型为NONE。
诀窍是确保设置引用对象中的ID和VERSION,以便Hibernate认为引用对象不是需要保存的新对象。这对我有用。
浏览要保存的类中的所有关系,以计算出关联的对象(以及关联的对象的关联对象),并确保在对象树的所有对象中都设置了ID和VERSION。
正如我在本文中解释的那样,当使用JPA和Hibernate时,实体可以处于以下4种状态之一:
新建 -从未与Hibernate会话(也称为持久性上下文)相关联且未映射到任何数据库表行的新创建的对象被视为处于“新建”或“瞬态”状态。
为了持久化,我们需要显式调用该persist
方法或使用可传递持久性机制。
持久 -持久实体已与数据库表行关联,并由当前正在运行的持久性上下文进行管理。
(在会话刷新期间)将检测到对此类实体所做的任何更改并将其传播到数据库。
分离 -当前运行的持久性上下文关闭后,所有先前管理的实体都将分离。不再跟踪连续的更改,并且不会发生自动数据库同步。
删除 -尽管JPA要求只允许删除托管实体,但是Hibernate也可以删除分离的实体(但只能通过remove
方法调用)。
从一个状态移动实体到另一个,你可以使用persist
,remove
或merge
方法。
您在问题中描述的问题:
object references an unsaved transient instance - save the transient instance before flushing
是由于将处于New状态的实体与处于Managed状态的实体相关联而引起的 。
当您将子实体与父实体中的一对多集合相关联并且该集合没有cascade
实体状态转换时,可能会发生这种情况。
因此,正如我在本文中所解释的,您可以通过将级联添加到触发此失败的实体关联中来解决此问题,如下所示:
@OneToOne
协会@OneToOne(
mappedBy = "post",
orphanRemoval = true,
cascade = CascadeType.ALL)
private PostDetails details;
注意
CascadeType.ALL
我们为cascade
属性添加的值。
@OneToMany
协会@OneToMany(
mappedBy = "post",
orphanRemoval = true,
cascade = CascadeType.ALL)
private List<Comment> comments = new ArrayList<>();
同样,sCascadeType.ALL
适用于双向@OneToMany
关联。
现在,为了使级联在双向上正常工作,您还需要确保父级和子级关联是同步的。
请查看本文,以获得有关实现此目标的最佳方法的更多详细信息。
@ManyToMany
协会@ManyToMany(
mappedBy = "authors",
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
}
)
private List<Book> books = new ArrayList<>();
在@ManyToMany
关联中,您不能使用,CascadeType.ALL
否则orphanRemoval
将导致删除实体的状态转换从一个父实体传播到另一父实体。
因此,对于@ManyToMany
关联,您通常会级联CascadeType.PERSIST
or CascadeType.MERGE
操作。或者,您可以将其扩展为DETACH
或REFRESH
。
有关映射
@ManyToMany
关联的最佳方法的更多详细信息,请参见本文。
或者,如果您想使用最少的“功能”(例如,如果您不想级联删除)来实现所需的功能,请使用
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
...
@Cascade({CascadeType.SAVE_UPDATE})
private Set<Child> children;
@ManyToMany(cascade={PERSIST, MERGE, REFRESH, DETACH})
(除REMOVE之外的所有)不像Hibernate那样级联更新CascadeType.SAVE_UPDATE
。
在我的情况下,它是由尚未造成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;
对于我来说,当持久保存一个实体时,在数据库中现有记录的@Version注释字段具有NULL值(用于乐观锁定)时,会发生这种情况。在数据库中将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;
}
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);
而如果对象只是一个“新”对象,那么它将抛出相同的错误。
要加上我的2美分,当我不小心发送null
ID 时遇到了同样的问题。下面的代码描述了我的情况(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);
在这里,我将现有部门ID设置为新的员工实例,而实际上并没有首先获取部门实体,因为我不想触发另一个选择查询。
在某些情况下,deptId
PKID null
来自调用方法,并且出现相同的错误。
因此,请注意null
PK ID的值
当我在标记为的方法中创建一个新实体和一个关联实体@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);
}
为了解决这个问题,我在创建新实体之前执行了查询。
我也面临同样的情况。通过在属性上方设置以下注释,可以解决提示的异常。
我遇到的例外。
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在保存父对象的同时将它们保存到数据库。
另一个可能的原因:在我的情况下,我试图在一个全新的实体上保存孩子之前先保存孩子。
代码在User.java模型中是这样的:
this.lastName = lastName;
this.isAdmin = isAdmin;
this.accountStatus = "Active";
this.setNewPassword(password);
this.timeJoin = new Date();
create();
setNewPassword()方法创建一个PasswordHistory记录,并将其添加到User的历史记录集合中。由于尚未为父级执行create()语句,因此它试图将其保存到尚未创建的实体的集合中。我要解决的所有事情就是在调用create()之后移动setNewPassword()调用。
this.lastName = lastName;
this.isAdmin = isAdmin;
this.accountStatus = "Active";
this.timeJoin = new Date();
create();
this.setNewPassword(password);
我认为是因为您已尝试持久保存一个具有对另一个尚未持久的对象的引用的对象,因此它尝试在“ DB端”中将对不存在的行的引用
解决此问题的简单方法是保存两个实体。首先保存子实体,然后保存父实体。因为父实体依赖于子实体作为外键值。
下面是一对一关系的简单考试
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);
此错误的可能性很大,添加页面或编辑页面上也有其他可能性。以我为例,我试图保存一个对象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;
.
.
}
在上述具有OneToOne关系的parent(Reference)和child(ReferenceAdditionalDetails)的情况下,当您尝试创建Reference实体然后创建其child(ReferenceAdditionalDetails)时,它将给您相同的例外。因此,为避免发生异常,您必须为子类设置null,然后创建父类。(示例代码)
.
.
reference.setRefAddDetails(null);
reference = referenceDao.create(reference);
entityManager.flush();
.
.
只需在基类中构造映射的构造函数即可。就像您要实体A,实体B中的一对一关系一样。如果您将A作为基类,则A必须具有一个构造函数,其中B作为参数。