JPA:与惰性初始化集合合并的行为是什么?

时间:2011-03-09 10:13:17

标签: jpa jpa-2.0

以下是导致问题的序列:

  1. 我有一个团队记录,数据库中有3个玩家记录。 Team实体有一个使用FetchType.LAZY,CascadeType.ALL
  2. 的List
  3. 点击网页上的搜索按钮
  4. 调用服务器端使用JPA查询的查询,查找所有Team记录,在这种情况下,只查询从查询​​返回的团队实体的1条记录(其中包含播放器实体列表的代理)
  5. 将此teamEntity映射到DTO,并将此DTO返回给webui,跳过播放器实体列表的映射
  6. Webui以html格式呈现DTO,准备接收用户的修改
  7. 用户修改了团队的属性,例如其成立时间
  8. 点击网页上的保存按钮
  9. 将DTO转换为团队实体,用于更新现有的团队记录
  10. 但是在这种情况下,如果我要使用em.merge(teamEntity),团队记录将会更新,但是玩家列表会发生什么?因为从DTO转换到团队实体时,teamEntity有一个空的玩家实体列表。合并后,我注意到teamEntity的大小为0。但在刷新该实体em.refresh(teamEntity)之后,它将返回3个细节大小。
  11. 我很困惑:

    1. 合并后为什么大小为0?它不再代表记录了
    2. 在进行测试之前,我认为细节将被移除,因为我将teamEntity与空细节合并。
    3. 请赐教:)

      谢谢!

1 个答案:

答案 0 :(得分:10)

JPA规范说:

  

合并操作的语义   应用于实体X如下:

     
      
  • 如果X是分离的实体,则为状态   将X复制到预先存在的   管理实体实例X'相同   X的身份或新的托管副本X'   已创建。

  •   
  • 如果X是新实体   例如,一个新的管理实体   实例X'创建和状态   将X复制到新的托管中   实体实例X'。

  •   
  • 如果X是a   删除实体实例,   IllegalArgumentException将是。{   由合并操作抛出(或者   事务提交将失败)。

  •   
  • 如果是X.   是一个托管实体,它被忽略   然而,合并操作   合并操作级联到   关系引用的实体   来自X,如果这些关系有   已经注册了级联   元素值cascade=MERGE或   cascade=ALL注释。

  •   
  • 对所有人来说   关系引用的实体Y.   来自X的具有级联元素   值cascade=MERGEcascade=ALL,Y   以Y'递归合并。对全部   这样的Y由X引用,X'设置为   参考Y'。 (注意,如果X是   管理然后X是与之相同的对象   X”)

  •   
  • 如果X是合并到X'的实体,   引用另一个实体Y,   cascade=MERGEcascade=ALL的位置   未指定,然后导航   来自X'的相同关联产生a   引用托管对象Y'   与Y相同的持久性身份。

  •   

正如你所看到的,这里没有魔力。已分离实例的状态将复制到新创建的托管实例中。由于您的分离实例有一个空列表,托管实例也会有它。

进一步的行为取决于关系的所有权,因为数据库中的表示反映了关系的拥有方:

  • 如果Team是拥有方,则TeamPlayer之间的关系将在刷新期间被销毁(但Player本身将存在,除非您拥有orphanRemoval = true关于你的关系)。
  • 否则在Team中使用空列表不会影响数据库。

如果在刷新上下文之前刷新Team,则Team的所有属性都会被数据库中的值重写,因此Player的列表将被恢复(因为空列表中的flush()球员还没有脸红。)

如果在调用refresh()之前致电Team,而flush()是拥有方,则列表将为空,因为在{{1}}期间,关系的破坏会传播到数据库