【问题标题】:Ebean multiple @ManyToMany delivers strange behaviorEbean 多个 @ManyToMany 提供了奇怪的行为
【发布时间】:2014-06-07 15:59:18
【问题描述】:

每当我尝试在模型中将多个 @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) 查询。

有人知道这里发生了什么吗?

【问题讨论】:

    标签: java playframework playframework-2.0 many-to-many ebean


    【解决方案1】:

    这是一个有趣的案例。我做了一些测试,有结果:

    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)
    

    Ebean 在查找bar1 时应参考foo_bar1 表,在查找bar2 时应参考foo_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 表。

    似乎两个@ManyToMany 关系对于Ebean 来说太多了。我想 Ebean 假设两个表之间只能有一个可连接的。并且它的名字在第一次查询后被缓存。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-18
      • 2023-03-22
      • 1970-01-01
      • 1970-01-01
      • 2021-09-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多