微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Spring JPA DTO 投影和处理带有空值的嵌套投影

如何解决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。有人可以帮我解决以下问题

  1. 有没有办法使用相同的构造函数表达式来处理这种情况?我试图查看文档,但没有找到详细信息。
  2. 我认为其他选项可能是使用 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 举报,一经查实,本站将立刻删除。