Using Ebean/JPA in my Play application, how can I

2019-04-13 04:59发布

I have the following classes:

import play.db.ebean.Model;
import javax.persistence.*;

@Entity
public class A extends Model {
    @Id
    private int id;

    /* Other irrelevant properties */

    @OneToOne(cascade = CascadeType.ALL, optional = true)
    private B b;
}

import play.db.ebean.Model;
import javax.persistence.*;

@Entity
public class B extends Model {
    @Id
    private int id;

    /* Other irrelevant properties */

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

    @OneToOne(cascade = CascadeType.ALL, optional = false)
    private C c;
}

import play.db.ebean.Model;
import javax.persistence.*;

@Entity
public class C extends Model {
    @Id
    private int id;

    /* Other irrelevant properties */

    @OneToOne(mappedBy = "c")
    private B B;
}

In the database, it looks like this:

Table    a
Columns  id, ... (other irrelevant columns), b_id

Table    b
Columns  id, ...(other irrelevant columns), c_id

Table    c
Columns  id, ...(other irrelevant columns)

Now in one the controller methods (for those familiar with Play) I have an object of A, and would like to delete its property "b" from the database. This should also cascade to c, so c gets deleted too. This is my current approach:

B b = a.getB();
b.delete();

This throws an exception though:

[PersistenceException: ERROR executing DML bindLog[] error[Cannot delete or update a parent row: a foreign key constraint fails (databasename.a, CONSTRAINT fk_a_payme_4 FOREIGN KEY (b_id) REFERENCES b (id))]]

It basically boils down to the fact that I'm trying to delete b, while a still holds a foreign key reference to b in column b_id, so I should first set that reference to null.

In Java, this translates to:

B b = a.getB();
a.setB(null);
a.update();
b.delete();

This does set the reference to b in object a to null and correctly deletes the b object, but c does not get deleted from the database. (Why? I though the cascade property would take care of this) The only way I have found to fix this is to explicitly delete c as well, so like this:

B b = a.getB();
C c = b.getC();

b.setC(null);
b.update();
c.delete();

a.setB(null);
a.update();
b.delete();

I'm not very pleased about this though, because that's already 8 lines of code to delete two rows in the database, and it would be more if there were more relationships in this picture.

So as for my question:

How can I delete b from a so the reference from a to b is deleted automatically first and how can I make sure c is deleted too when I delete b?

Thank you in advance!

Edit: best idea so far: move the ownership of the a-b relationship to b.

2条回答
仙女界的扛把子
2楼-- · 2019-04-13 05:11

I run into some issue with @johny answer. Try this.

@JoinColumn(name = "b_id", nullable = false)
查看更多
我只想做你的唯一
3楼-- · 2019-04-13 05:17

Try using

class A{

   ......

   @JoinColumn(nullable=true)
   private B b;

   .......
}

See this question for more info What is the difference between @ManyToOne(optional=false) vs. @Column(nullable=false).

查看更多
登录 后发表回答