问题
My question is pretty similar to the following:
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
I also had a look in Wikibooks but still not able to fix my problem
So, my problem is that I have a Parent class with childs, and when I add a new child and use entityManager.merge(parent) to update the new children are not inserted and I get an error of null primary key.
I'm able to create a Parent with whatever children I want, and update theses children, but not to add a new child.
Example:
@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;
}
If I create a Parent with some children it works fine. If I update the children's attributes it works fine, and if I add a new child to parent it does not work.
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
}
Note: My PK is a composite Key (lets say in this example that it is the idFromParent + idCompany)
Thanks in advance.
EDIT
I solved the problem removing the composite key and adding an auto generated ID. I'm posting my real code and what I have done to make it work. With this code,
@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;
}
With this code I get this error when I try to insert one more SerieExercise in my List:
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
I have debugging and the values before I call entityManager.merge() are not null. I'm using hibernate provider. I'm able to insert a Serie with whatever SerieExercise I want in my list, and able to update the values, but not able to add a new SerieExercise in my List.
To fix I made these changes:
@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;
}
Does anyone know why it happens? Can I make this work using a composite key?
Let me know if you need more info.
回答1:
I think your mapping at child side looks wrong to me. You must maintain this @ManyToOne relationship like this:
@ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
@JoinColumn(name="idParent", nullable=false)
private Parent parent;
I mean, usually at the owner side of a @ManyToOne
relationship you must use @JoinColumn
. Maybe irrevelent but worth mentioning.
Also, we want to see full code and full stacktrace, especially the child ID mapping(a composite id may be or nothe reason, but full code please). When it comes to ID regeneration, sometimes underlying database and JPA implementation library can matter. Are you using EclipseLink, Toplink or something else?
回答2:
This line of code looks wrong to me:
parent.addChildren(moreOneChild);
I would have thought it should be something like this:
List<Child> children = parent.getChildren();
children.add(moreOneChild);
entityManager.merge(parent);
来源:https://stackoverflow.com/questions/35782167/jpa-does-not-insert-new-childs-from-one-to-many-relationship-when-we-use-merge