2013-06-20 63 views
5

這與this question有關,但下面的示例較短,所以我想出了另一個有關此問題的問題。Play + Ebean + JPA:在OneToOne映射上級聯刪除

我有兩個實體,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; 

} 

然而,這似乎是Ebean忽略「可選」註解,因爲當我執行尋找一省一ID爲1,下面的SQL執行:

select t0.id c0, t1.id c1 
from a t0 
join b t1 on t1.a_id = t0.id 
where t0.id = 1 

換句話說,它的內部,而不是左連接,這使得查找時失敗沒有關聯B.我嘗試過各種組合@JoinColumn等無濟於事。我發現唯一令人滿意的解決方法是將A-to-B建模爲「假」一對多關係。有更好的解決方案嗎?這是一個錯誤還是它是Ebean的已知/限制?

回答

1

我找到了解決方案。我切換了這個映射的方向。所以我從A類刪除了mappedBy = "a",並在B類中添加了mappedBy = "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; 

    ... 
} 

我加入B級name領域,使這個測試更有趣。

我的測試medhod:

@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()); 
} 

而這個測試的結果是:

[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: [email protected] 
[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 

所以此代碼的工作好不管A.bnull與否。正如我們在日誌中看到的,現在有left outer join而不是join