Spring 引导数据 jdbc 实现与同一实体的多对多关系
Spring boot data jdbc implement Many to Many relationship with same entity
如何使用 spring 数据 jdbc 对同一实体的多对多关系建模。我有一个场景,其中一个任务可以依赖于其他几个任务,同时该任务有依赖项但它是同一个对象。我以前用 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<>();
在您的示例中,AsyncTask
是一个聚合及其自己的聚合根。
因此,从一个 AsyncTask
到另一个的引用被认为是聚合之间的引用。
在 Spring 数据 JDBC 中(并且在领域驱动设计中也推荐)对其他聚合的引用将作为 ID 实现,而不是实际的 Java 引用。
对于映射 table,您需要一个单独的小实体,它成为关系一侧聚合的一部分。
您可以使用 AggregateReference
而不是 Id
,以避免到处都是 Long
值。
完整的模型可能如下所示:
@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);
}
}
并像这样使用:
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);
底层数据库模式如下所示:
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)
);
complete source code is on GitHub.
有关该主题的更多信息,请阅读 Spring Data JDBC, References, and Aggregates
和 Spring Data JDBC - How do I make Bidirectional Relationships?
如何使用 spring 数据 jdbc 对同一实体的多对多关系建模。我有一个场景,其中一个任务可以依赖于其他几个任务,同时该任务有依赖项但它是同一个对象。我以前用 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<>();
在您的示例中,AsyncTask
是一个聚合及其自己的聚合根。
因此,从一个 AsyncTask
到另一个的引用被认为是聚合之间的引用。
在 Spring 数据 JDBC 中(并且在领域驱动设计中也推荐)对其他聚合的引用将作为 ID 实现,而不是实际的 Java 引用。
对于映射 table,您需要一个单独的小实体,它成为关系一侧聚合的一部分。
您可以使用 AggregateReference
而不是 Id
,以避免到处都是 Long
值。
完整的模型可能如下所示:
@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);
}
}
并像这样使用:
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);
底层数据库模式如下所示:
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)
);
complete source code is on GitHub.
有关该主题的更多信息,请阅读 Spring Data JDBC, References, and Aggregates 和 Spring Data JDBC - How do I make Bidirectional Relationships?