ManyToMany replationship in JPA

Defines a many-valued association with many-to-many multiplicity. If the Collection is defined using generics to specify the element type, the associated target entity class does not need to be specified; otherwise it must be specified.

Every many-to-many association has two sides, the owning side and the non-owning, or inverse, side. The join table is specified on the owning side. If the association is bidirectional, either side may be designated as the owning side.


All relationships in Java and JPA are unidirectional, in that if a source object references a target object there is no guarantee that the target object also has a relationship to the source object. This is different than a relational database, in which relationships are defined through foreign keys and querying such that the inverse query always exists.
JPA also defines a OneToMany relationship, which is similar to a ManyToMany relationship except that the inverse relationship (if it were defined) is a ManyToOne relationship. The main difference between a OneToMany and a ManyToMany relationship in JPA is that a ManyToMany always makes use of a intermediate relational join table to store the relationship, where as a OneToMany can either use a join table, or a foreign key in target object's table referencing the source object table's primary key.
In JPA a ManyToMany relationship is defined through the @ManyToMany annotation or the <many-to-many> element.
All ManyToMany relationships require a JoinTable. The JoinTable is defined using the @JoinTable annotation and <join-table> XML element. The JoinTable defines a foreign key to the source object's primary key (joinColumns), and a foreign key to the target object's primary key (inverseJoinColumns). Normally the primary key of the JoinTable is the combination of both foreign keys.

Example of a ManyToMany relationship database

EMPLOYEE (table)
E_IDFIRSTNAMELASTNAME





EMP_PROJ (table)
EMP_IDPROJ_ID




PROJECT (table)
P_IDNAME




Example of a ManyToMany relationship annotation

@Entity
public class Employee {
  @Id
  @Column(name="E_ID")
  private long id;
  ...
  @ManyToMany
  @JoinTable(
      name="EMP_PROJ",
      joinColumns={@JoinColumn(name="EMP_ID", referencedColumnName="E_ID")},
      inverseJoinColumns={@JoinColumn(name="PROJ_ID", referencedColumnName="P_ID")})
  private List<Project> projects;
  .....
}

Bi-directional Many to Many

Although a ManyToMany relationship is always bi-directional on the database, the object model can choose if it will be mapped in both directions, and in which direction it will be mapped in. If you choose to map the relationship in both directions, then one direction must be defined as the owner and the other must use the mappedBy attribute to define its mapping. This also avoids having to duplicate the JoinTable information in both places.
If the mappedBy is not used, then the persistence provider will assume there are two independent relationships, and you will end up getting duplicate rows inserted into the join table. If you have a conceptual bi-directional relationship, but have two different join tables in the database, then you must not use the mappedBy, as you need to maintain two independent tables.
As with all bi-directional relationships it is your object model's and application's responsibility to maintain the relationship in both direction. There is no magic in JPA, if you add or remove to one side of the collection, you must also add or remove from the other side. Technically the database will be updated correctly if you only add/remove from the owning side of the relationship, but then your object model will be out of synch, which can cause issues.

Example of an inverse ManyToMany relationship annotation

@Entity
public class Project {
  @Id
  @Column(name="P_ID")
  private long id;
  ...
  @ManyToMany(mappedBy="projects")
  private List<Employee> employees;
  ...
}

More examples:

Example 1:

    In Customer class:

    @ManyToMany
    @JoinTable(name="CUST_PHONES")
    public Set getPhones() { return phones; }

    In PhoneNumber class:

    @ManyToMany(mappedBy="phones")
    public Set getCustomers() { return customers; }

    Example 2:

    In Customer class:

    @ManyToMany(targetEntity=com.acme.PhoneNumber.class)
    public Set getPhones() { return phones; }

    In PhoneNumber class:

    @ManyToMany(targetEntity=com.acme.Customer.class, mappedBy="phones")
    public Set getCustomers() { return customers; }

    Example 3:

    In Customer class:

    @ManyToMany
    @JoinTable(name="CUST_PHONE",
        joinColumns=
            @JoinColumn(name="CUST_ID", referencedColumnName="ID"),
        inverseJoinColumns=
            @JoinColumn(name="PHONE_ID", referencedColumnName="ID")
        )
    public Set getPhones() { return phones; }

    In PhoneNumberClass:

    @ManyToMany(mappedBy="phones")
    public Set getCustomers() { return customers; }


Comments

Popular posts from this blog

How to get Active Transactions and Locks from MySQL

Example of a PAC file