Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OneToMany Spring Data JDBC

I want to model a OneToMany Relation with Spring Data JDBC. I´ve read on this very useful blog https://spring.io/blog/2018/09/24/spring-data-jdbc-references-and-aggregates that you should use references when you want to model ToMany Reference:

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

So I have this scenario:
One Student can have multiple Registration. And one Registration can have exactly one Student. If you delete Registration the assigned Student should not get deleted cascading.
I ended up with this modelling:

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

}

My question is whether my modeling is correctly implemented?

like image 321
Thomas Lang Avatar asked Nov 19 '18 13:11

Thomas Lang


People also ask

Is Spring data JDBC ORM?

Spring Data JDBC aims at being conceptually easy. In order to achieve this it does NOT offer caching, lazy loading, write behind or many other features of JPA. This makes Spring Data JDBC a simple, limited, opinionated ORM.

What is the difference between Spring JDBC and Spring data JDBC?

Spring Data JDBC has less abstractions than Spring Data JPA, but uses Spring Data concepts to make it easier to do CRUD operations than Spring JDBC. It sits closer to the database because it does not contain the most part of the Spring Data magic when querying the database.

What is Spring data JDBC?

Spring Data JDBC is an object-relational mapping framework for relational databases that aims to avoid most of the complexity of other ORM frameworks. It does that by avoiding features like lazy loading, managed lifecycles of entity objects and caching.


1 Answers

You are quoting the article talking about "Many-To-X" but you talk yourself about "X-To-Many". You can model a One-To-One or a One-To-Many relationship with a direct reference, or a List/Set/Map of entities.

What you should avoid are bidirectional relationships. While you probably can make them work with the approach you are using, you really shouldn't.

Which brings us to the question: How should this model look like?

The central decision to make is how many aggregates are involved?

A Student certainly is an aggregate and the Student class is its aggregate root. It can exist on its own.

But what about Registration? I'd argue, it is probably part of the same aggregate. The delete test is a good one. If you delete a Student from the system, do the registrations of that Student still have value? Or should the disappear together with the Student?

As an exercise let's do both variants. I start with: Just one aggregate:

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

With this, you would have a single repository:

interface StudentRepository extends CrudRepository<Student, Long>{}

I removed all the Lombok annotations since they aren't really relevant to the problem. Spring Data JDBC can operate on simple attributes.

If Registration and Student both are aggregates it gets a little more involved: You need to decide which side owns the reference.

First case: The Registration owns the reference.

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

Second case: The Student owns the reference

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

Note that the RegistrationRef doesn't have a studentId or similar. The table assumed for the registrations property will have a student_id column.

like image 152
Jens Schauder Avatar answered Sep 19 '22 16:09

Jens Schauder