为什么会忽略此FetchType.LAZY并在查询中提取所有实体?

时间:2019-10-17 17:52:00

标签: java spring hibernate spring-boot spring-data-jpa

我正在将Spring Boot 2与Hibernate一起使用,并且我有一个名为ItemCarga的实体:

@ManyToMany(cascade = { CascadeType.DETACH }, fetch = FetchType.LAZY)
@JoinTable(name = "rel_transp_carga", joinColumns = { @JoinColumn(name = "fk_item_carga") }, inverseJoinColumns = { @JoinColumn(name = "fk_transportadora") })
@LazyCollection(LazyCollectionOption.TRUE)
private Set<Transportadora> transportadoras = new HashSet<Transportadora>();

为什么使用我的存储库中的该实体进行查询,如下所示:

@Query("select e from ItemCarga e where e.cnpjCeramica = :cnpjCeramica and (e.dataInserido between :inicio and :fim) ")
List<ItemCarga> listarProdutosPorPeriodo(
        @Param("cnpjCeramica") String cnpjCeramica, 
        @Param("inicio") Date dataInicial, 
        @Param("fim") Date dataFinal, 
        Sort sort);

结果是一组ItemCarga实体,其属性transportadoras随其所有项目一起提取。

它不应该为null还是为空?

因为我没有在选择中提及该属性,所以不应该忽略它吗?

1 个答案:

答案 0 :(得分:1)

您确实在查询中提到了该属性:select e from ItemCarga e。这意味着您正在获取整个ItemCarga实体。由于您将transportadoras定义为fetch = FetchType.LAZY,因此将创建一个代理(不从数据库中获取数据)。

如果使用事务调用查询,则可以遍历集合,然后休眠将获取子实体(这通常会导致n + 1选择问题)。如果您尝试在事务之外访问它,则会抛出LazyInitializationException

由于这只是休眠的提示,因此可以确保不会以几种方式获取Set

  1. 通过不查询它,例如:

    @Query("select e.field1, e.field2 from ItemCarga e ...")
    List<Object[]> listarProdutosPorPeriodo...
    

    缺点是您必须转换结果

  2. 通过使用dto和查询映射。我不会详细描述它,更多信息请参见here

  3. 通过使用投影-与要获取的字段的getter和setter接口。更多详细信息,here