使用变形金刚

时间:2017-09-26 05:22:58

标签: java sql hibernate dto

我有一个名为Student

的实体
@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());
        }
    }

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

当查询中包含注释时,这是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生成的,而不是我控制的东西。我需要在queryString中更改某些内容以实现我需要的结果。

我不想手动将结果映射到我的DTO,有没有办法可以直接将Student.java中的studentNotes映射到StudentDTO.java中的注释

2 个答案:

答案 0 :(得分:0)

看起来这个查询是错误的。更好的方法是获得学生。你总是可以从学生那里收集笔记。

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
在您的查询中

?不确定我的回答是否有帮助。

答案 1 :(得分:0)

您的查询是错误的,因为您需要两个联接才能选择音符计数,但这甚至没有必要,因为您可以仅通过使用音符集合的大小来确定音符计数。

我正是为此用例创建了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);