【发布时间】:2016-03-03 20:17:42
【问题描述】:
我的问题与以下内容非常相似:
JPA: How do I add new Items to a List with a OneToMany annotation
Why merging is not cascaded on a one to many relationship
JPA with JTA: Persist entity and merge cascaded child entities
我也查看了Wikibooks,但仍然无法解决我的问题
所以,我的问题是我有一个带孩子的 Parent 类,当我添加一个新孩子并使用 entityManager.merge(parent) 更新新的孩子时,没有插入新的孩子,我得到一个空主键的错误。
我可以用我想要的任何孩子创建一个 Parent,并更新这些孩子,但不能添加新的孩子。
例子:
@Entity
public class Parent {
private String name;
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
private List<Child> children;
}
@Entity
public class Child {
private String name;
@ManyToOne
private Parent parent;
}
如果我创建一个有一些孩子的父母,它工作正常。如果我更新孩子的属性,它可以正常工作,如果我将一个新孩子添加到父母,它就不起作用。
public void foo(){
Parent parent = new Parent();
List<Child> children = new ArrayList<Child>();
children.add(new Child());
children.add(new Child());
children.add(new Child());
parent.setChildren(children);
//it works
entityManager.persist(parent);
//and lets say that I have updated some attributes
changeAttributesValues(parent);
changeAttributesValues(children);
//it still working and the values are updated properly
entityManager.merge(parent);
//but if I add some child
List<Child> children = parent.getChildren();
children.add(moreOneChild);
parent.setChildren(children);
entityManager.merge(parent);
//here I got an error saying that jpa cannot insert my attribute because my PK is null
}
注意:我的 PK 是一个复合键(假设在这个例子中它是 idFromParent + idCompany)
提前致谢。
编辑
我解决了删除复合键并添加自动生成的 ID 的问题。我正在发布我的真实代码以及我为使其工作所做的工作。有了这段代码,
@Entity
public class Serie implements Serializable{
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SERIE_ID_SEQ")
@SequenceGenerator(name = "SERIE_ID_SEQ", sequenceName = "real.serie_id_seq")
@Column(name = "idserie")
private Long id;
@Basic
@Column(name = "nmserie")
private String nmSerie;
@OneToMany(mappedBy = "serie", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
private List<SerieExercise> serieExercises;
@ManyToOne
@JoinColumn(name = "idtrainning")
private Trainning Trainning;
}
@Entity
public class SerieExercise implements Serializable{
@Basic
@Column(name = "nrrepetition")
private int nrRepetition;
@Column(name = "tminterval")
@Temporal(TemporalType.TIMESTAMP)
private Date tmInterval;
@Id
@Basic
@Column(name = "nrorder")
private Integer nrOrder;
@Id
@ManyToOne
@JoinColumn(name = "idexercise")
private Exercise exercise;
@Id
@ManyToOne
@JoinColumn(name = "idserie")
private Serie serie;
}
使用此代码,当我尝试在我的列表中再插入一个 SerieExercise 时出现此错误:
Caused by: org.postgresql.util.PSQLException: ERRO: ERROR: null value in column "nrorder" violates not-null constraint
Detail: Failing row contains(null, 10, null, null, null).
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2270)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1998)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:255)
at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:570)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:420)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:366)
at org.jboss.jca.adapters.jdbc.WrappedPreparedStatement.executeUpdate(WrappedPreparedStatement.java:493)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:208) [hibernate-core-4.3.7.Final.jar:4.3.7.Final]
... 132 more
我进行了调试,并且调用 entityManager.merge() 之前的值不为空。我正在使用休眠提供程序。我可以在列表中插入带有我想要的任何 SerieExercise 的 Serie,并且能够更新值,但无法在我的列表中添加新的 SerieExercise。
为了解决这个问题,我做了以下更改:
@Entity
public class SerieExercise implements Serializable{
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SER_EXER_ID_SEQ")
@SequenceGenerator(name = "SER_EXER_ID_SEQ", sequenceName = "realvida.ser_exer_id_seq")
@Column(name = "idserieexercicio")
private Long id;
@Basic
@Column(name = "nrrepetition")
private int nrRepetition;
@Column(name = "tminterval")
@Temporal(TemporalType.TIMESTAMP)
private Date tmInterval;
//@Id
@Basic
@Column(name = "nrorder")
private Integer nrOrder;
//@Id
@ManyToOne
@JoinColumn(name = "idexercise")
private Exercise exercise;
//@Id
@ManyToOne
@JoinColumn(name = "idserie")
private Serie serie;
}
有人知道为什么会这样吗?我可以使用复合键来完成这项工作吗?
如果您需要更多信息,请告诉我。
【问题讨论】:
-
你在moreOneChild中设置了父级吗?你能举一个更简单的例子吗?
-
抱歉,代码已编辑。看起来问题与具有复合主键有关。我还在研究。
-
我可以让你的保存序列正常工作,所以这没有什么问题。你需要提出一个可重复的问题。如果您有一个复合主键并且您遇到键违规,那么这需要成为您问题的基础
-
知道了,谢谢提示,这是我的 seconf 问题,下次我会尝试改进我的问题。
-
当您尝试在列表中再插入一个 SerieExercise 时,代码在哪里?