当我们使用合并时,JPA不会从一个到多个关系插入新的子元素

时间:2016-03-03 20:17:43

标签: java hibernate jpa

我的问题非常类似于以下内容:

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

有谁知道为什么会这样?我可以使用复合键来完成这项工作吗?

如果您需要更多信息,请与我们联系。

2 个答案:

答案 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还是其他什么东西?