我将把我的问题分成3部分:
@Entity
@Table(name = "foo")
public class Foo {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false, unique = true)
private Long id;
// ... other fields
@OneToMany(mappedBy = "fooer", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Bar> barInfo = new ArrayList<>();
@OneToMany(mappedBy = "fooing", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Bar> baringInfo = new ArrayList<>();
}
@Entity
@Table(name = "bar")
public class Bar {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false, unique = true)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "fooer_id", referencedColumnName = "id", nullable = false,
foreignKey = @ForeignKey(name = "bar_fooer_id_fkey"))
private Foo fooer;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "fooing_id", referencedColumnName = "id", nullable = false,
foreignKey = @ForeignKey(name = "bar_fooing_id_fkey"))
private Foo fooing;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "baz_id", referencedColumnName = "id", nullable = false,
foreignKey = @ForeignKey(name = "bar_baz_id_fkey"))
private Baz baz;
}
@Entity
@Table(name = "baz")
public class Baz {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false, unique = true)
private Long id;
// ... other fields
}
CREATE TABLE some_schema.bar
(
id int8 GENERATED BY DEFAULT AS IDENTITY ( INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1 NO CYCLE) NOT NULL,
fooer_id int8 NOT NULL,
fooing_id int8 NOT NULL,
baz_id int8 NOT NULL,
CONSTRAINT bar_id_key UNIQUE (id),
CONSTRAINT bar_fooer_id_fkey FOREIGN KEY (fooer_id) REFERENCES some_schema.foo (id),
CONSTRAINT bar_fooing_id_fkey FOREIGN KEY (fooing_id) REFERENCES some_schema.foo (id),
CONSTRAINT bar_baz_id_fkey FOREIGN KEY (baz_id) REFERENCES some_schema.baz (id)
);
假设我们有两个
Foo
类型的实体(John[id=111] 和 Alice[id=222])和一个 Baz
类型的实体(Paperwork[id=999])。 John 想向 Alice 请求与 文书工作 相关的帮助。我当前对上面解释的添加请求的实现如下所示:
final var john = getById(contextId); // fooing
final var alice = getById(id); // fooer
final var paperwork = bazService.getBazById(bazId);
john.getBarInfo()
.add(Bar.builder()
.fooer(alice)
.fooing(john)
.baz(paperwork)
.build());
fooRepository.save(john); // <-- Here john have barInfo with values set above and baringInfo empty which is what we want
表
bar
中的数据如下所示:
id | fooer_id | fooing_id | baz_id |
---|---|---|---|
1 | 222 | 111 | 999 |
从当前实施和要求的角度来看,这看起来还不错。 但是问题在于检索实体和类型为
Foo
的实体。
通过 ID 或整个列表检索预期结果:
{
"John": {
"barInfo": {
"fooers": [
{
"foo_id": 222,
"baz_id": 999
}
],
"fooing": []
}
},
"Alice": {
"barInfo": {
"fooers": [],
"fooing": [
{
"foo_id": 111,
"baz_id": 999
}
]
}
}
}
实际结果:
{
"John": {
"barInfo": {
"fooers": [],
"fooing": [
{
"foo_id": 111,
"baz_id": 999
}
]
}
},
"Alice": {
"barInfo": {
"fooers": [
{
"foo_id": 222,
"baz_id": 999
}
],
"fooing": []
}
}
}
上面显示的数据是实体的伪表示
从 Spring 存储库检索(未包装到其他对象)Foo
fooing
/fooers
似乎颠倒了(我认为实体之间的关联有问题),我想知道我的方法是否存在一些缺陷。任何建议将不胜感激。
项目中使用的版本:
想通了!
我所要做的就是反转
mappedBy
参数 Foo
:
@Entity
@Table(name = "foo")
public class Foo {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false, unique = true)
private Long id;
// ... other fields
@OneToMany(mappedBy = "fooing", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
~~~~~~~~
private List<Bar> barInfo = new ArrayList<>();
@OneToMany(mappedBy = "fooer", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
~~~~~~~
private List<Bar> baringInfo = new ArrayList<>();
}
在与添加请求相关的服务中,而不是添加到
barInfo
或baringInfo
列表中,我们应该刚刚保存新的Bar
,它将与相应的实体相关联:
final var john = getById(contextId); // fooing
final var alice = getById(id); // fooer
final var paperwork = bazService.getBazById(bazId);
final var bar = Bar.builder()
.fooer(alice)
.fooing(john)
.baz(paperwork)
.build();
barRepository.save(bar);
检索有关
Foo
的信息给出了我的问题中提到的预期结果。