2013-06-20 10 views
5

Questo è correlato a this question, ma l'esempio di seguito è più breve, quindi ho pensato che sarebbe stata utile un'altra domanda.Riproduci + Ebean + JPA: crea un'eliminazione su una mappatura OneToOne

Ho due entità, A e B, in una relazione uno-a-uno. Per una A, una B è opzionale, ed ogni B deve avere una A. Voglio cascata elimina da A a B. Ecco il mio primo tentativo:

@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; 

} 

Tuttavia, sembra che Ebean ignora il "optional" annotazione, perché quando eseguo trovare per un una salvata con id 1, il seguente SQL viene eseguita:

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

In altre parole, si fa un interno invece di una sinistra join, che provoca il ritrovamento di fallire quando non è associato B. Ho provato varie combinazioni di @JoinColumn, ecc. senza risultato. L'unica soluzione alquanto soddisfacente che ho trovato è quella di modellare A-to-B come una relazione "uno-a-molti" falsa. C'è una soluzione migliore? Si tratta di un bug o è una limitazione nota/dichiarata di Ebean?

risposta

1

Ho trovato la soluzione. Ho cambiato la direzione di questa mappatura. Così ho rimosso mappedBy = "a" dalla classe A e aggiunto mappedBy = "b" nella classe B.
Così il codice ora appare in questo modo:

@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; 

    ... 
} 

ho aggiunto name campo in classe B per rendere questo test più interessante.

La mia prova 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()); 
} 

E il risultato di questo test è:

[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 

Quindi, questo codice funziona bene, non importa se è A.bnull o meno. Come possiamo vedere nel registro, ora è left outer join anziché join.

Problemi correlati