一对多Spring Data JDBC

时间:2018-11-19 13:52:01

标签: java spring-data software-design spring-data-jdbc

我想用Spring Data JDBC为OneToMany关系建模。我在这个非常有用的博客https://spring.io/blog/2018/09/24/spring-data-jdbc-references-and-aggregates上已经读到过,当您要建模ToMany Reference时,应该使用引用:

  

因此,任何多对一和多对多关系都必须仅通过引用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<>();

}

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

1 个答案:

答案 0 :(得分:6)

您引用的是有关“许多到X”的文章,但您自己谈论的是“许多到X”。您可以使用直接参考或实体的列表/集合/地图来建模一对一或一对多关系。

您应该避免的是双向关系。尽管您可以使它们与您使用的方法一起使用,但实际上不应该这样做。

这带给我们一个问题:该模型的外观如何?

要做出的主要决定是涉及多少个聚集体?

Student当然是聚合,而Student类是其聚合根。它可以独立存在。

但是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 Data 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属性的表将具有student_id列。