我的问题非常类似于以下内容:
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)来更新时,未插入新的子节点并且我得到null主键的错误。
我可以创建一个包含我想要的孩子的父母,并更新这些孩子,但不要添加新的孩子。
示例:
@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()之前的值不为null。我正在使用hibernate提供程序。我可以在我的列表中插入一个Serie以及我想要的任何SerieExercise,并且能够更新值,但是无法在我的列表中添加新的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;
}
有谁知道为什么会这样?我可以使用复合键来完成这项工作吗?
如果您需要更多信息,请与我们联系。
答案 0 :(得分:0)
这行代码对我来说不对:
parent.addChildren(moreOneChild);
我原以为它应该是这样的:
List<Child> children = parent.getChildren();
children.add(moreOneChild);
entityManager.merge(parent);
答案 1 :(得分:0)
我认为你在儿童方面的映射对我来说是错误的。你必须保持这样的@ManyToOne关系:
linkaxes([ax2,ax4], 'x');
我的意思是,通常在@ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
@JoinColumn(name="idParent", nullable=false)
private Parent parent;
关系的所有者方面,您必须使用@ManyToOne
。也许是不懈的,但也值得一提。
此外,我们希望看到完整的代码和完整的堆栈跟踪,尤其是子ID映射(复合ID可能是或不是原因,但请完整代码)。在ID重新生成方面,有时候底层数据库和JPA实现库很重要。您使用的是EclipseLink,Toplink还是其他什么东西?