【问题标题】:OneToMany relationsip of entity in persistence context is not updated持久性上下文中实体的 OneToMany 关系未更新
【发布时间】:2019-12-18 08:40:29
【问题描述】:

MxN 关系中有 3 个实体,B 为关联实体。我们在单个 TX 中创建它们,将它们全部持久化,并使用 OneToMany 关联获取实体。此关联在获取后未初始化。

来源:https://github.com/alfonz19/springboot222demo/commits/what

    @Transactional
    @Test
    void contextLoads() {
//      for(int i = 0; i < 3; i++) {
            UUID aId = UUID.randomUUID();
            AEntity aEntity = aRepository.save(new AEntity().setId(aId));
            UUID bId = UUID.randomUUID();
            CEntity cEntity = cRepository.save(new CEntity().setId(bId));
            em.flush();

            bRepository.save(new BEntity().setAEntity(aEntity).setCEntity(cEntity));
//      }

        em.flush();
//      em.clear();

        Iterable<CEntity> centities = cRepository.findAll();
        List<BEntity> bEntities =
                iterableToStream(centities).flatMap(e -> e.getBEntities().stream()).collect(Collectors.toList());

        Assert.assertThat(centities, Matchers.iterableWithSize(1));
        Assert.assertThat(bRepository.findAll(), Matchers.iterableWithSize(1));
        Assert.assertThat(bEntities.size(), CoreMatchers.is(1));
...
}

好的,我明白了,在创建 BEntity 时,我不会更新 AEntityCEntity 导致它们损坏。调用 cRepository.findAll() 然后确实调用 db 上的 select 以获取所有 C(即使没有任何 evict/flush/clear)但使 @OneToMany 未初始化。我不明白。我会理解,如果根本不调用 db,但如果我无论如何都获取 Cs 来刷新它,为什么不刷新关联表。这是为什么呢?

更令人惊讶的是aRepository.save(new AEntity().setId(aId)) 在执行 em.merge(实体已分配 id)时,即使 @OneToMany 是惰性的,休眠也会使用 2 个左外连接加载整个 MxN 结构。为什么会这样? 编辑:好的,这根本不奇怪,这就是级联合并的含义。完全没问题。

我对这种行为有点惊讶,因为在不应该出现的地方 (IIUC) 发出了选择,而在很容易出现的地方却没有。 p>

并将最好的保持到最后。稍作改动:取消注释 for 循环并清除,我得到了完全的非确定性行为。

来源:https://github.com/alfonz19/springboot222demo/tree/nondeterministic

测试要么工作,要么产生如下异常:

  • 数组越界
  • 拥有的实体实例不再引用具有 cascade="all-delete-orphan" 的集合:
  • java.lang.NullPointerException

但是如果我在bEntities 变量声明上放置断点,cEntities 总是会正确创建并测试然后通过。我不知道是什么原因造成的。

【问题讨论】:

    标签: jpa spring-data-jpa


    【解决方案1】:

    我对非确定性行为问题奖金问题有答案。

    列表中另一个随机生成的例外是org.springframework.orm.jpa.JpaSystemException: Found shared references to a collection,所有这些行为都会随着flatMap 的删除而消失。即替换:

    List<BEntity> bEntities =
                    StreamSupport.stream(centities.spliterator(), true).flatMap(e -> e.getBEntities().stream()).collect(Collectors.toList());
    

    List<BEntity> bEntities = new LinkedList<>();
            centities.forEach(e->bEntities.addAll(e.getBEntities()));
    

    并在(不再)“非确定性”分支中测试将通过 100%。不知道为什么,但是看起来,stream-api 对于休眠管理的集合并不那么安全。

    【讨论】:

      猜你喜欢
      • 2020-06-15
      • 1970-01-01
      • 1970-01-01
      • 2015-07-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多