In Which Case Do You Use the JPA @Jointable Annotation

In which case do you use the JPA @JoinTable annotation?

EDIT 2017-04-29: As pointed to by some of the commenters, the JoinTable example does not need the mappedBy annotation attribute. In fact, recent versions of Hibernate refuse to start up by printing the following error:

org.hibernate.AnnotationException: 
Associations marked as mappedBy must not define database mappings
like @JoinTable or @JoinColumn

Let's pretend that you have an entity named Project and another entity named Task and each project can have many tasks.

You can design the database schema for this scenario in two ways.

The first solution is to create a table named Project and another table named Task and add a foreign key column to the task table named project_id:

Project      Task
------- ----
id id
name name
project_id

This way, it will be possible to determine the project for each row in the task table. If you use this approach, in your entity classes you won't need a join table:

@Entity
public class Project {

@OneToMany(mappedBy = "project")
private Collection<Task> tasks;

}

@Entity
public class Task {

@ManyToOne
private Project project;

}

The other solution is to use a third table, e.g. Project_Tasks, and store the relationship between projects and tasks in that table:

Project      Task      Project_Tasks
------- ---- -------------
id id project_id
name name task_id

The Project_Tasks table is called a "Join Table". To implement this second solution in JPA you need to use the @JoinTable annotation. For example, in order to implement a uni-directional one-to-many association, we can define our entities as such:

Project entity:

@Entity
public class Project {

@Id
@GeneratedValue
private Long pid;

private String name;

@JoinTable
@OneToMany
private List<Task> tasks;

public Long getPid() {
return pid;
}

public void setPid(Long pid) {
this.pid = pid;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public List<Task> getTasks() {
return tasks;
}

public void setTasks(List<Task> tasks) {
this.tasks = tasks;
}
}

Task entity:

@Entity
public class Task {

@Id
@GeneratedValue
private Long tid;

private String name;

public Long getTid() {
return tid;
}

public void setTid(Long tid) {
this.tid = tid;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

}

This will create the following database structure:

ER Diagram 1

The @JoinTable annotation also lets you customize various aspects of the join table. For example, had we annotated the tasks property like this:

@JoinTable(
name = "MY_JT",
joinColumns = @JoinColumn(
name = "PROJ_ID",
referencedColumnName = "PID"
),
inverseJoinColumns = @JoinColumn(
name = "TASK_ID",
referencedColumnName = "TID"
)
)
@OneToMany
private List<Task> tasks;

The resulting database would have become:

ER Diagram 2

Finally, if you want to create a schema for a many-to-many association, using a join table is the only available solution.

When Should I Use @JoinColumn or @JoinTable with JPA?

Let's say you have an entity A which has a @ManyToOne association ot an entity B

@JoinColumn will define the target table Foreign Key (e.g B_ID) while using the target Entity table (e.g. B).

@Entity
public class A {

private Long id;

@ManyToOne
@JoinColumn(name="B_ID")
private B b;

}

@JoinTable will use a separate table to hold the relationship between A and B.

@Entity
public class A {

private Long id;

@ManyToOne
@JoinTable(
name = "A_B",
joinColumns = @JoinColumn(name = "B_ID"),
inverseJoinColumns = @JoinColumn(name = "A_ID")
)
private B b;

}

This time neither A nor B contain any Foreign Key, because there's a separate table (e.g. A_B) to hold the association between A and B.

JPA @JoinTable with extra join conditions

You can use @WhereJoinTable annotation. It applies to the association table

@OneToMany
@JoinTable(
name="Contract_Party",
joinColumns = {@JoinColumn(name="party_id",referencedColumnName="party_id")},
inverseJoinColumns = {@JoinColumn(name="contract_id", referencedColumnName="contract_id")}
}
@WhereJoinTable ( "ROLE = 'SIGNER' ")
private List<Contract> contracts;

Why would you use @JoinTable annotation instead of Unidirectional @OneToMany annotation within Java

Then he is clearly wrong, @JoinTable is definitely not necessary here and will introduce overhead in terms of memory (more data to store) and time complexity (another table to join).

You're right about that you only need @JoinColumn to map one-to-one and one-to-many relationships (and mappedBy on the other side if it should be bidirectional).

P.S.: I would consider going further with this course, as it seems to be flawed even with the very basics of jpa.

How to create join table with JPA annotations?

You definitely shouldn't create User_Group entity as it's more the underlying database representation than the object oriented one.

You can achieve the join table by defining something like:

@Entity
@Table(name="USERS", schema="ADMIN")
public class User implements Serializable {
//...

@ManyToOne
@JoinTable(name="USER_GROUP")
Group group;

@Entity
@Table(name="GROUPS", schema="ADMIN")
public class Group implements Serializable {
//...

@OneToMany(mappedBy="group")
Set<User> users;

Edit: If you want to explicitly set the names of the columns you could use @JoinColumn elements as shown below:

@ManyToOne
@JoinTable(name="USER_GROUP",
joinColumns = @JoinColumn(name = "userid",
referencedColumnName = "userid"),
inverseJoinColumns = @JoinColumn(name = "groupid",
referencedColumnName = "groupid"))
Group group;

Why is the @JoinTable annotation is always present along with the @OneToMany annotation

Try to understand owning side as the entity which knows of the other end of the association.

I am the owning entity if i'm able to reach the associated entity so i have informations which allow me to reach the associated entity.

The most used case is to put the foreign key on the many side of the association.
So if you have a relation between Project and Task and we 're telling that 1 Project can have many Tasks.
A project_id column will be add on Task table which will be the owning side of the relation because it held information (Project Fk) which allow it to reach Project Entity from Car.

When you're using @Jointable on OneToMany association you're designing a unidirectional association so car entity don't have anymore the information to reach associated User entity like in a bidirectional association.
This information is now kept by a join table which is in User entity so User entity become the owning side of the relation.

So to answer your question the owning side shifted to Projet because now you can't anymore reach a project from a task and the only way to have tasks associated to a project is to use the join table held by Project entity. So now It's project entity through its joinTable wich keep informations to retrieve the tasks associated to a project.
Hope it's clear.

JPA problem with @ManyToMany annotation using @JoinTable

This is expected behavior

@JoinTable(name = "users_roles", joinColumns = @JoinColumn(name = "id_user", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "id_role", referencedColumnName = "id"))

This tells that we are creating the new join table , which joins the two columns from 2 tables mapped id_user from User and id_role from role table

You can check

https://docs.jboss.org/hibernate/jpa/2.1/api/javax/persistence/JoinTable.html

I can't SELECT a schema that was created in @jointable annotation in jpa

JPQL like this would find all itineraries which have a flight

SELECT ti FROM TravellerItinerary ti JOIN ti.flights fl WHERE fl.id = :id

but then you don't post the related entity so to say more than that is not possible



Related Topics



Leave a reply



Submit