【问题标题】:Spring JPA DTO projection and handling the nested projection with null valuesSpring JPA DTO 投影和处理带有空值的嵌套投影
【发布时间】:2021-08-28 18:30:42
【问题描述】:

我正在使用基于类的投影和构造函数表达式。这是我工作的示例代码

@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,c.code,c.externalCode,c.seoMeta, c.createdAt, c.updatedAt, " +
            "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 我也尝试过加入,但这似乎也不起作用。

更新:我犯了一个愚蠢的错误。使用的是简单连接而不是左连接,导致了这个问题。

【问题讨论】:

  • Nitpick:使用 ResultTransformer 会将您绑定到 Hibernate。通过到处使用 JPA,您已经与 JPA 绑定了。

标签: hibernate jpa spring-data-jpa jpa-2.0 jpa-2.1


【解决方案1】:

尝试使用左连接

@Query("select new com.core.data.category.CategoryDto(c.id,c.code,c.externalCode,c.seoMeta, c.createdAt, c.updatedAt,parent.code) FROM Category c left join c.parent as parent where c.code = :code")
CategoryDto findCategoryByCode(@Param("code") String code); 

【讨论】:

  • 对不起..我忘了更新,我已经尝试过加入但似乎不适合我的情况。我也更新了我的帖子。
  • @UmeshAwasthi 您能否确认您尝试使用左连接而不是仅使用连接?可以分享一下加入试用的代码吗?
  • 你是对的..我试图在不使用 left 的情况下进行左连接,并且正在寻找其他问题:)
【解决方案2】:

我怀疑您的问题完全不同,因为使用左外连接可以解决您描述的问题。

将您的查询更改为:

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));
    }

}

【讨论】:

  • 我的问题是没有仔细查看我的查询。我没有使用左连接,而是简单连接:)
猜你喜欢
  • 2021-06-19
  • 1970-01-01
  • 2022-12-02
  • 1970-01-01
  • 2018-03-05
  • 1970-01-01
  • 2018-11-25
  • 2021-06-01
  • 2017-12-11
相关资源
最近更新 更多