简体   繁体   English

从Spring Data Jpa查询返回自定义对象

[英]Return custom object from Spring Data Jpa query

I've a custom query inside a jpa repository class: 我在jpa存储库类中有一个自定义查询:

package it.univaq.we.internshipTutor.repository;
import ...

public interface ProfessorRepository extends JpaRepository<Professor, Long> {

    List<Professor> findAll();

    ...

    @Query(value =  "SELECT professor.id, professor.department_id, " +
                    "professor.first_name, professor.last_name, " +
                    "professor.email, COUNT(professor_id) as count " +
                    "FROM professor LEFT JOIN student_internship ON professor.id = professor_id " +
                    "GROUP BY professor_id ORDER BY count DESC LIMIT ?1", nativeQuery = true)
    List<ProfessorInternshipCount> mostRequestedProfessors(int limit);
}

The query returns the 10 most requested internship tutors/professors; 该查询返回10个最需要的实习辅导员/教授; the result is composed by the information of the Professor and an integer value (the count). 结果由教授的信息和整数值(计数)组成。

Professor model class: 教授模特课:

package it.univaq.we.internshipTutor.model;

import ...

@Entity
@Table(name = "professor")
public class Professor {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", nullable = false)
    private Long id;

    @Transient
    private UUID uuid;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "department_id", nullable = false)
    @NotNull(message = "this field is mandatory")
    private Department department;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "professor")
    private List<StudentInternship> studentInternships;

    @Column(name = "first_name", nullable = false, length = 255)
    @NotEmpty
    private String firstName;

    @Column(name = "last_name", nullable = false, length = 255)
    @NotEmpty
    private String lastName;

    @Column(name = "email", nullable = false, length = 255)
    @Email
    @NotEmpty
    private String email;

    ...getters and setters...
}

ProfessorInternshipCount model (created to incapsulate the result of the query): ProfessorInternshipCount模型(创建以封装查询结果):

package it.univaq.we.internshipTutor.model;

public class ProfessorInternshipCount {
    private Professor professor;
    private Integer count;

    public ProfessorInternshipCount(Professor professor, int count) {
        this.professor = professor;
        this.count = count;
    }

    ...getters and setters...
}

Now, I've difficulties in binding what the query returns with the model I've created. 现在,我很难将查询返回的内容与我创建的模型绑定。 More precisely I get the following exception: 更准确地说,我得到以下例外:

org.springframework.core.convert.ConverterNotFoundException: 
    No converter found capable of converting from type 
    [org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap] 
    to type 
    [it.univaq.we.internshipTutor.model.ProfessorInternshipCount]
...

Am I doing something wrong? 难道我做错了什么? Is there a better way of doing what I'am trying to do? 有没有更好的方法来做我想做的事情?

You can easily achive this using projection. 您可以使用投影轻松实现此目的。 Here you have the bellow columns : 在这里你有以下列:

private String firstName;
private String lastName;
private Long id;

Create an Interface with getter from your query. 使用查询中的getter创建一个接口。 Your projection will like this: 您的预测将是这样的:

public interface ITestProjection {
    Long getId();
    Integer getCount();
    String getFirstName();
    String getLastName();
}

Your Query will like this : 您的查询将是这样的:

@Query(value = "SELECT professor.id, professor.department_id, " +
                    "professor.first_name, professor.last_name, " +
                    "professor.email, COUNT(professor_id) as count " +
                    "FROM professor LEFT JOIN student_internship ON professor.id = professor_id " +
                    "GROUP BY professor_id ORDER BY count DESC LIMIT =?1", nativeQuery = true)
    ArrayList<ITestProjection> findDataWithCount(Integer limit);

Hope this will solve your problem. 希望这能解决你的问题。

For more details visit this thread . 有关详细信息,请访问此主题

Thanks :) 谢谢 :)

You can do this by either following ways. 您可以通过以下方式执行此操作。

  1. Using ModelMapper to convert entity to target bean type 使用ModelMapper将实体转换为目标bean类型
  2. Use Spring Projection to make this happen 使用Spring Projection来实现这一目标

Go through the article to get more detail. 阅读文章以获取更多详细信息。

http://javasampleapproach.com/spring-framework/spring-data/query-alter-domain-model-spring-jpa-projection-springboot-mysql-database http://javasampleapproach.com/spring-framework/spring-data/query-alter-domain-model-spring-jpa-projection-springboot-mysql-database

For example, let's that we have: 例如,让我们拥有:

  • User - entity object with many fields. 用户 - 具有许多字段的实体对象。

  • UserBean - just object where our data will be converted. UserBean - 只是我们的数据将被转换的对象。

Bad practice: 不好的做法:

 @Repository
    public class ReportingRepository {

        @PersistenceContext
        private EntityManager em;

        public List<UserBean> findQuery() {
            Query query = em.createNativeQuery("select  ...  from Table  INNER JOIN ...");
            List<UserBean> items = (List<UserBean>) query.getResultList();
            return items;
        }

    }

but it will return values in arrays, so it will be more beautiful if we write the following code, that is better practice: 但它会返回数组中的所以如果我们编写以下代码会更漂亮,这是更好的做法:

query.unwrap(SQLQuery.class)
           .addScalar("instance name", StringType.INSTANCE)
           .addScalar("second instance name", IntegerType.INSTANCE)
           .setResultTransformer(Transformers.aliasToBean(UserBean.class));

   List<UserBean> items = query.getResultList();

So finally everything is converted to UserBean class. 所以最后一切都转换为UserBean类。 Note that in addScalar method you should pass instance variable name (in your question you have count variable ) 请注意 ,在addScalar方法中,您应该传递实例变量名称(在您的问题中,您有计数变量)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM