一对一关联+可选字段DTO投影(内连接):如何返回全部鸟类数据?
解决方案
首先修正你DTO构造函数的错误:当前BirdSummaryDTO的构造函数参数是Integer id和Transmitter,但JPQL查询传递的是name、sex、currentTransmitter,参数数量、类型完全不匹配,会导致运行时异常,先把构造函数改成对应类型和参数:
public class BirdSummaryDTO { final String name; final String sex; final Transmitter currentTransmitter; // 修正后的构造函数,匹配查询传递的参数 public BirdSummaryDTO(String name, String sex, Transmitter currentTransmitter) { this.name = name; this.sex = sex; this.currentTransmitter = currentTransmitter; } }
然后解决只返回关联发射器鸟类的问题,有两种可靠方式:
方式一:JPQL显式使用LEFT JOIN
在查询语句中显式指定LEFT JOIN关联currentTransmitter,强制使用左连接返回所有Bird,即使没有关联发射器:
@Query("SELECT NEW com.contoso.view.BirdSummaryDTO(b.name, b.sex, ct) FROM Bird b LEFT JOIN b.currentTransmitter ct") List<BirdSummaryDTO> listBirdDTO();
方式二:调整实体关联的Fetch策略(可选)
虽然你在实体中设置了@OneToOne(optional = true),理论上默认应该是左连接,但@Fetch(FetchMode.JOIN)可能在某些场景下影响关联查询的连接类型。如果不想修改JPQL,可以尝试将FetchMode改为SELECT(延迟加载模式),或者通过FetchProfile按需控制加载策略:
@OneToOne(optional = true) @Fetch(FetchMode.SELECT) @JoinColumn(name = "current_transmitter_id", nullable = true) // 可选:通过FetchProfile在需要时启用JOIN加载 @FetchProfile(name = "bird-with-transmitter", fetchOverrides = { @FetchProfile.FetchOverride(entity = Bird.class, association = "currentTransmitter", mode = FetchMode.JOIN) }) private Transmitter currentTransmitter;
不过更推荐第一种方式,直接在JPQL中显式指定LEFT JOIN,逻辑清晰且不受实体注解的潜在影响。
内容的提问来源于stack exchange,提问作者Al Grant
相关产品推荐
相关产品推荐

