R4N63RW4R
R4N63RW4R

Reputation: 41

Hibernate - ManyToMany using unique property of one of the mapped tables

Hibernate doesn't let me do a join table with a unique field "docket", no matter if I specify the "referencedColumnName = "docket"" (i thought the idea of this property was to tell Hibernate which field to use, in case it is not the primary key).

Database tables:

    student
---------------
  id (PK) | docket (UNIQUE)

  inscription
---------------
course_id | docket

inscription's PK is (course_id, docket)

    course
---------------
     id (PK)

The above problems raise with the following configuration:

On Student Entity:

@ManyToMany
@JoinTable(
            name="inscription",
            joinColumns=@JoinColumn(referencedColumnName = "docket", name="docket"),
            inverseJoinColumns=@JoinColumn(name="course_id", referencedColumnName = "id")
)
private List<Course> studentCourses;

On Course Entity:

@ManyToMany(mappedBy = "studentCourses")
private List<Student> students;

What causes the problem is that, when project is deployed, Hibernate executes the statement:

alter table public.inscription add constraint FKp625s5r1hmlggpgeq4x2nju91 foreign key (docket) references public.student

which is (of course) incorrect, as it is not specifying that docket is a unique field.

What it should be doing is:

alter table public.inscription add constraint FKp625s5r1hmlggpgeq4x2nju91 foreign key (docket) references public.student(docket)

but I don't know how can I tell it to do so.

Any help? Thanks in advance.

Upvotes: 1

Views: 1322

Answers (2)

R4N63RW4R
R4N63RW4R

Reputation: 41

Found the answer at the official documentation.

From JPA 2.0 documentation: http://download.oracle.com/otndocs/jcp/persistence-2.0-fr-oth-JSpec/:

11.1.21 JoinColumn Annotation

The JoinColumn annotation is used to specify a column for joining an entity association or element collection.

...

The name annotation element defines the name of the foreign key column. The remaining annotation elements (other than referencedColumnName) refer to this column and have the same semantics as for the Column annotation.

If the referencedColumnName element is missing, the foreign key is assumed to refer to the primary key of the referenced table.

Support for referenced columns that are not primary key columns of the referenced table is optional. Applications that use such mappings will not be portable.

So, perhaps, what was going on was that Hibernate does not have this feature implemented, as it is not mandatory.

What I did to fix it was to modify the inscription table, replacing each field by the corresponding primary key.

Upvotes: 2

ujulu
ujulu

Reputation: 3309

(i thought the idea of this property was to tell Hibernate which field to use, in case it is not the primary key)

Your assumption is in contradiction with the JPA 2.0 specification provided you are using Hibernate as an implementation of the JPA because the following extract states that you have to join on primary keys. It doesn't say anything about unique fields:

2.10.4 Bidirectional ManyToMany Relationships

Assuming that:

  • Entity A references a collection of Entity B.

  • Entity B references a collection of Entity A.

  • Entity A is the owner of the relationship.

The following mapping defaults apply:

  • Entity A is mapped to a table named A.
  • Entity B is mapped to a table named B.

There is a join table that is named A_B (owner name first). This join table has two foreign key columns. One foreign key column refers to table A and has the same type as the primary key of table A. The name of this foreign key column is formed as the concatenation of the following: the name of the relationship property or field of entity B; "_"; the name of the primary key column in table A.

The other foreign key column refers to table B and has the same type as the primary key of table B. The name of this foreign key column is formed as the concatenation of the following: the name of the relationship property or field of entity A; "_"; the name of the primary key column in table B.

(I added the format; the text is the original quotation from the specification.)

docket is not primary key in your case and therefore you cannot join on it.

Upvotes: 1

Related Questions