没有对相关实体的额外查询

no extra query for related entity

我有这个实体:

@Entity
public class PlantArea {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_plantarea")
    @SequenceGenerator(name = "seq_plantarea", allocationSize = 1)
    @Column(nullable = false, updatable = false)
    private Long id;
    private String code;
    private String name;
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name="plantid", nullable = false)
    private Plant plant;
}

在 repo 中,我得到的所有植物区域都是这样的:

@Override
    public List<PlantArea> getPlantAreas() {
        return plantAreaRepository.findAll();
    }

所以,没什么特别的。

我有两个问题:

  1. Hibernate 触发两个查询:一个用于 selecting plantareas,一个用于 selecting 相关植物。如何避免这种情况以及如何强制休眠只执行一个查询?就像在 sql(伪)中一样:select 所有植物区域都在内部加入植物。我想我必须写一些 jpql/hql,无论查询是什么?

  2. 用简单的 findAll() 查询植物区得到这个 json 结果:

    [ { “编号”:1, “代码”:“122”, “名称”:“汽车”, “植物”: { “编号”:1, “代码”:“130”, “位置”:“某个城市”, “公司”: { “编号”:1, "name": "测试公司长名", "shortName": "测试公司" } } } ]

如你所见,每个工厂也都有一个公司。所以,我得到了相关对象的完整链:plantaraea -> plant -> company。问题是,如何抑制 company 对象?基本上我需要这样的查询(伪sql):

select plantarea.*, plant.*, company.* from plantarea 
inner join plant on plantarea.plant_id=plant.id
inner join company on plant.company_id=company.id

(1) 那些对 select Plant 的额外查询是因为您在 PlantArea.plant 中配置了 FetchType.EAGER 这是一种代码味道(参考 this for details). To solve it , you can use 'fetch join'获取 PlantArea 及其 Plant 的列表。类似于:

public interface PlantAreaRepository extends JpaRepository<PlantArea, Long> {
    
    @Query("select p from PlantArea p left join fetch p.plant")
    List<PlantArea> findAllWithPlant(); 

}

(2) 我觉得又是一种代码味道。对于一个非常重要的应用程序,我宁愿为 API JSON 响应创建另一个 DTO,而不是直接将实体暴露给外界。它只会让您难以改进您的应用程序,因为每当您更改实体时,您都必须担心它可能会影响现有的 API 客户端。因此,只需创建一个单独的 DTO,其结构与您的 API 响应完全相同。然后将 PlantArea 映射到这些 DTO,并将 return 映射回客户端。

@Data
public class PlantAreaDto {
    private Long id;
    private String code;
    private String name;
    private PlantDto plant;
}

@Data
public class PlantDto {
    private Long id;
    private String location;
}