以下是导致问题的序列:
- 我的数据库中有一条球队记录和 3 名球员记录。团队实体有一个使用 FetchType.LAZY、CascadeType.ALL 的列表
- 点击了 WebUI 上的搜索按钮
- 调用服务器端使用 JPA 查询的查询,查找所有团队记录,在本例中,仅查询返回团队实体的 1 条记录(具有玩家实体列表的代理)
- 将此 teamEntity 映射到 DTO,并将此 DTO 返回到 WebUI,跳过玩家实体列表的映射
- Webui 以 html 形式呈现 DTO,准备接收用户的修改
- 用户修改团队的属性,例如团队的成立日期
- 单击 WebUI 上的“保存”按钮
- 将 DTO 转换为团队实体,用于更新现有团队记录
- 但是在这种情况下,如果我使用 em.merge(teamEntity),球队记录将被更新,但是球员列表会发生什么?因为当从 DTO 转换为团队实体时,团队实体有一个空的玩家实体列表。合并后,我注意到 teamEntity 的详细信息大小为 0。但刷新该实体 em.refresh(teamEntity) 后,它将返回详细大小的 3。
我很困惑:
- 为什么合并后大小为0?就像不再代表记录一样
- 在进行测试之前,我认为细节将被删除,因为我将 teamEntity 与空细节合并。
请赐教:)
谢谢!
最佳答案
JPA 规范说:
The semantics of the merge operation applied to an entity X are as follows:
If X is a detached entity, the state of X is copied onto a pre-existing managed entity instance X' of the same identity or a new managed copy X' of X is created.
If X is a new entity instance, a new managed entity instance X' is created and the state of X is copied into the new managed entity instance X'.
If X is a removed entity instance, an
IllegalArgumentException
will be thrown by the merge operation (or the transaction commit will fail).If X is a managed entity, it is ignored by the merge operation, however, the merge operation is cascaded to entities referenced by relationships from X if these relationships have been annotated with the cascade element value
cascade=MERGE
orcascade=ALL
annotation.For all entities Y referenced by relationships from X having the cascade element value
cascade=MERGE
orcascade=ALL
, Y is merged recursively as Y'. For all such Y referenced by X, X' is set to reference Y'. (Note that if X is managed then X is the same object as X'.)If X is an entity merged to X', with a reference to another entity Y, where
cascade=MERGE
orcascade=ALL
is not specified, then navigation of the same association from X' yields a reference to a managed object Y' with the same persistent identity as Y.
如您所见,这里没有魔法。分离实例的状态被复制到新创建的托管实例中。由于您的分离实例有一个空列表,托管实例也会有它。
进一步的行为取决于关系的所有权,因为数据库中的表示反射(reflect)了关系的拥有方:
- 如果
Team
是拥有方,Team
和Player
之间的关系将在刷新期间被破坏(但是Player
code> 本身将继续存在,除非您的关系中有orphanRemoval = true
)。 - 否则,
Team
中的空列表不会影响数据库。
如果在刷新上下文之前刷新Team
,Team
的所有属性都会被数据库中的值重写,因此Player
列表s 已恢复(因为空玩家列表尚未刷新)。
如果在调用 refresh()
之前调用 flush()
,并且 Team
是拥有方,则列表将为空,因为销毁关系在 flush()
期间传播到数据库。
关于JPA : What is the behaviour of merge with lazy initialized collection?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5244238/