Play + Ebean + JPA:在OneToOne映射上级联删除

use*_*521 5 java one-to-one jpa-2.0 ebean playframework-2.1

这与这个问题有关,但下面的例子较短,所以我认为另一个问题是有道理的.

我有两个实体,A和B,一对一的关系.对于A,B是可选的,并且每个B必须具有A.我想级联从A到B的删除.这是我的第一次尝试:

@Entity
public class A extends Model {

    @Id
    private Long id;

    @OneToOne(optional = true, mappedBy = "a", cascade = CascadeType.REMOVE, orphanRemoval = true)
    private B b;

}

@Entity
public class B extends Model {

    @Id
    private Long id;

    @OneToOne(optional = false)
    private A a;

}
Run Code Online (Sandbox Code Playgroud)

但是,似乎Ebean忽略了"可选"注释,因为当我为ID为1的已保存A执行查找时,将执行以下SQL:

select t0.id c0, t1.id c1 
from a t0
join b t1 on t1.a_id = t0.id 
where t0.id = 1  
Run Code Online (Sandbox Code Playgroud)

换句话说,它执行内部而不是左连接,这导致查找失败,当没有关联B.我尝试了各种组合@JoinColumn,等等无济于事.我发现的唯一令人满意的解决方法是将A-to-B模型化为"假的"一对多关系.有更好的解决方案吗?这是一个错误还是Ebean已知/明确的限制?

rtr*_*szk 2

我已经找到了解决方案。我改变了这个映射的方向。所以我mappedBy = "a"A课堂上删除并添加到课堂mappedBy = "b"B
所以代码现在看起来像这样:

@Entity
public class A extends Model {

    @Id
    private Long id;

    @OneToOne(optional = true, cascade = CascadeType.REMOVE, orphanRemoval = true)
    private B b;

 ...
}


@Entity
public class B extends Model {

    @Id
    private Long id;

    @OneToOne(optional = false, mappedBy = "b")
    private A a;

    private String name;

    ...
}
Run Code Online (Sandbox Code Playgroud)

name在B类中添加了字段以使这个测试更有趣。

我的测试方法:

@Test
public void abTest () {
    FakeApplication app = Helpers.fakeApplication(Helpers.inMemoryDatabase());
    Helpers.start(app);

    A a = new A();
    B b = new B();
    a.setId(1L);
    b.setId(2L);
    a.setB(b);
    b.setA(a);
    b.setName("bbb");

    Ebean.save(b);
    Ebean.save(a);

    A fa = Ebean.find(A.class, 1L);
    System.out.println("a.id: "+fa.getId());
    System.out.println("a.b.id: "+fa.getB());
    System.out.println("a.b.name: "+fa.getB().getName());

    A a1 = new A();
    a1.setId(3L);
    Ebean.save(a1);
    A fa1 = Ebean.find(A.class, 3L);
    System.out.println("a1.id: "+fa1.getId());
    System.out.println("a1.b.id: "+fa1.getB());

    B fb = Ebean.find(B.class, 2L);
    System.out.println("b.id: "+fb.getId());
    System.out.println("b.name: "+fb.getName());
    System.out.println("b.a.id: "+fb.getA().getId());
}
Run Code Online (Sandbox Code Playgroud)

而这次测试的结果是:

[debug] c.j.b.PreparedStatementHandle - insert into b (id, name) values (2,'bbb')
[debug] c.j.b.PreparedStatementHandle - insert into a (id, b_id) values (1,2)
[debug] c.j.b.PreparedStatementHandle - select t0.id c0, t0.b_id c1 from a t0 where t0.id = 1
a.id: 1
a.b.id: models.B@2
[debug] c.j.b.PreparedStatementHandle - select t0.id c0, t0.name c1, t1.id c2 from b t0 left outer join a t1 on t1.b_id = t0.id  where t0.id = 2
a.b.name: bbb
[debug] c.j.b.PreparedStatementHandle - insert into a (id, b_id) values (3,'[SQL NULL of type -5]')
[debug] c.j.b.PreparedStatementHandle - select t0.id c0, t0.b_id c1 from a t0 where t0.id = 3
a1.id: 3
a1.b.id: null
[debug] c.j.b.PreparedStatementHandle - select t0.id c0, t0.name c1, t1.id c2 from b t0 left outer join a t1 on t1.b_id = t0.id  where t0.id = 2
b.id: 2
b.name: bbb
b.a.id: 1
Run Code Online (Sandbox Code Playgroud)

所以无论是否A.b存在,这段代码都可以正常工作null。正如我们在日志中看到的,现在left outer joinjoin.