如何基于同一实体的另一个字段(列表)向实体添加新字段

How to add a new field to an entity based on another field of the same Entity which is a List

我有一个 Student Class:

@Getter
@Setter
@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    private String name;

    private double gpa;

    private int unitsPassed;

    private int failures;

    @ManyToOne
    @JoinColumn(name = "classroom_id", nullable = false)
    private Classroom classroom;
}

还有一个Classroom Class:

@Getter
@Setter
@Entity
public class Classroom {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private long id;

  private String name;

  @OneToMany(mappedBy = "classroom", cascade = CascadeType.ALL)
  private List<Student> students;

  public Student getBestStudent() {
    Comparator<Student> comparator =
        Comparator.comparing(Student::getGpa, Comparator.reverseOrder())
            .thenComparing(Student::getUnitsPassed, Comparator.reverseOrder())
            .thenComparing(Student::getFailures);

    return students.stream().min(comparator).orElse(null);
  }
}

出于某些操作原因,table 包含的教室应该有一个外键引用教室中最好学生的 ID。最佳学生的确定方法如 getBestStudent 中所列。我如何在课堂上添加一个字段 Class 来代表最好的学生。教室里的学生名单可以改变,因此最好的学生也可以改变。然后可以使用基于当前学生列表的同步服务填充新字段。

P.S.: 我无法控制需要这个外键的系统。

对我来说,这样的要求更多是关于报告查询,最好通过按需发出查询来解决,而不是直接将结果存储在 table 中。但如果你坚持这样做,你可以简单地将 best_student_id 映射到 Classroom :

@Entity
public class Classroom {

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "best_student_id")
  private Student bestStudent;

}

然后使用 OOP 封装技术强制执行这样的逻辑,即无论何时将学生添加到教室或从教室中删除,还要查找并更新该教室的最佳学生。

例如在Classroom中,添加方法来封装添加和删除学生的逻辑:

@Entity
public class Classroom {

  @OneToMany(mappedBy = "classroom", cascade = CascadeType.ALL)
  private List<Student> students;

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "best_student_id")
  private Student bestStudent;

  public void addStudent(Student student){
     student.setClassroom(this);
     this.students.add(student);

     bestStudent = getBestStudent();
  }

  public void removeStudent(Student student){
     this.students.remove(student);
     bestStudent = getBestStudent();
  }

  public Student getBestStudent() {
    Comparator<Student> comparator =
        Comparator.comparing(Student::getGpa, Comparator.reverseOrder())
            .thenComparing(Student::getUnitsPassed, Comparator.reverseOrder())
            .thenComparing(Student::getFailures);

    return students.stream().min(comparator).orElse(null);
  }

}

注意:我从 Classroom 中删除了 @Getter / @Setter 因为我不希望有人可以通过直接设置或获取学生列表以确保对教室的学生列表所做的所有更改都必须通过这些方法完成。

另请注意,此方法需要将教室的所有学生加载到内存中以计算出最好的学生。所以如果教室里有很多学生,就会出现性能和内存问题。如果发生这种情况,你可以考虑写一个查询来找到最好的学生,并将这样的逻辑封装在服务层而不是实体层。

我只是给你一个整体的想法。你必须自己微调代码。