java 当我们使用合并时,JPA 不会从一对多关系插入新的孩子

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35782167/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 00:34:54  来源:igfitidea点击:

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

javahibernatejpa

提问by Klinsman Maia

My question is pretty similar to the following:

我的问题与以下内容非常相似:

JPA: How do I add new Items to a List with a OneToMany annotation

JPA:如何使用 OneToMany 注释将新项目添加到列表中

Why merging is not cascaded on a one to many relationship

为什么合并不在一对多关系上级联

JPA with JTA: Persist entity and merge cascaded child entities

JPA 与 JTA:持久化实体并合并级联子实体

I also had a look in Wikibooksbut 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.

所以,我的问题是我有一个带有孩子的 Parent 类,当我添加一个新孩子并使用 entityManager.merge(parent) 更新新孩子时,没有插入新的孩子,我得到一个空主键的错误。

I'm able to create a Parent with whatever children I want, and update theses children, but not to add a new child.

我可以用我想要的任何孩子创建一个 Parent,并更新这些孩子,但不能添加一个新孩子。

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)

注意:我的 PK 是一个复合键(让我们在这个例子中说它是 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,

我解决了删除复合键并添加自动生成的 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;
}

With this code I get this error when I try to insert one more SerieExercise in my List:

使用此代码,当我尝试在列表中再插入一个 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

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.

我进行了调试,并且在调用 entityManager.merge() 之前的值不为空。我正在使用休眠提供程序。我可以在我的列表中插入一个带有我想要的任何 SerieExercise 的 Serie,并且能够更新值,但不能在我的列表中添加一个新的 SerieExercise。

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.

如果您需要更多信息,请告诉我。

采纳答案by WesternGun

I think your mapping at child side looks wrong to me. You must maintain this @ManyToOne relationship like this:

我认为您在儿童方面的映射对我来说是错误的。您必须像这样保持这种@ManyToOne 关系:

@ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
@JoinColumn(name="idParent", nullable=false)
private Parent parent;

I mean, usually at the owner side of a @ManyToOnerelationship you must use @JoinColumn. Maybe irrevelent but worth mentioning.

我的意思是,通常在@ManyToOne关系的所有者方面,您必须使用@JoinColumn. 也许无关紧要但值得一提。

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?

此外,我们希望看到完整的代码和完整的堆栈跟踪,尤其是子 ID 映射(复合 ID 可能是也可能不是原因,但请提供完整代码)。说到 ID 重新生成,有时底层数据库和 JPA 实现库很重要。您在使用 EclipseLink、Toplink 还是其他什么?

回答by mwarren

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);