我想用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<>();
}
我的问题是我的建模是否正确实施?
答案 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可以对简单属性进行操作。
如果Registration
和Student
都是聚合的,则会涉及更多:
您需要确定哪一方拥有引用。
第一种情况: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
列。