Custom bridge table in playframework ebean

2020-08-01 06:22发布

问题:

I am unsuccessfuly trying to create bridge table that would resolve two @ManyToMany relations. However this table have to contain additional field. For example:

Course: -course_id - pk

Student: -student_id -pk

Bridge: -(course_id, student_id) - pk
        -additional_field

My student class looks like this:

@Entity
public class Student extends Model {

    @Id
    @OneToMany
    public List<Bridge> student_id;
}

Course class is basicaly the same.

Bridge table looks like this:

@Entity
public class Bridge extends Model{

    @EmbeddedId 
    public compound_key student_course;

    public String additional_field;

    @Embeddable
    public class compound_key{

        @ManyToOne
        public Student student_id;

        @ManyToOne
        public Student course_id;

    }

}

Thank you for help.

回答1:

I have found the following solution. This is a solution without a composite key in Bridge. I added normal @Id field in Bridge class and relations to Student and Course are normal relations. This solution contains an additional 'id' field in the 'bridge' table in the database.

Here is the code:

Student.java:

@Entity
public class Student extends Model {

    @Id
    public Integer id;

    @OneToMany(mappedBy="student")
    public List<Bridge> bridges;

    public static Finder<Integer,Student> find = new Finder<Integer,Student>(
        Integer.class, Student.class
    ); 
}

Course.java:

@Entity
public class Course extends Model {

    @Id
    public Integer id;

    @OneToMany(mappedBy="course")
    public List<Bridge> bridges;

    public static Finder<Integer,Course> find = new Finder<Integer,Course>(
        Integer.class, Course.class
    ); 
}

Bridge.java:

@Entity
public class Bridge extends Model {

    @Id
    public Integer id;

    @ManyToOne public Student student;

    @ManyToOne public Course course;

    public String additional_field;

    public static Finder<Integer,Bridge> find = new Finder<Integer,Bridge>(
        Integer.class, Bridge.class
    ); 
}

EDIT

After many attempts I have found solution with composite key in Bridge class. Classes Student and Course are the same as in previous solution.

Bridge.java changed to following:

@Entity
public class Bridge extends Model {

    Bridge() {
        bridgeId = new BridgeId();      
    }

    @EmbeddedId
    protected BridgeId bridgeId;

    @ManyToOne
    @JoinColumn(name = "student_id", insertable = false, updatable = false)
    private Student student;

    @ManyToOne 
    @JoinColumn(name="course_id", insertable = false, updatable = false)
    private Course course;

    public String additional_field;

    public Student getStudent() {
        return student;
    }

    public void setStudent(Student aStudent) {
        student=aStudent;
        bridgeId.student_id = aStudent.id;
    }

    public Course getCourse() {
        return course;
    }

    public void setCourse(Course aCourse){
        course=aCourse;
        bridgeId.course_id = aCourse.id;
    }
}

And there is additional BridgeId.java:

@Embeddable
public class BridgeId implements Serializable
{
    public Integer student_id;

    public Integer course_id;

    public int hashCode() {
        return student_id + course_id;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) 
            return true;
        BridgeId b = (BridgeId)obj;
        if(b==null)
            return false;
        if (b.student_id == student_id && b.course_id == course_id) {
            return true;
        }
        return false;
    }
}

What is more important in this code is:

  1. Fields of embedded id are mapped to the same columns as ManyToOne relations.
  2. Value to 'student_id' and 'course_id' columns are inserted from embedded id and not from relations. This is because relations have attributes 'insertable' and 'updatable' set to false.
  3. I had to add getters and setters to 'student' and 'course' fields. In setters I am updating fields of embedded key.

Above solution has several workarounds. But I wasn't ableto find easier and cleaner one.