简体   繁体   English

Hibernate中的OneToMany单向映射。 在引用实体中设置外键设置

[英]OneToMany unidirectional mapping in Hibernate. Issue setting foreign key in referenced entity

Say there are two entities: Parent and Child , with @OneToMany mapping from Parent to Child . 假设有两个实体: ParentChild ,其中@OneToMany映射从ParentChild

class Parent {
    @Column(name="id")
    private Long id;

    @OneToMany(cascade=CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "parent_id", referencedColumnName = "id")
    private List<Child> children;
}

class Child {
    @Column(name="id")
    private Long id;

    @Column(name="parent_id")
    private Long parentId;
}

As you can see, in my case, the Child table stores a foreign key to the Parent 's primary key. 如您所见,在我的例子中, Child表将一个外键存储到Parent的主键中。 But I don't want that as bi-directional mapping in my Child entity. 但我不希望这在我的Child实体中作为双向映射。

The issue arises now is, I'm unable to set the parent_id in Child instances. 现在出现的问题是,我无法在Child实例中设置parent_id

I've created instances like this: 我创建了这样的实例:

Parent parent = new Parent();
parent.setChildren(Lists.newArrayList(new Child(), new Child()));
parentDomainService.save(parent);

Assuming that there is cascading on Parent end. 假设父端有级联。 This approach saves the Parent first, then saves the Child instances. 此方法首先保存Parent,然后保存Child实例。 And then it runs the update query on child instances to update the parent_id , as I see from the Hibernate show_sql logs. 然后它在子实例上运行更新查询以更新parent_id ,正如我从Hibernate show_sql日志中看到的那样。 But surprisingly, after update query, I see for some of the child , the parent_id is null . 但令人惊讶的是,在更新查询后,我看到一些childparent_idnull That was surprising to me. 这让我感到惊讶。

So, I went to handle that thing manually, and removed cascading. 所以,我去手动处理那个东西,并删除了级联。 Then I saved the entities like this: 然后我保存了这样的实体:

Parent parent = new Parent();
parent.setChildren(Lists.newArrayList(new Child(), new Child()));
parent = parentDomainService.save(parent);

for (Child child: parent.getChildren()) {
    child.setParentId(parent.getId());
} 

childDomainService.save(parent.getChildren());

This one bounced back on me with following exception: 这一个反弹在我身上,但有以下异常:

org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.somepkg.Child

I've seen many questions on SO with that exception, and I know there are many out there, but almost all of them are dealing with bi-directional mapping, or uni-directional mapping with JoinTable. 我已经在SO上看到了很多关于异常的问题,我知道有很多问题,但是几乎所有这些问题都涉及双向映射,或者使用JoinTable进行单向映射。 Neither of them suits my situation. 它们都不适合我的情况。

Any lights on this? 这有什么灯吗? I'm out of options. 我没有选择。

PS: The actual scenario I'm dealing with requires saving huge amount of data. PS:我正在处理的实际场景需要节省大量数据。 Eg: 50000 parent records, and 250000 Child records. 例如:50000个父记录和250000个子记录。 That is why I don't want bi-directional mapping. 这就是为什么我不想要双向映射。 Because saving Child will do create a query with join table in the back-end. 因为保存Child会在后端创建一个带有连接表的查询。

I'm mostly interested in solution, wherein I don't have to fire query twice on Child table. 我最感兴趣的是解决方案,其中我不必在Child表上触发两次查询。 As that is happening in my current application, and that is hampering the performance. 正如我当前的应用程序中发生的那样,这妨碍了性能。

When you remove cascading the parent does not persist the referenced child elements and at 当您删除级联时,父级不会保留引用的子元素和

parent = parentDomainService.save(parent);

the parent references the "unsaved transient" child instances and therefore throws the exception. 父引用“未保存的瞬态”子实例,因此抛出异常。 If you first save the parent and then add the children: 如果您先保存父项,然后添加子项:

Parent parent = new Parent();
parent = parentDomainService.save(parent);
parent.setChildren(Lists.newArrayList(new Child(), new Child()));

for (Child child: parent.getChildren()) {
    child.setParentId(parent.getId());
} 

childDomainService.save(parent.getChildren());

then the exception will not be thrown. 然后不会抛出异常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM