【问题标题】:How to add a new field to an entity based on another field of the same Entity which is a List如何根据同一实体的另一个字段(即列表)向实体添加新字段
【发布时间】:2022-01-16 14:19:24
【问题描述】:

我有一个Student 班级:

@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 类:

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

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

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

【问题讨论】:

    标签: postgresql spring-boot hibernate hibernate-onetomany


    【解决方案1】:

    对我来说,这样的要求更多是关于报告查询,最好通过按需发出查询来解决,而不是直接将结果存储在表中。但是如果你坚持这样做,你可以简单地将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,因为我不希望有人可以通过直接设置或获取学生列表来违反此类逻辑,以确保所有更改都在一个教室的学生名单必须通过这些方法来完成。

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

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

    【讨论】:

      猜你喜欢
      • 2020-07-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多