Search code examples
spring-boothibernatespring-data-jpaconstraintsmany-to-many

JPA @ForeignKey(value = ConstraintMode.NO_CONSTRAINT) not working with @ManyToMany


I have two entities with ManyToMany Relationship. Goal here is to create schema when application start with no foreign key

1). Job.java

package com.govjobportalbackend.entity;

import java.util.List;

import javax.persistence.Column;
import javax.persistence.ConstraintMode;
import javax.persistence.Entity;
import javax.persistence.ForeignKey;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name = "job")
public class Job extends BasicEntity {

    @Column(name = "icon")
    private String icon;

    @ManyToMany
    @JoinTable(
            name="job_city",
            joinColumns = @JoinColumn(name = "job_id"),
            inverseJoinColumns = @JoinColumn(name = "city_id"),
            foreignKey = @ForeignKey(value = ConstraintMode.NO_CONSTRAINT),
            inverseForeignKey = @ForeignKey(value = ConstraintMode.NO_CONSTRAINT)
    )
    private List<City> cities;

    public String getIcon() {
        return icon;
    }

    public void setIcon(String icon) {
        this.icon = icon;
    }

    public List<City> getCities() {
        return cities;
    }

    public void setCities(List<City> cities) {
        this.cities = cities;
    }

}

2). City.java

package com.govjobportalbackend.entity;

import java.util.List;

import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.ManyToMany;

@Entity
@DiscriminatorValue(value = "city")
public class City extends JobMetadata {

    @ManyToMany(mappedBy = "cities")
    private List<Job> jobs;

    @Override
    public List<Job> getJobs() {
        return jobs;
    }

    @Override
    public void setJobs(List<Job> jobs) {
        this.jobs = jobs;
    }
}

Below property is set in application.properties file

spring.jpa.hibernate.ddl-auto=update

When run the application, it is logging below SQLs in logs and is creating two foreign keys

Hibernate: create table job (id int4 not null, name varchar(255), icon varchar(255), primary key (id))
Hibernate: create table job_city (job_id int4 not null, city_id int4 not null)
Hibernate: create table job_metadata (type varchar(31) not null, id int4 not null, name varchar(255), primary key (id))
Hibernate: alter table if exists job_city add constraint FKiksm0d31mc3osxut4ciaf4uof foreign key (job_id) references job
Hibernate: alter table if exists job_city add constraint FKknw4pf63xt1tvnqrmrjrm5hqq foreign key (city_id) references job_metadata

If I annotate as per below in City.java then it works as expected but as per my "little" research, this bug is fixed in hibernate (so mapped entity is not required to be annotated with depreciated annotation), or may be I am wrong.

@ManyToMany(mappedBy = "cities")
@org.hibernate.annotations.ForeignKey(name = "none")
private List<Job> jobs;

Environment I am using is below;

  • Java 11
  • Hibernate 5.4.28.Final (spring-boot-starter-web)

Solution

  • As SimonMartinelli pointed out, this is most definitely a Hibernate bug. The version that worked for me was:

    @JoinTable(
                name="job_city",
                joinColumns = @JoinColumn(name = "job_id", foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT)),
                inverseJoinColumns = @JoinColumn(name = "city_id", foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT))
        )
    

    I found that the functionality breaks when you either (1) use @JoinTable.foreignKey instead, or (2) omit the name parameter.