51

I have been reading a lot about @JoinColumn but I still don't get the idea behind it.

Patient Table

CREATE TABLE patient (
patient_id BIGINT NOT NULL,
first_name VARCHAR(255) NOT NULL,
last_name VARCHAR(255) NOT NULL,
PRIMARY KEY(patient_id));

Vehicle Table

CREATE TABLE vehicles (
patient_id BIGINT NOT NULL,
vehicle_id BIGINT NOT NULL,
vehicle_manufacturer VARCHAR(255),
PRIMARY KEY (vehicle_id),
CONSTRAINT patienthasmanyvehicle FOREIGN KEY(patient_id) REFERENCES patient(patient_id));

Patient Class

@OneToMany(mappedBy = "patient")
    private Collection<Vehicle> patientVehicles = new ArrayList<Vehicle>();

Vehicle Class

@ManyToOne
@JoinColumn(name="patient_id")
private Patient patient;

I'm confused on how the Vehicle class part, what is the relationship between

Vehicle Class ---- Entity
@JoinColumn(name="patient_id") ---- annotation
private Patient patient ----field

Does it say; The Vehicle Entity has a Foreign Key to Patient entity named patient_id. Add the patient_id as a column in the Vehicle Entity table

Do the name parameter of the JoinColumn should always be a Foreign Key or Primary Key?

I have been reading this but I'm still confuse. JPA JoinColumn vs mappedBy

Community
  • 1
  • 1
zbryan
  • 805
  • 2
  • 12
  • 24

5 Answers5

72

A unidirectional association via a join table

@Entity
class Patient {

    @OneToMany
    private Collection<Vehicle> vehicles = new ArrayList<Vehicle>();

}

@Entity
class Vehicle {

}

A bidirectional association via a join table

@Entity
class Patient {

    @OneToMany
    private Collection<Vehicle> vehicles = new ArrayList<Vehicle>();

}

@Entity
class Vehicle {

    @ManyToOne(fetch = FetchType.LAZY)
    private Patient patient;

}

A unidirectional association via a foreign key

@Entity
class Patient {

    @OneToMany
    @JoinColumn
    private Collection<Vehicle> vehicles = new ArrayList<Vehicle>();

}

@Entity
class Vehicle {

}

A bidirectional association via a foreign key

@Entity
class Patient {

    @OneToMany(mappedBy = "patient")
    private Collection<Vehicle> vehicles = new ArrayList<Vehicle>();

}

@Entity
class Vehicle {

    @ManyToOne(fetch = FetchType.LAZY)
    private Patient patient;

}

We don't need to use @JoinColumn on the Vehicle side, Hibernate assumes it by default. Sometimes I use it just to stress it out (another case, when we want to specify a join column name).

    @Entity
    class Vehicle {
    
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn
        private Patient patient;
    
    }

A bidirectional association via a foreign key with a foreign column name specification

@Entity
class Patient {

    @OneToMany(mappedBy = "patient")
    private Collection<Vehicle> vehicles = new ArrayList<Vehicle>();

}

@Entity
class Vehicle {

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="patient_id")
    private Patient patient;

}

This is the basic starting point of using @JoinColumn.

To verify that the foreign key(patient_id in the Vehicle table) is really mapped in the patients table you can use @JoinColumn(nullable = false)

@Entity
class Vehicle {

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="patient_id", nullable = false)
    private Patient patient

}
v.ladynev
  • 19,275
  • 8
  • 46
  • 67
  • isn't there a implicit `@JoinColum` when you specify `@OneToMany`? I mean are An association via a join table, A unidirectional association via a foreign key more different than just a default coulmn name and manual coulmn name? – sql_dummy Feb 07 '18 at 10:26
  • @sql_dummy `@JoinColumn` is not used for a join table. I don't understand the second question. For the unidirectional and bidirectional associations you will have the same database schema. – v.ladynev Feb 07 '18 at 11:43
  • I mean is `@JoinColumn` not specified implicitly when I specify @OneToMany? I got this doubt because going through `Debug` file I see the feild has similar `binding` weather I explicitly use `@JoinColumn` or not. (I guess the answer to my question is most probably "no", but why is similar `binding`) – sql_dummy Feb 08 '18 at 07:04
  • can you please answer [here](https://stackoverflow.com/questions/48679668/hibernate-why-is-binding-for-a-field-similar-weather-explicit-joincolum-annota) – sql_dummy Feb 08 '18 at 07:19
  • @v.ladynev I have two Entity **Publisher** and **Book** and both of them have bidirectional association but the `@JoinColumn` is specified on `@OneToMany` side. What type of relation is this can you please answer Link: https://github.com/springframeworkguru/spring5webapp/tree/publisher-relationships/src/main/java/guru/springframework/spring5webapp/domain – Akki Apr 04 '20 at 09:33
  • @Akki I think that this is a bidirectional association. Better to use `mappedBy` in such situations. – v.ladynev Apr 04 '20 at 11:50
  • This answer is missing the table in which the join column will be found, answer given by [Yogesh](https://stackoverflow.com/a/59700281/4982691) – jumping_monkey Jun 08 '20 at 07:31
  • With the last case, can use the @ManyToOne unidirectional with JoinColumn ? – BeliliF Dec 07 '20 at 22:26
  • @BeliliF yes. Just add `@ManyToOne(fetch = FetchType.LAZY)` and `@JoinColumn(name = "fk_some_column")` – v.ladynev Dec 09 '20 at 10:50
  • @v.ladynev is it mandatory to set "fetch = FetchType.LAZY" for this to work – BeliliF Dec 09 '20 at 19:03
  • @BeliliF No. But my advice is to always do that. – v.ladynev Dec 10 '20 at 11:54
  • Amazing response here. Wondering what the benefit of bidirectional is with unidirectional though – Amir Apr 01 '21 at 09:49
  • @Amir For `OneToMany` always use bidirectional. You will not to load all the list just to delete an item. – v.ladynev Apr 01 '21 at 10:42
9

The join column is declared with the @JoinColumn annotation which looks like the @Column annotation. It has one more parameters named referencedColumnName. This parameter declares the column in the targeted entity that will be used to the join.

In a bidirectional relationship, one of the sides (and only one) has to be the owner: the owner is responsible for the association column(s) update. To declare a side as not responsible for the relationship, the attribute mappedBy is used. mappedBy refers to the property name of the association on the owner side.

Here is Sample code :

EntityOne : 
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "TEST_ID")
    private EntityTwo entityTwo;

EntityTwo : 
      // bi-directional many-to-one association to EntityOne Here TEST_ID is the Primary key
    @OneToMany(mappedBy = "entityTwo")
    private List<EntityOne> entityOne;
Lova Chittumuri
  • 2,994
  • 1
  • 30
  • 33
5

Vehicle Class ---- Entity @JoinColumn(name="patient_id") ---- annotation private Patient patient ----field

Above code will generate a column patient_id (a foreign key) in Vehicle class which will point to Patient Class primary key.

MappedBy - This attribute tells us that this relation will be managed by Vehicle class. Example. If we insert a vehicle, then two SQL will be injected if cascadetype is all/save. 1st SQL will inject details in Patient table and 2nd SQL will inject vehicle details in vehicle table with patient_id column of Vehicle column pointing to Patient tuple inserted.

Perkone
  • 57
  • 3
  • 8
Vishal nigam
  • 51
  • 1
  • 8
  • but why is that the **patient_id (generated column which is a FK)** in the **Vehicle Table** doesn't have any value when I run my code? – zbryan May 31 '16 at 10:06
  • @zenlloyd For a unidirectional association It is impossible. For a bidirectional It is normal. – v.ladynev May 31 '16 at 10:15
  • is there a way to verify that the foreign key(patient_id in Vehicle table) is really mapped in the patients table? – zbryan May 31 '16 at 10:18
  • 2
    @zenlloyd. To have patient object mapped properly, you need to make sure that you have patient attribute set in vehicle object. If this value is not set, then patient_id will be injected with null value. – Vishal nigam May 31 '16 at 11:51
1

The table in which join column will be found depends upon context.

  • If the join is for a OneToOne or ManyToOne mapping using a foreign key mapping strategy, the foreign key column is in the table of the source entity or embeddable.

  • If the join is for a unidirectional OneToMany mapping using a foreign key mapping strategy, the foreign key is in the table of the target entity.

  • If the join is for a ManyToMany mapping or for a OneToOne or bidirectional ManyToOne/OneToMany mapping using a join table, the foreign key is in a join table.

  • If the join is for an element collection, the foreign key is in a collection table.

Yogesh Sanchihar
  • 1,080
  • 18
  • 25
0

Why is that the patient_id (generated column which is a FK) in the Vehicle Table doesn't have any value when I run my code?

All @JoinColumn does is to specify a column for joining an entity association or element collection. Since you have made @JoinColumn associated with Patient class object, that's why foreign key is created on Patient table.

For more please refer https://docs.jboss.org/hibernate/jpa/2.1/api/javax/persistence/JoinColumn.html

v.ladynev
  • 19,275
  • 8
  • 46
  • 67
  • This statement: "Since you have made @JoinColumn associated with Patient class object, that's why foreign key is created on Patient table." is NOT correct. This is the reason: **"If the join is for a OneToOne or ManyToOne mapping using a foreign key mapping strategy, the foreign key column is in the table of the source entity or embeddable."** – jumping_monkey Jun 08 '20 at 07:25