Java JPA@OneToMany->;父-子引用(外键)

Java JPA@OneToMany->;父-子引用(外键),java,hibernate,jpa,parent-child,one-to-many,Java,Hibernate,Jpa,Parent Child,One To Many,我有一个关于从子实体引用父实体的问题 如果我有这样的东西: org.hibernate.exception.GenericJDBCException: Field 'paren_id' doesn't have a default value Parent.java: @Entity(name ="Parent") public class Parent { @Id @Generate..... @Column private int id;

我有一个关于从子实体引用父实体的问题 如果我有这样的东西:

org.hibernate.exception.GenericJDBCException: Field 'paren_id' doesn't have a default value
Parent.java:

@Entity(name ="Parent")
public class Parent {
    @Id
    @Generate.....
    @Column
    private int id;
   
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "parent")
    private Set<Child> children;

    simple ... getter and setter ...
}
...
setChildren(Set<Child> children) {
    for (Child child : children) {
        child.setParent.(this);
    }

    this.children = children;
}
...
@Entity(name ="Parent")
public class Parent {
    @Id
    @Generate.....
    @Column
    private int id;
    
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name= "paren_id")
    private Set<Child> children;
    
    simple ... getter and setter ...
}
将创建以下表格:

Parent:
     int id

Child:
     int id
     int parent_id (foreign key: parent.id)
好的,到目前为止,一切都很好。但是当涉及到使用来自Java的这个引用时,我认为,您可以这样做

@Transactional
public void test() {
    Parent parent = new Parent();
    Child child = new Child();

    Set<Child> children = new HashSet<Child>();
    children.add(child);
    parent.setChildren(children);
    entityManager.persist(parent);
}
但事实并非如此,您必须明确地将父对象设置为子对象(我认为,框架本身可能会这样做)

所以数据库中真正的内容是:

Parent:
     id
     100

Child
     id     paren_id
     101    (null)
因为我没有将父对象设置为子对象。因此,我的问题是:

我真的必须这样做吗?

Parent.java:

@Entity(name ="Parent")
public class Parent {
    @Id
    @Generate.....
    @Column
    private int id;
   
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "parent")
    private Set<Child> children;

    simple ... getter and setter ...
}
...
setChildren(Set<Child> children) {
    for (Child child : children) {
        child.setParent.(this);
    }

    this.children = children;
}
...
@Entity(name ="Parent")
public class Parent {
    @Id
    @Generate.....
    @Column
    private int id;
    
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name= "paren_id")
    private Set<Child> children;
    
    simple ... getter and setter ...
}
现在如果我们这样做:

@Transactional
public void test() {
    Parent parent = new Parent();
    Child child = new Child();

    Set<Child> children = new HashSet<Child>();
    children.add(child);

    parent.setChildren(children);
    entityManager.persist(parent);
}

是的,就是这样。JPA并不关心实体图的一致性。特别是,您必须将其设置为双向关系的所有者端(在您的情况下,设置为Child的parent属性)

在JPA 2.0规范中,这用以下词语表示:

请注意,应用程序负责 维护运行时关系的一致性,例如, 为了确保一个政党的“一”和“多”面 当应用程序 在运行时更新关系

我真的必须这样做吗

这是一个策略,是的

在双向关系中,关系有“拥有”和“不拥有”两个方面。因为您案例中的拥有方位于
Child
,所以您需要在那里设置关系,以便将其持久化。拥有方通常由指定
@JoinColumn
的位置决定,但它看起来不像是在使用该注释,因此它很可能是从您在
父注释中使用
mappedBy
这一事实推断出来的


您可以。

我们在保存上面所示的简单对象图时遇到了问题。在H2中运行一切都可以,但是当我们在MySQL上运行时,子表(在@JoinColumn注释中定义)中的“paren_id”没有被父表的生成id填充,即使它在DB中被设置为带有外键约束的非空列

我们会得到这样一个例外:

org.hibernate.exception.GenericJDBCException: Field 'paren_id' doesn't have a default value
对于其他可能遇到这种情况的人,我们最终发现我们必须为
@JoinColumn
添加另一个属性才能使其正常工作:

@JoinColumn(name="paren_id", nullable=false)

根据
EntityManager
,如果我没有弄错,如果你想让它管理事务的插入顺序,你必须“告诉他”它也应该保留子事务。您没有这样做,所以“他”不知道要保存什么,但是您父母的子列表不是空的,所以“他”认为它是正确的,但是存储的值是空的

所以你应该考虑这样做:

... begin, etc
em.persist(child)
em.persist(parent)

在这里对父对象执行您想要的操作,然后提交,这也适用于类似的情况。

情况似乎仍然如此。在父级
实体中
可以有

@PrePersist
private void prePersist() {
   children.forEach( c -> c.setParent(this));
}

为了避免在代码中的其他位置重复设置子/父关系的代码。

是否有子实体上的父实体?如果是,它们是如何配置的。没有父级时,我收到错误(StaleStateException:批更新从更新[0]返回意外的行数;实际行数:0;应为1)。如果我添加没有注释的父对象,它也会显示错误(映射错误)。在子项的父字段上设置@manytoone时,我在保存时出现错误(ORA-00904:“报告”报告ID:“报告”。我的fk和它在id上的pk名为report_id,但我不知道report_report_id从哪里来(使用EclipseLink JPA实现)。值得注意的是,您仍然需要@Column(name=“paren\u id”)私有长parenId;为您的孩子映射此wot工作。!!在我孤独了两个星期之后,他是个好人。我尝试从客户端发送json,并使用spring的@RequestBody转换为对象,然后保存到db,我不想自己管理关系(将父对象设置为子对象——对我来说没有意义)!!!更新!!!关于@PrePersist的链接(您可以由@EntityListener管理)请参见--Nice man!!这节省了大量的精力,也优化了性能。出于某种原因,我在
@PrePersist
子级上得到了
NullPointerException
。forEach
@guneetgstar可能您的
子级
就是空的。首先初始化它?将
nullable=false
也修复了我在OneToMany上的问题。然而,对于我的一个人来说,我仍然得到了例外。关于如何处理这种情况,有什么建议吗?我也尝试过这个,但运气不好,如果有问题的话,我也在使用MySQL。你能分享代码吗?