【问题标题】:Play + Ebean + JPA: Cascade a delete on a OneToOne mappingPlay + Ebean + JPA:在 OneToOne 映射上级联删除
【发布时间】:2013-06-20 20:29:08
【问题描述】:

这与this question 相关,但下面的示例更短,所以我认为关于这方面的另一个问题是有意义的。

我有两个实体,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 的已保存 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  

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

【问题讨论】:

    标签: java jpa-2.0 playframework-2.1 one-to-one 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 字段,让这个测试更有趣。

    我的测试方法:

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

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

    【讨论】:

      猜你喜欢
      • 2016-12-13
      • 1970-01-01
      • 1970-01-01
      • 2014-05-08
      • 1970-01-01
      • 2014-05-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多