Hibernate 中的 OneToMany 单向映射。引用实体中的问题设置外键
OneToMany unidirectional mapping in Hibernate. Issue setting foreign key in referenced entity
假设有两个实体:Parent 和 Child,具有 @OneToMany
映射从 Parent 到 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;
}
如您所见,在我的例子中,Child table 将外键存储到 Parent的主键。但我不希望它作为我的 Child 实体中的 bi-directional 映射。
现在出现的问题是,我无法在 Child
个实例中设置 parent_id
。
我创建了这样的实例:
Parent parent = new Parent();
parent.setChildren(Lists.newArrayList(new Child(), new Child()));
parentDomainService.save(parent);
假设Parent端有级联。这种方法首先保存 Parent,然后保存 Child 实例。然后它在 child 实例上运行更新查询以更新 parent_id
,正如我从 Hibernate show_sql 日志中看到的那样。但令人惊讶的是,更新查询后,我看到一些 child
, parent_id
是 null
。这让我很惊讶。
所以,我去手动处理那个东西,并删除了级联。然后我这样保存实体:
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());
这个问题在我身上反弹,但有以下例外:
org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.somepkg.Child
我已经看到很多关于 SO 的问题,但我知道那里有很多问题,但几乎所有问题都在处理 bi-directional 映射,或 uni-directional 与 JoinTable 的映射.两者都不适合我的情况。
这里有灯吗?我别无选择。
P.S.: 我正在处理的实际场景需要保存大量数据。例如:50000 parent 条记录和 250000 Child 条记录。这就是为什么我不想要 bi-directional 映射。因为保存 Child 确实会在 back-end.
中创建一个带有连接 table 的查询
我最感兴趣的是解决方案,其中我不必在 Child
table 上触发两次查询。正如我当前的应用程序中发生的那样,这会影响性能。
当您移除级联时,父元素不会保留引用的子元素并且在
parent = parentDomainService.save(parent);
父引用 "unsaved transient" 子实例,因此抛出异常。如果先保存父项然后添加子项:
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());
则不会抛出异常
假设有两个实体:Parent 和 Child,具有 @OneToMany
映射从 Parent 到 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;
}
如您所见,在我的例子中,Child table 将外键存储到 Parent的主键。但我不希望它作为我的 Child 实体中的 bi-directional 映射。
现在出现的问题是,我无法在 Child
个实例中设置 parent_id
。
我创建了这样的实例:
Parent parent = new Parent();
parent.setChildren(Lists.newArrayList(new Child(), new Child()));
parentDomainService.save(parent);
假设Parent端有级联。这种方法首先保存 Parent,然后保存 Child 实例。然后它在 child 实例上运行更新查询以更新 parent_id
,正如我从 Hibernate show_sql 日志中看到的那样。但令人惊讶的是,更新查询后,我看到一些 child
, parent_id
是 null
。这让我很惊讶。
所以,我去手动处理那个东西,并删除了级联。然后我这样保存实体:
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());
这个问题在我身上反弹,但有以下例外:
org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.somepkg.Child
我已经看到很多关于 SO 的问题,但我知道那里有很多问题,但几乎所有问题都在处理 bi-directional 映射,或 uni-directional 与 JoinTable 的映射.两者都不适合我的情况。
这里有灯吗?我别无选择。
P.S.: 我正在处理的实际场景需要保存大量数据。例如:50000 parent 条记录和 250000 Child 条记录。这就是为什么我不想要 bi-directional 映射。因为保存 Child 确实会在 back-end.
中创建一个带有连接 table 的查询我最感兴趣的是解决方案,其中我不必在 Child
table 上触发两次查询。正如我当前的应用程序中发生的那样,这会影响性能。
当您移除级联时,父元素不会保留引用的子元素并且在
parent = parentDomainService.save(parent);
父引用 "unsaved transient" 子实例,因此抛出异常。如果先保存父项然后添加子项:
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());
则不会抛出异常