简体   繁体   中英

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

I have a 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;
}

And a 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);
  }
}

For some operational reasons, the table containing classrooms should have a foreign key referencing the id of the best student in the classroom. The best student is determined as listed in the getBestStudent method. How would I add a field to the classroom Class to represent the best student. The list of students in the classroom can change and therefore best student could change. The new field could then be filled with a synchronization service based on the current list of students.

PS: I have no control over the systems requiring this foreign key.

To me, such requirement is more about a reporting query which is better to be solved by issuing a query on demand rather than storing the result in a table directly. But if you insist to do it, you can simply map the best_student_id to the Classroom :

@Entity
public class Classroom {

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

}

Then use OOP encapsulation technique to enforce the logic that whenever a student is added to or removed from a classroom, also find and update the best student for that classroom.

For example in Classroom , add methods to encapsulate the logic of adding and removing a student:

@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);
  }

}

Note: I remove @Getter / @Setter from Classroom as I do not want someone can violate such logic by directly setting or getting the students list to make sure that all changes made on a classroom 's student list must be done through these methods.

Please also note that this approach requires loading all students of a classroom to memory to compute the best student. So it will have performance and memory problem if a classroom contain many students. If it happens, you can consider to write a query to find the best student and encapsulate such logic in the service layer rather than the entity layer.

I just give you an overall idea. You have to fine tune the codes by yourself.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM