spring data jpa - 带有自定义查询的基于类的投影

Bor*_*ris 6 java spring jpa spring-data-jpa

我需要一个用于自定义查询的 spring 数据存储库方法,并希望使用基于类的投影。

看着这个 https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections

@Entity
public class Person {
  @Id
  private Long id;
  private String firstName;
  private String lastName;
  private int age;
}

@Value // lombok annotation to create constructor, equals and hash-code
public class PersonDTO {
  private String firstName;
  private String lastName;
}

public interface PersonRepository extends Repository<Person, Long> {

List<PersonProjection> findDistinct();

@Query("select distinct firstName, lastName from Person")
List<PersonProjection> findDistinctQuery();

@Query(value = "select distinct first_name, last_name from person", nativeQuery = true)
List<PersonProjection> findDistinctNativeQuery();

}
Run Code Online (Sandbox Code Playgroud)
  • findDistinct 效果很好
  • findDistinctQuery 和 findDistinctNativeQuery 抛出

没有找到能够从类型 [org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap] 转换为类型 [com.x.PersonDTO] 的转换器

是否有任何选项可以使其与类(而不是接口)一起使用?

swy*_*rik 6

请亲自编写您的方法,如下所示

@Query(value = "select distinct new xxx.xxx.dto.PersonDTO(p.first_name, p.last_name) from person p")
List<PersonProjection> findDistinctNativeQuery();
Run Code Online (Sandbox Code Playgroud)

“xxx.xxx.dto.PersonDTO”这应该指向您的完全限定类名。

供您参考,请查看此 https://www.bytestree.com/spring/spring-data-jpa-projections-5-ways-return-custom-object/


ili*_*hma 5

我不确定是否有适用于本机查询的 Spring Data 解决方案,但您可以使用 JPA ConstructorResult

@Entity
@NamedNativeQuery(
        name="Person.findDistinctNativeQuery",
        query="select distinct first_name as firstName, last_name as lastName from person",
        resultSetMapping="PersonMapping"
)
@SqlResultSetMapping(name="PersonMapping",
        classes={
                @ConstructorResult(targetClass=PersonDTO.class, columns={
                        @ColumnResult(name="firstName", type=String.class),
                        @ColumnResult(name="lastName", type=String.class)
                })
        })
public class Person {
    @Id
    private Long id;
    private String firstName;
    private String lastName;
    private int age;
}

@Value // lombok annotation to create constructor, equals and hash-code
public class PersonDTO {
    private String firstName;
    private String lastName;
}

public interface PersonRepository extends Repository<Person, Long> {

    List<PersonProjection> findDistinct();

    @Query("select distinct firstName, lastName from Person")
    List<PersonProjection> findDistinctQuery();

    @Query(name = "Person.findDistinctNativeQuery", nativeQuery = true)
    List<PersonDTO> findDistinctNativeQuery();

}
Run Code Online (Sandbox Code Playgroud)

或者您可以从 findDistinctNativeQuery() 返回 Object[],然后手动创建 PersonDTO。

使用 HQL,您也可以使用基于类的投影,唯一的条件 PersonDTO 必须具有所有参数构造函数,其参数名称必须与根实体类的属性匹配:

public interface PersonRepository extends Repository<Person, Long> {

    ...

    List<PersonDTO> findDistinct();

}
Run Code Online (Sandbox Code Playgroud)

如果 PersonDTO 属性与基本实体属性不匹配,则可以使用HQL 动态实例化。同样,这不适用于本机查询:

public interface PersonRepository extends Repository<Person, Long> {

    ...

    @Query("select new com.x.PersonDTO(firstName, lastName) from Person")
    List<PersonDTO> findDistinct();

}
Run Code Online (Sandbox Code Playgroud)


Jay*_*Jay 5

这也有效:

public interface PersonRepository extends CrudRepository<Person, Long> {

    @Query(nativeQuery = true,
        value = "SELECT DISTINCT fist_name AS firstName, last_name AS lastName FROM person ")
    List<PersonNameOnly> findDistinctNames();

    interface PersonNameOnly {
        String getFirstName;
        String getLastName;
    }
}
Run Code Online (Sandbox Code Playgroud)