1

How can I model many to many relationship with same entity with spring data jdbc. I have a scenario where a task can depend on several other task and at the same time the task has dependants but it is same object. I have done this previously with jpa

@JoinTable(
 name = "task_dependencies",
 joinColumns = @JoinColumn(name = "dependent_process"),
 inverseJoinColumns = @JoinColumn(name = "depends_on_process")
)
private final Set<AsyncTask> dependencies = new HashSet<>();
@ManyToMany(fetch = FetchType.LAZY, mappedBy = "dependencies")
private final Set<AsyncTask> dependents = new HashSet<>();
asked Dec 10, 2021 at 10:09

1 Answer 1

3

In your example AsyncTask is an aggregate and its own aggregate root. So references from one AsyncTask to another are considered references between aggregates.

In Spring Data JDBC (and also recommended in Domain Driven Design) references to other aggregates are to be implemented as ids, not actual Java references.

For the mapping table you need a separate small entity which becomes part of the aggregate on one side of the relationship.

Instead of just an Id you can use an AggregateReference in order to avoid having Long values all over the place.

The complete model could look like this:


@Table
class AsyncTask {
 @Id
 Long id;
 String name;
 @MappedCollection(idColumn = "FROM_ID")
 Set<DependentTask> dependents = new HashSet<>();
 AsyncTask(String name) {
 this.name = name;
 }
 public void addDependent(AsyncTask task) {
 dependents.add(new DependentTask(task.id));
 }
}

@Table
class DependentTask {
 @Column("TO_ID")
 AggregateReference<AsyncTask, Long> id; // this is the Id of the dependent task, note that it is not marked with `@Id`
 DependentTask(Long id) {
 this.id = AggregateReference.to(id);
 }
}

And be used like this:

AsyncTask one = repo.save(new AsyncTask("one"));
AsyncTask two = repo.save(new AsyncTask("two"));
AsyncTask three = new AsyncTask("three");
three.addDependent(one);
three.addDependent(two);
repo.save(three);
one.addDependent(two);
repo.save(one);
two.addDependent(two);
repo.save(two);

The underlying database schema looks like this:

CREATE TABLE ASYNC_TASK (
 ID INTEGER IDENTITY PRIMARY KEY,
 NAME VARCHAR (200) NOT NULL
);
CREATE TABLE DEPENDENT_TASK (
 FROM_ID INTEGER NOT NULL REFERENCES ASYNC_TASK(ID),
 TO_ID INTEGER NOT NULL REFERENCES ASYNC_TASK(ID)
);

The complete source code is on GitHub.

For more information on the topic read Spring Data JDBC, References, and Aggregates and Spring Data JDBC - How do I make Bidirectional Relationships?

answered Dec 15, 2021 at 12:40
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.