我有四个描述数据库的表:
讲师
@Entity
@Table(name = "LECTURER")
public class Lecturer
{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name = "NAME")
private String name;
@Column(name = "NOBEL_PRICE_YEAR")
private int nobel_price_year;
}```
注册(使用讲座和学生)
@Entity
@IdClass(EnrollmentId.class)
@Data
public class Enrollment
{
@Id
@JoinColumn(name = "lecture_id", referencedColumnName = "id")
@ManyToOne
private Lecture lecture;
@Id
@JoinColumn(name = "student_id", referencedColumnName = "id")
@ManyToOne
private Student student;
@Id
private int year;
@Column(nullable = false, columnDefinition = "TINYINT(1)")
private boolean exam_taken;
@Column(nullable = false, columnDefinition = "TINYINT(1)")
private boolean exam_passed;
}
自复合主键以来具有 ID 类
public class EnrollmentId implements Serializable
{
@Id
@JoinColumn(name = "lecture_id", referencedColumnName = "id")
@ManyToOne
private int lecture;
@Id
@JoinColumn(name = "student_id", referencedColumnName = "id")
@OneToOne
private int student;
private int year;
}
学生
@Entity
@Table(name="STUDENT")
@Data
@NamedQuery(name = "Student.findAll", query = "SELECT s FROM Student s")
public class Student
{
private static final long serialVersionUID = 1L;
@Id
@Column(name="ID", nullable=false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name="FIRSTNAME", nullable=false)
private String firstname;
@Column(name="LASTNAME", nullable=false)
private String lastname;
@Column(name="YEAR_OF_BIRTH")
private int yearOfBirth;
@Column(name="GENDER")
@Enumerated(EnumType.STRING)
private Gender gender;
}
讲座(使用讲师)
@Entity
@Table(name="LECTURE")
public class Lecture
{
private static final long serialVersionUID = 1L;
@Id
@Column(name = "ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name="TITLE")
private String title;
@JoinColumn(name="LECTURER_ID", referencedColumnName = "id")
@ManyToOne
private Lecturer lecturer;
@Column(name = "ROOM")
@Enumerated(EnumType.STRING)
private Room room;
@Column(name = "DAY_OF_WEEK")
private DayOfWeek dow;
@JoinColumn(name = "PREREQUISITE_ID", referencedColumnName = "id")
@ManyToOne
private Lecture prerequisite;
}
当我尝试构建查询时,我得到了很多结果。 (SQL Server 在同一查询上打印 129,JPA 90k+)
查询:
Query q = em.createQuery("SELECT"
+ " l.title, l.dow, l.room "
+ ", t.name, CASE WHEN (t.nobel_price_year != NULL) THEN 'YES' ELSE 'No' END"
+ ", e.year, e.exam_taken, e.exam_passed "
+ ", CONCAT(s.lastname,', ', s.firstname) AS student "
+ "FROM Lecture l "
+ "JOIN Lecturer t "
+ "JOIN Enrollment e "
+ "JOIN Student s "
+ "ORDER BY l.id", EmpireDBExample.class);
代码是手动生成的,因为 SQL Server 连接不适用于 Eclipse(据我所知/发现)。
映射中是否有错误?
我需要添加加入条件吗?如果是这样,我怎样才能实现这一目标? “ON a.id = b.id”不起作用。
最佳答案
好吧,由于 ON ...
不起作用(Hibernate 5 将支持它),您需要沿着路径加入或使用 where 条件来过滤不适合的行。目前,您正在交叉加入所有讲座、讲师、注册学生和学生,即使它们不相关。
另一个问题是,没有从 Lecture
到 Enrollment
的代码路径,因此您可能需要从 Enrollment
开始。因此,查询可能如下所示(我将跳过公共(public)部分):
... FROM Enrollment e
JOIN e.lecture l //join the lecture for the enrollment
JOIN l.lecturer t //join the lecturer for the lecture
JOIN e.student s //join the enrolled student
最后的建议:“我有四个描述数据库的表” - 在这里改变你的想法。您有四个实体描述您的模型,并且它们映射到数据库(不过映射可能会改变)。因此,在处理 JPA 查询时,您需要考虑实体而不是表,例如因为没有从 Lecture
到 Enrollment
的路径,并且除非您的 JPA 提供程序支持通用 ON
,否则您需要找到一个入口点和一条通往所有内容的路径。想要加入(例如,有一条从 Enrollment
到 Lecture
的路径,因此您可以从 Enrollment
开始)。
关于java - JPA Join 打印多个结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58518711/