有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java在使用转换器将实体映射到DTO时获取实体内的集合

我有一个实体叫做学生

@Entity
@Table(name = "students")
public class Student implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "STUDENT_ID")
    private Integer studentId;

    @Column(name = "STUDENT_NAME", nullable = false, length = 100)
    private String studentName;

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "student", cascade = CascadeType.ALL)
    private List<Note> studentNotes;

    // Some other instance variables that are not relevant to this question

    /* Getters and Setters */

}

还有一个叫做Note的实体

@Entity
@Table(name = "notes")
public class Note implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "NOTE_ID")
    private Integer noteId;

    @Column(name = "NOTE_CONTENT")
    private String noteText;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "STUDENT_ID")
    private Student student;

    /* Getters and Setters */

}

正如你所见,这种关系决定了一个学生可以有多张笔记

为了在特定页面上显示有关该学生的一些信息,我只需要studentName、笔记计数和所有笔记。 我为此创建了一个StudentDTO,它看起来像这样:

public class StudentDTO {

    private Long count;
    private String name;
    private List<Note> notes;

    /* Getters and setters */

}

我使用以下代码将从DB返回的Student和Notes映射到StudentDTO

private static void testDTO() {
        Session session = getSessionFactory().openSession();
        String queryString = "SELECT count(n) as count, s.studentName as name, s.studentNotes as notes " +
                "from Student s join s.studentNotes n where s.id = 3";
        Query query = session.createQuery(queryString);

        List<StudentDTO> list = query.setResultTransformer(Transformers.aliasToBean(StudentDTO.class)).list();
        for (StudentDTO u : list) {
            System.out.println(u.getName());
            System.out.println(u.getCount());
            System.out.println(u.getNotes().size());
        }
    }

当在查询中获取注释时,上面的代码会失败,但是如果我删除注释并只获取名称和计数,它就可以正常工作

当查询中包含notes时,这是Hibernate触发的错误:

select
            count(studentnot2_.NOTE_ID) as col_0_0_,
            . as col_3_0_,
            studentnot3_.NOTE_ID as NOTE_ID1_2_,
            studentnot3_.NOTE_CONTENT as NOTE_CON2_2_,
            studentnot3_.STUDENT_ID as STUDENT_3_2_ 
        from
            students studentx0_ 
        inner join
            notes studentnot2_ 
                on studentx0_.STUDENT_ID=studentnot2_.STUDENT_ID 
        inner join
            notes studentnot3_ 
                on studentx0_.STUDENT_ID=studentnot3_.STUDENT_ID 
        where
            studentx0_.STUDENT_ID=3;

这是我得到的错误信息:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'as col_3_0_, studentnot3_.NOTE_ID as NOTE_ID1_2_, studentnot3_.NOTE_CONTENT as N' at line 1

现在我可以看到查询哪里出错了,但它是由Hibernate生成的,而不是我可以控制的。在我的查询字符串中是否有我需要更改的内容,以获得我需要的结果

我不想手动将结果映射到我的DTO,是否有一种方法可以直接将我的studentNotes映射到Student中。java到StudentDTO中的notes。爪哇


共 (2) 个答案

  1. # 1 楼答案

    您的查询是错误的,因为还需要两个联接来选择notes的计数,但这甚至不是必需的,因为您可以通过使用notes集合的大小来确定计数

    我为这个用例创建了Blaze-Persistence Entity Views。实际上,您将JPA实体的DTO定义为接口,并将其应用于查询。它支持映射嵌套的DTO、集合等,基本上是您所期望的一切,而且最重要的是,它将提高您的查询性能,因为它将生成只获取DTO实际需要的数据的查询

    示例中的实体视图可能如下所示

    @EntityView(Student.class)
    interface StudentDTO {
      @Mapping("studentName")
      String getName();
      @Mapping("studentNotes")
      List<NoteDTO> getNotes();
      default int getCount() { return getNotes().size(); }
    }
    
    @EntityView(Note.class)
    interface NoteDTO {
      // attributes of Note that you need
      @IdMapping Integer getId();
      String getNoteText();
    }
    

    查询可能是这样的

    StudentDTO student = entityViewManager.find(entityManager, StudentDTO.class, studentId);
    
  2. # 2 楼答案

    看起来这个查询是错误的。更好的方法是只找学生。你总能从学生那里得到一系列笔记

    Session session = getSessionFactory().openSession();
    String queryString = from Student s where s.studentId = 3;
    Query query = session.createQuery(queryString);
    Student student = query.getSingleResult();
    sysout(student.getNotes().size())
    

    而且,我从未在SELECT子句中以这种方式检索集合;所以,不确定,但你真的需要吗

    join s.studentNotes
    

    在你的询问中?我不确定我的回答是否有用