如何解决Spring JPA DTO 投影和处理带有空值的嵌套投影
@Query("select new com.core.data.category.CategoryDto(c.id,c.code,c.externalCode,c.SEOMeta,c.createdAt,c.updatedAt,c.parent.code) FROM Category c where c.code = :code")
CategoryDto findCategoryByCode(@Param("code") String code);
这就是我的 CategoryDto
的样子:
public class CategoryDto implements Serializable {
private Long id;
private String code;
private String externalCode;
private SEOMeta SEOMeta;
private CategoryDto parent;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
Map<String,LocCategoryDto> translation;
//constructor based on the requirement
}
这似乎工作正常,除了嵌套对象的属性为 null
的一种情况。在我的情况下,父属性可以是 null
,以防这是一个根类别,但似乎使用 c.parent.code
导致问题,并且整个对象即将出现 null
。有人可以帮我解决以下问题
- 有没有办法使用相同的构造函数表达式来处理这种情况?我试图查看文档,但没有找到详细信息。
- 我认为其他选项可能是使用 ResultTransformer(它将我的代码绑定到特定的 JPA),但我没有找到任何关于如何将它与 Spring JPA 一起使用的信息。
更新
我什至尝试了使用 CASE
选项的选项,但似乎这对我也不起作用,因为我仍然得到空实体(而数据在数据库中可用)。这是我尝试的更新代码
@Query(value = "select new com.core.data.category.CategoryDto(c.id," +
"CASE " +
"WHEN c.parent is NULL " +
"THEN NULL " +
"ELSE c.parent.code " +
"END ) " +
"FROM Category c where c.code = :code")
CategoryDto findCategoryByCode(@Param("code") String code);
编辑 2 我也尝试过加入,但这似乎也不起作用。
更新:我犯了一个愚蠢的错误。使用简单连接而不是左连接导致了这个问题。
解决方法
尝试使用左连接
SPLIT
,
我怀疑您的问题完全不同,因为使用左外连接可以解决您描述的问题。
将您的查询更改为:
select new com.core.data.category.CategoryDto(c.id,c.code,c.externalCode,c.seoMeta,c.createdAt,c.updatedAt,p.code)
FROM Category c
LEFT JOIN c.parent p
WHERE c.code = :code
我创建了一个 reproducer demonstrating that an outer join fixes the problem。
相关代码:
@Entity
class SomeEntity {
@Id
@GeneratedValue
Long id;
String name;
@ManyToOne
SomeEntity parent;
}
public class Dto {
final String name;
final String parentName;
public Dto(String name,String parentName) {
this.name = name;
this.parentName = parentName;
}
@Override
public String toString() {
return name + " - " + parentName;
}
}
public interface SomeEntityRepository extends JpaRepository<SomeEntity,Long> {
@Query("select new de.schauderhaft.de.constructorexpressionwithnestedreference.Dto(e.name,p.name) " +
"from SomeEntity e " +
"left join e.parent p")
List<Dto> findDto();
@Query("select new de.schauderhaft.de.constructorexpressionwithnestedreference.Dto(e.name,e.parent.name) " +
"from SomeEntity e")
List<Dto> findDtoInnerJoin();
@Query("select e from SomeEntity e")
List<SomeEntity> findEntities();
}
@SpringBootTest
class ConstructorExpressionWithNestedReferenceApplicationTests {
@Autowired
SomeEntityRepository ents;
@Test
@Transactional
void testDtos() {
createEnts();
assertThat(ents.findDto()).extracting(Dto::toString).containsExactlyInAnyOrder("ents name - parents name","parents name - null");
}
@Test
@Transactional
void testDtosInnerJoin() {
createEnts();
assertThat(ents.findDtoInnerJoin()).extracting(Dto::toString).containsExactly("ents name - parents name");
}
@Test
@Transactional
void testEntities() {
createEnts();
assertThat(ents.findEntities()).extracting(e -> e.name).containsExactlyInAnyOrder("ents name","parents name");
}
private void createEnts() {
SomeEntity ent = new SomeEntity();
ent.name = "ents name";
ent.parent = new SomeEntity();
ent.parent.name = "parents name";
ents.saveAll(asList(ent,ent.parent));
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。