简体   繁体   中英

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 .

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. But I don't want that as bi-directional mapping in my Child entity.

The issue arises now is, I'm unable to set the parent_id in Child instances.

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. And then it runs the update query on child instances to update the parent_id , as I see from the Hibernate show_sql logs. But surprisingly, after update query, I see for some of the child , the parent_id is null . 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. 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. Eg: 50000 parent records, and 250000 Child records. 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.

I'm mostly interested in solution, wherein I don't have to fire query twice on Child table. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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