JPA does not insert new childs from one to many relationship when we use merge

邮差的信 提交于 2021-02-10 10:54:32

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!