持久性上下文中的实体的OneToMany关系未更新

时间:2019-12-18 08:40:29

标签: jpa spring-data-jpa

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(即使没有任何逐出/清除/清除),但@OneToMany尚未初始化。我不明白我会理解,如果根本就没有对db的调用,但是如果我还是要获取Cs来刷新它,为什么不还要刷新关联表。为什么那样?

更令人惊讶的是,aRepository.save(new AEntity().setId(aId))在执行em.merge(实体已分配ID)时,即使@OneToMany是惰性的,休眠也使用2个左外部联接来加载整个MxN结构。为什么那样?编辑:好的,这一点也不奇怪,这意味着级联合并。完全可以。

我对此行为感到有点惊讶,因为在不应该出现的位置(IIUC)发出了选择,而在容易出现的位置没有发出选择。

并保持最佳状态。进行很小的更改:无需评论循环和清除,我将获得完整的不确定性行为。

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

测试将起作用,或产生如下异常:

  • 数组超出范围
  • 拥有实体实例不再引用具有层叠=“ all-delete-orphan”的
  • 集合:
  • java.lang.NullPointerException

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

1 个答案:

答案 0 :(得分:0)

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

该列表的另一个随机生成的异常是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%。不知道为什么,但是似乎hibernate管理的集合中的stream-api不那么安全。