OneToMany Spring 数据 JDBC

OneToMany Spring Data JDBC

我想用 Spring 数据 JDBC 建立一对多关系模型。我在这个非常有用的博客 https://spring.io/blog/2018/09/24/spring-data-jdbc-references-and-aggregates 上读到,当你想为 ToMany 建模时应该使用引用参考:

Therefore any Many-to-One and Many-to-Many relationship must be modeled by just referencing the id.

所以我有这个场景:
一个 Student 可以有多个 Registration。并且一个 Registration 可以正好有一个 Student。如果您删除 Registration,则分配的 Student 不应被级联删除。
我最终得到了这个模型:

@Data
@AllArgsConstructor(access = AccessLevel.PRIVATE, onConstructor = @__(@PersistenceConstructor))
public class Registration {

    private final @Id
    @Wither
    long registrationId;

    @NotNull
    private String electiveType;

    @NotNull
    private LocalDateTime created = LocalDateTime.now();

    @NotNull
    private StudentRegistrationReference studentRegistrationReference;

}

@Data
@AllArgsConstructor(access = AccessLevel.PRIVATE, onConstructor = @__(@PersistenceConstructor))
public class StudentRegistrationReference {
    private long student;
    private long registration;
}

@Data
@AllArgsConstructor(access = AccessLevel.PRIVATE, onConstructor = @__(@PersistenceConstructor))
public class Student {

    private final @Id
    @Wither
    long studentId;

    @NotNull
    @Size(min = 4, max = 20)
    private String userId;

    @NotNull
    @Min(0)
    private int matriculationNumber;

    @NotNull
    @Email
    private String eMail;

    private Set<StudentRegistrationReference> studentRegistrationReferences = new HashSet<>();

}

我的问题是我的建模是否正确实施?

您引用的是 "Many-To-X" 的文章,但您自己却在谈论 "X-To-Many"。您可以使用直接引用或 List/Set/Map 实体对一对一或一对多关系进行建模。

你应该避免的是双向关系。虽然您可能可以让它们按照您正在使用的方法工作,但实际上不应该这样做。

这让我们想到了一个问题:这个模型应该是什么样子的?

要做出的核心决定是涉及多少聚合?

一个Student肯定是一个聚合,Studentclass是它的聚合根。它可以独立存在。

但是 Registration 呢?我会争辩说,它可能是同一聚合的一部分。删除测试是一个很好的测试。如果你从系统中删除了一个Student,那个Student的注册还有价值吗?还是应该和Student一起消失?

作为练习,我们来做两个变体。我开始:只有一个聚合:

class Registration {

    @Id private long Id;

    String electiveType;
    LocalDateTime created = LocalDateTime.now();
}

class Student {

    @Id private long Id;

    String userId;
    int matriculationNumber;
    String eMail;
    Set<Registration> registrations = new HashSet<>();
}

这样,您将拥有一个存储库:

interface StudentRepository extends CrudRepository<Student, Long>{}

我删除了所有 Lombok 注释,因为它们与问题无关。 Spring数据JDBC可以对简单的属性进行操作。

如果 RegistrationStudent 都是聚合,它会涉及更多一点: 您需要决定哪一方拥有参考。

第一种情况:Registration 拥有引用。

class Registration {

    @Id private long Id;

    String electiveType;
    LocalDateTime created = LocalDateTime.now();

    Long studentId;
}

public class Student {

    @Id private long Id;

    String userId;
    int matriculationNumber;
    String eMail;
}

第二种情况:Student 拥有引用

class Registration {

    @Id private long Id;

    String electiveType;
    LocalDateTime created = LocalDateTime.now();
}

class Student {

    @Id private long Id;

    String userId;
    int matriculationNumber;
    String eMail;

    Set<RegistrationRef> registrations = new HashSet<>();
}

class RegistrationRef {

    Long registrationId;
}

请注意 RegistrationRef 没有 studentId 或类似的。为 registrations 属性 假设的 table 将有一个 student_id 列。