Can add extra field(s) to @ManyToMany Hibernate extra table?

I have these two class(table)

@Entity
@Table(name = "course")
public class Course {

    @Id
    @Column(name = "courseid")
    private String courseId;
    @Column(name = "coursename")
    private String courseName;
    @Column(name = "vahed")
    private int vahed;
    @Column(name = "coursedep")
    private int dep;
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "student_course", joinColumns = @JoinColumn(name = "course_id"),  inverseJoinColumns = @JoinColumn(name = "student_id"))
    private Set<Student> student = new HashSet<Student>();
//Some setter and getter

and this one:

    @Entity
    @Table(name = "student")
    public class Student {

        @Id
        @Column(name="studid")
        private String stId;
        @Column(nullable = false, name="studname")
        private String studName;
        @Column(name="stmajor")
        private String stMajor;
        @Column(name="stlevel", length=3)
        private String stLevel;
        @Column(name="stdep")
        private int stdep;

        @ManyToMany(fetch = FetchType.LAZY)
        @JoinTable(name = "student_course"
                ,joinColumns = @JoinColumn(name = "student_id")
                ,inverseJoinColumns = @JoinColumn(name = "course_id")
        )
        private Set<Course> course = new HashSet<Course>();
//Some setter and getter

After running this code an extra table was created in database(student_course), now I wanna know how can I add extra field in this table like (Grade, Date , and ... (I mean student_course table)) I see some solution but I don't like them, Also I have some problem with them:

First Sample


If you add extra fields on a linked table (STUDENT_COURSE), you have to choose an approach according to skaffman's answer or another as shown bellow.

There is an approach where the linked table (STUDENT_COURSE) behaves like a @Embeddable according to:

@Embeddable
public class JoinedStudentCourse {

    // Lets suppose you have added this field
    @Column(updatable=false)
    private Date joinedDate;

    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="STUDENT_ID", insertable=false, updatable=false)
    private Student student;

    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="COURSE_ID", insertable=false, updatable=false)
    private Course course;

    // getter's and setter's 

    public boolean equals(Object instance) {
        if(instance == null)
            return false;

        if(!(instance instanceof JoinedStudentCourse))
            return false;

        JoinedStudentCourse other = (JoinedStudentCourse) instance;
        if(!(student.getId().equals(other.getStudent().getId()))
            return false;

        if(!(course.getId().equals(other.getCourse().getId()))
            return false;

        // ATT: use immutable fields like joinedDate in equals() implementation
        if(!(joinedDate.equals(other.getJoinedDate()))
            return false;

        return true;
    }

    public int hashcode() {
        // hashcode implementation
    }

}

So you will have in both Student and Course classes

public class Student {

    @CollectionOfElements
    @JoinTable(
        table=@Table(name="STUDENT_COURSE"),
        joinColumns=@JoinColumn(name="STUDENT_ID")
    )
    private Set<JoinedStudentCourse> joined = new HashSet<JoinedStudentCourse>();

}

public class Course {

    @CollectionOfElements
    @JoinTable(
        table=@Table(name="STUDENT_COURSE"),
        joinColumns=@JoinColumn(name="COURSE_ID")
    )
    private Set<JoinedStudentCourse> joined = new HashSet<JoinedStudentCourse>();

}

remember: @Embeddable class has its lifecycle bound to the owning entity class (Both Student and Course), so take care of it.

advice: Hibernate team suppports these two approachs (@OneToMany (skaffman's answer) or @CollectionsOfElements) due some limitations in @ManyToMany mapping - cascade operation.

regards,


The student_course table is there purely to record the association between the two entities. It is managed by hibernate, and can contain no other data.

The sort of data you want to record needs to be modelled as another entity. Perhaps you could a one-to-many association between Course and StudentResult (which contains the grade, etc), and then a many-to-one association between StdentResult and Student.


Drop the many-to-many, create a class called StudentCourseRelationship and set up one to manys on Student and Course to the StudentCourseRelationship.

You can put all sorts of things on it, like DateEnrolled, DateKickedOut etc. etc.

IMO the many-to-many mapping is a bit of a con.


The accepted answer unfortunately doesn't work for me, hibernate generates the join table in a weird way (all join columns are duplicated). However the variant with dedicated entity for the join table works fine. Here it is described in great detail: http://www.mkyong.com/hibernate/hibernate-many-to-many-example-join-table-extra-column-annotation/