我目前正在构建一个JPQL自定义查询,至少乍一看应该很简单。
堆栈:Java 11,spring-boot 2.4.5,spring-boot starter数据jpa 2.4.8,hibernate内核5.4.16,Postgre数据库。
案例
我只需要我的JPQL查询在自定义DTO中检索3个字段,这些字段来自父实体及其子实体/嵌套实体(映射为一对一单向关系(,而不是域中的实体
域如下:
@Entity
@Table(name = "Item")
public class ItemEntity {
@Id
private Long id;
@NotNull
private String field1;
@ManyToOne
@JoinColumn(name = "nestedEntity_id", referencedColumnName = "id")
private NestedEntity nestedEntity;
//...
}
@Entity
@Table(name = "Nested")
public class NestedEntity {
@Id
private Long id;
@NotNull
private String field1;
@NotNull
private String field2;
//...
}
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class MyDTO {
@NotNull
private String myField;
private String concatedNestedFields;
private String otherNestedField;
//...
}
我觉得这很容易,于是做了这样的事情:
@Query("SELECT new my.package.MyDto(itemEntity.field1, CONCAT(itemEntity.nestedEntity.field1, ' ', itemEntity.nestedEntity.field2), itemEntity.nestedEntity.field3) FROM ItemEntity itemEntity WHERE itemEntity.country = :country")
MyDTO findByCountry(@Param("country") CountryEnum country);
特殊性
我不知道它是否相关,但嵌套的实体字段是@NotNull
注释的。
问题
当nestedEntity为null时会出现问题:尽管存在"parent"ItemEntity,但查询不返回任何内容。如果nestedEntity不为null,则查询有效。
我尝试了什么
我尝试使用COALESCE((函数,它在每个nestedEntity字段上返回我们给出的参数中的第一个非null值,如下所示:
@Query("SELECT new my.package.MyDto(itemEntity.field1, COALESCE(CONCAT(itemEntity.nestedEntity.field1, ' ', itemEntity.nestedEntity.field2),'-'), COALESCE(itemEntity.nestedEntity.field3), '-') FROM ItemEntity itemEntity WHERE itemEntity.country = :country")
MyDTO findByCountry(@Param("country") CountryEnum country);
但它也不起作用
更新我刚刚尝试了一些方法来消除一些根本原因。如果我运行springdata/JPA提供的JPA-Named查询,并返回实体而不是我的自定义DTO,即使嵌套实体为null,它也能工作。它确实检索了带有嵌套null实体的实体。查询如下:
ItemEntity findItemEntityByCountry(@Param("country") CountryEnum country);
我不知道该怎么总结,但它可能会帮助那些比我更了解JPA的人(这是很多人…XD(。
我没有找到任何关于这个案子的在线资源,我有点不知所措。
如果你们能帮我解决这个小问题,我将不胜感激
非常感谢你们抽出时间!希望这也能帮助其他人:(
尝试以下左加入
@Query("SELECT new my.package.MyDto(itemEntity.field1,
CONCAT(nestedEntity.field1, ' ', nestedEntity.field2),
nestedEntity.field3)
FROM ItemEntity itemEntity left join itemEntity.nestedEntity as nestedEntity
WHERE itemEntity.country = :country")
MyDTO findByCountry(@Param("country") CountryEnum country);
否则,不要使用concat,只需传递nestedEntity.field2并在java端进行连接