2012-03-02 44 views
37

我有一个关于从小孩的entites IR 引用ParentEntities问题,如果我有这样的事情:JPA @OneToMany - >父 - 子引用(外键)

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

而Child.java:

@Entity(name ="Child") 
public class Child{ 
    @Id 
    @Generate.... 
    @Column 
    private int id; 

    @ManyToOne 
    private Parent parent; 

    ... simple getter an 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 100 

但那不是这样的,你必须明确地对家长设置为儿童(其中,我认为,框架很可能通过做本身)。

那么什么真正的数据库是这样的:

Parent: 
    id 
    100 

Child 
    id  paren_id 
    101 (null) 

因为我还没有家长设置为儿童。所以我的问题:

我真的必须做某事。喜欢这个?

Parent.java:

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

    this.children = children; 
} 
... 

编辑:

根据快速回复我能够通过使用基准拥有实体的@JoinColumn来解决这个问题。如果我们从上面看例子,我做了某事。像这样:

Parent.java:

@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 ... 
    } 

而且Child.java:

@Entity(name ="Child") 
public class Child{ 
    @Id 
    @Generate.... 
    @Column 
    private int id; 

    ... simple getter an 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); 
    } 

引用是正确的设置父母:

Parent: 
    id 
    100 

Child 
    id  paren_id 
    101 100 

感谢您的答复。

+0

**您是否有父项子项实体?**如果是,他们是如何配置的。没有父母我得到错误(_StaleStateException:批量更新返回来自update [0]的意外行数;实际行数:0;预期:1_)。如果我添加没有注释的父项,它也会显示错误(映射错误)。在child的父字段上设置@manytoone,我在保存时出错(_ORA-00904:“REPORT_REPORT_ID”:недопустимыйидентификатор_)。我的fk和它的pk上的id命名为report_id,但我不知道report_report_id在哪里。 – Erlan 2015-08-07 05:11:01

+0

(使用EclipseLink JPA实现)。值得注意的是你仍然需要@Column(name =“paren_id”)private long parenId;绘制你的孩子这个工作。 – AfterWorkGuinness 2015-09-23 14:57:20

回答

12

我真的必须做某事吗?喜欢这个?

这是一个策略,是的。

关于双向关系,关系有一个“拥有”和“非拥有”的一面。由于您的案例中的拥有方位于Child,因此您需要在该处设置关系以使其保留。拥有方通常由您指定@JoinColumn的位置决定,但它看起来并不像您使用该注释,因此可能是因为您在Parent注释中使用了mappedBy这一事实。您可以read a lot more about this here

3

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

在JPA 2。0规范,这是用下面的话称:

注意,它是承担责任 维护运行时的一致性应用的关系,例如,对于 确保了“一”和“多“当应用程序 在运行时更新关系时,双向关系的边相互一致。

1

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

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

org.hibernate.exception.GenericJDBCException:字段“paren_id”没有默认值

为别人谁可能碰到这个,有什么我们最终发现的是,我们不得不另一个属性到@JoinColumn得到它的工作:

@JoinColumn(name =“paren_id”,可为空= FALSE)

0

如果我正确地得到你,根据EntityManager,如果哟你想要它管理交易的插入顺序,你必须“告诉他”它应该坚持孩子们。你不这样做,所以“他”不知道要坚持什么,但你父母的子女名单不是空的,所以“他”认为它是正确的,但存储的值为空。

所以,你应该考虑这样做:

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

做你想做的与父对象这里然后提交,这应该对类似案件工作了。

1

它似乎仍然是这种情况。在父母Entity你可以在为了避免在代码的其他地方设置父/子关系的重复代码类似

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

+0

!!在我卡住了阿隆莫斯2周之后的好人。我尝试从客户端发送JSON并将其转换为使用Spring的@RequestBody的对象,然后保存到分区 我不想通过我自己管理关系(将父项设置为子项 - 对我来说没有意义) – WRDev 2018-02-15 03:42:31

+0

!!!更新!关于@PrePersist的链接(您可以通过@EntityListener管理) 请参阅 - https://www.concretepage.com/java/jpa/jpa-entitylisteners-example-with-callbacks-prepersist-postpersist-postload-preupdate-postupdate -preremove,删除后 – WRDev 2018-02-15 04:07:22