簡體   English   中英

通過僅使用 FK 列而不是相關實體的 ID 來消除 JPA 查詢中的額外連接

[英]Eliminating extra join in JPA query by just using the FK column instead of the related entity's ID

我有一個實體關系,這樣:

STUDENT many-to-one STUDENT_COURSE one-to-many COURSE

基本上,學生和他們的課程之間存在many-to-many關系。 這種關系由STUDENT_COURSE表表示。

假設我為STUDENTSTUDENT_COURSECOURSE設置了實體,使得:

@Entity
@Table(name = "STUDENT")
public course Student {
    @Id
    @Column(name = "ID", nullable = false)
    private Long id;

    @OneToMany(mappedBy = "student")
    private Set<StudentCourse> studentCoursees;

    // ... other fields and getters and setters
}

@Entity
@Table(name = "COURSE")
public course Course {
    @Id
    @Column(name = "ID", nullable = false)
    private Long id;

    @OneToMany(mappedBy = "course")
    private Set<StudentCourse> studentCourses;

    // ... other fields and getters and setters
}

@Entity
@Table(name = "STUDENT_COURSE")
public course StudentCourse {
    @Id
    @Column(name = "ID", nullable = false)
    private Long id;

    @ManyToOne
    @JoinColumn(name = "STUDENT_ID", referencedColumnName = "ID")
    @NotNull
    private Student student;

    @ManyToOne
    @JoinColumn(name = "COURSE_ID", referencedColumnName = "ID")
    @NotNull
    private Course course;

    // ... other fields and getters and setters
}

然后我有一個復雜的標准查詢,我正在為搜索目的而創建,希望所有學生都參加特定課程。 我有要添加到限制中的courseId 在 SQL 中,我會做這樣的事情:

select *
from STUDENT, STUDENT_COURSE
where STUDENT.ID = STUDENT_COURSE.STUDENT_ID
and STUDENT_COURSE.COURSE_ID = <courseId>

請注意,我只加入STUDENTSTUDENT_COURSE 使用上述設置的標准和實體,似乎我被迫加入STUDENTSTUDENT_COURSECOURSE因為我在STUDENT_COURSE上沒有 courseId 字段:

Join<Person, PersonCourse> personCourse = root.join("personCourses");
Join<PersonCourse, Course> course = personCourse.join("course");
Predicate onlySpecificCourse = builder.equal(course.get("id"), courseId);

這只是一些地方我都必須同時@ManyToOne從StudentCourse到的課程領域和courseId上StudentCourse場? 如果我將 courseId 字段聲明為:

@Column(name = "USER_ID", insertable = false, updatable = false)
private String userId;

然后加入變成:

Join<Person, PersonCourse> personCourse = root.join("personCourses");
Predicate onlySpecificCourse = builder.equal(personCourse.get("courseId"), courseId);

如果我這樣做,有什么我應該注意的問題嗎? 特別是,在PersonCourse實體上同時使用courseIdcourse設置器似乎很奇怪。


更新

我正在更新我的答案以為您提供解決方案,即使我不喜歡它。 :-)

但首先,聽起來您希望以 OOP 方式執行此操作,但您不想將持久化數據視為對象樹,因為 Person、PersonCourse 和 Course 都是同一對象樹的一部分,但是對於某些特殊情況,您可能會忘記這個事實。 您只能將 ORM 推到某個點,之后您將不得不退回到本機 SQL。

但是,我將在這里提供一個您可能不喜歡的 ORM 解決方案,所以在這里:

向 PersonCourse 實體添加一個新屬性並將其映射到連接表中的 COURSE_ID 列。 但是您必須確保在插入和更新中不使用新屬性。

@Column(name = "COURSE_ID", insertable = false, updatable = false)
private Long courseId;

現在您可以從等式中刪除 Course Root 並使用您在上面顯示的 Predicate。


原答案

如果 STUDENT_CLASS 表除了 STUDENT 和 CLASS 關系的 ID 之外沒有其他列,那么只需在 Student 和 Class 實體之間使用@ManyToMany ,而不是@ManyToOne ,並且不需要第三個實體; Hibernate 會為你處理它。

如果連接表確實有其他列,例如GRADERATING列,則使用如下所述的解決方案: 使用額外列映射多對多關聯表

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM