Java 通过仅使用FK列而不是相关实体来消除JPA查询中的额外连接';身份证

Java 通过仅使用FK列而不是相关实体来消除JPA查询中的额外连接';身份证,java,hibernate,jpa,join,criteria-api,Java,Hibernate,Jpa,Join,Criteria Api,我与实体的关系如下: STUDENT many-to-one STUDENT_COURSE one-to-many COURSE @Entity @Table(name = "STUDENT") public course Student { @Id @Column(name = "ID", nullable = false) private Long id; @OneToMany(mappedBy = "student") private Set&l

我与实体的关系如下:

STUDENT many-to-one STUDENT_COURSE one-to-many COURSE
@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
}
基本上,学生和他们的课程之间存在着一种多对多的关系。这种关系由
STUDENT\u COURSE
表表示

假设我为
学生
学生课程
课程
设置了实体,以便:

STUDENT many-to-one STUDENT_COURSE one-to-many COURSE
@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
}
请注意,我只加入了
STUDENT
STUDENT\u课程
。通过如上所述设置标准和实体,我似乎被迫加入
学生
学生课程
课程
,因为我在
学生课程
上没有courseId字段:

Join<Person, PersonCourse> personCourse = root.join("personCourses");
Join<PersonCourse, Course> course = personCourse.join("course");
Predicate onlySpecificCourse = builder.equal(course.get("id"), courseId);
然后连接变成:

Join<Person, PersonCourse> personCourse = root.join("personCourses");
Predicate onlySpecificCourse = builder.equal(personCourse.get("courseId"), courseId);
Join personCourse=root.Join(“personCourses”);
仅谓词SpecificCourse=builder.equal(personCourse.get(“courseId”),courseId);
如果我这样做了,有什么我应该注意的地方吗?特别是,在
PersonCourse
实体上同时为
courseId
course
设置setter似乎很奇怪。


更新 我正在更新我的答案,以便为您提供解决方案,尽管我不喜欢它。:-)

但首先,听起来您希望以面向对象的方式来实现这一点,但您不希望将持久化数据视为对象树,在这种情况下,PersonCourse和Course都是同一个对象树的一部分,但在某些特殊情况下,您希望忘记这一事实。您只能将ORM提升到某一点,之后您将不得不求助于本机SQL

但是,我将在这里提供一个您可能不喜欢的ORM解决方案,因此,它是这样的:

向PersonCourse实体添加一个新属性,并将其映射到联接表中的“课程ID”列。但您必须确保在插入和更新中不使用新属性

@Column(name = "COURSE_ID", insertable = false, updatable = false)
private Long courseId;
现在你可以从方程中去掉课程根,然后用上面的谓词


原始答案 如果STUDENT_CLASS table除了学生和类关系的ID之外没有其他列,那么只需在学生和类实体之间使用@manytomy,而不是@manytomone,并且不需要第三个实体;Hibernate会帮你处理的


如果联接表确实有其他列,例如GRADE或RATING列,则使用如下所述的解决方案:

我很难理解为什么带有额外连接的标准解决方案对您不起作用,您能扩展吗?好问题。添加无用的连接是我想要避免的事情。我查询的ID在第二个表上,所以从技术上讲,连接到第三个表是多余的,可能会对查询的性能产生负面影响。明白了。然而,考虑在IDEXS上加入应该对性能有不可忽视的影响。关于你的解决方案,不幸的是,我不能给你一个答案。没有比你已经解决的问题更多的问题了。至于setter,请记住,JPA将忽略覆盖
courseId
的值。谢谢。联接表中有额外的信息,因此我们不能使用“@manytomy”。我们已经按照您的链接所示绘制了关系图。不过,这并没有回答关于额外连接的原始问题。