每当我尝试在模型中使用@ManyToMany
多个CascadeType.ALL
属性时,我会遇到使用Ebean(版本3.2.2)的奇怪行为。
我做了一个简化的例子来重现这个问题:
我有以下两个实体(省略了getter)
@Entity
public class Foo extends Model {
@Id
@GeneratedValue
private Long id;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "foo_bar1")
private List<Bar> bars1;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "foo_bar2")
private List<Bar> bars2;
public void addBar1(Bar bar1) {
bars1.add(bar1);
}
public void addBar2(Bar bar2) {
bars2.add(bar2);
}
}
和
@Entity
public class Bar extends Model {
@Id
@GeneratedValue
private Long id;
private String name;
@ManyToMany(mappedBy = "bars1")
private List<Foo> foos1;
@ManyToMany(mappedBy = "bars2")
private List<Foo> foos2;
public Bar(String name) {
this.name = name;
}
}
但每次执行以下测试时都会导致奇怪的行为
@Test
public void cascadeTest() {
Ebean.beginTransaction();
Foo foo = new Foo();
Bar bar1 = new Bar("bar1");
Bar bar2 = new Bar("bar2");
foo.addBar1(bar1);
foo.addBar2(bar2);
Ebean.save(foo);
Ebean.commitTransaction();
}
因为Foo.bars2
中的值未被保留(例如foo.getBars2().size() == 0
)。
Ebean生成以下SQL查询
insert into foo (id) values (1)
insert into bar (id, name) values (1,'bar1')
insert into foo_bar1 (foo_id, bar_id) values (1, 1)
insert into bar (id, name) values (2,'bar2')
没有所需的insert into foo_bar2 (foo_id, bar_id) values (1, 2)
查询。
有人知道这里发生了什么吗?
答案 0 :(得分:2)
这是一个有趣的案例。我做了一些测试,结果如下:
将foo
添加到条形码列表后,Ebean正确保存了关系
所以下面的代码:
Foo foo = new Foo();
Bar bar1 = new Bar("bar1");
Bar bar2 = new Bar("bar2");
foo.addBar1(bar1);
foo.addBar2(bar2);
bar1.foos1.add(foo);
bar2.foos2.add(foo);
Ebean.save(foo);
生成以下SQL查询:
insert into foo (id) values (1)
insert into bar (id, name) values (1,'bar1')
insert into foo_bar1 (foo_id, bar_id) values (1, 1)
insert into bar (id, name) values (2,'bar2')
insert into foo_bar2 (bar_id, foo_id) values (2, 1)
但是当我想阅读foo
并且它是酒吧时,我收到了有趣的结果
以下代码:
Foo ffoo = Ebean.find(Foo.class, 1L);
System.out.println("first bar:"+ffoo.bars1.get(0).name);
System.out.println("second bar:"+ffoo.bars2.get(0).name);
给出了结果:
first bar:bar1
second bar:bar1
并生成查询:
select t0.id c0 from foo t0 where t0.id = 1
select int_.foo_id c0, t0.id c1, t0.name c2 from bar t0 left outer join foo_bar1 int_ on int_.bar_id = t0.id where (int_.foo_id) in (1)
select int_.foo_id c0, t0.id c1, t0.name c2 from bar t0 left outer join foo_bar1 int_ on int_.bar_id = t0.id where (int_.foo_id) in (1)
在查找foo_bar1
时,Ebean在查找bar1
和foo_bar2
表时应引用bar2
表。但在这两种情况下,Ebean都查询foo_bar1
表。
我将代码更改为:
Foo ffoo = Ebean.find(Foo.class, 1L);
System.out.println("second bar:"+ffoo.bars2.get(0).name);
System.out.println("first bar:"+ffoo.bars1.get(0).name);
然后Ebean将两次提到foo_bar2
表。
似乎Ebean的两个@ManyToMany
关系太多了。我想Ebean假设两个表之间只能有一个连接表。它的名字在第一次查询后被缓存。