Java Persistence/ManyToOne

ManyToOne edit

 

A ManyToOne relationship in Java is where the source object has an attribute that references another object, the target object. I.e. the rather typical Java case that one object holds a reference to another object. A ManyToOne relationship can be specified unidirectional. However, it is typical that the target object has the inverse relationship specified back to the source object. This would be a OneToMany relationship specification in the target object. 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.

In JPA a ManyToOne relationship is specified through the @ManyToOne annotation or the <many-to-one> element. A @ManyToOne annotation is typically accompanied by a @JoinColumn annotation. The @JoinColumn annotation specifies how the relationship should be mapped to (expressed in) the database. The @JoinColumn defines the name of the foreign key column (@JoinColumn(name = "...")) in the source object that should be used to find (join) the target object.

If the reverse OneToMany relationship is specified in the target object, then the @OneToMany annotation in the target object must contain a mappedBy attribute to define this inverse relation.

JPA also defines a OneToOne relationship, which is similar to a ManyToOne relationship, except that the inverse relationship (if it were defined) is a OneToOne relationship. The main difference between a OneToOne and a ManyToOne relationship in JPA is that a ManyToOne always contains a foreign key from the source object's table to the target object's table, whereas a OneToOne relationship the foreign key may either be in the source object's table or the target object's table.

Example of a ManyToOne relationship database edit

EMPLOYEE (table)

EMP_ID FIRSTNAME LASTNAME SALARY MANAGER_ID
1 Bob Way 50000 2
2 Sarah Smith 75000 null

PHONE (table)

ID TYPE AREA_CODE P_NUMBER OWNER_ID
1 home 613 792-0000 1
2 work 613 896-1234 1
3 work 416 123-4444 2

Example of a ManyToOne relationship annotations edit

@Entity
public class Phone {
  @Id
  private long id;
  ...
  // Specifies the PHONE table does not contain an owner column, but 
  // an OWNER_ID column with a foreign key. And creates a join to
  // lazily fetch the owner
  @ManyToOne(fetch=FetchType.LAZY)
  @JoinColumn(name="OWNER_ID")
  private Employee owner;
  ...
}

// Specification of the reverse OneToMany relationship in Employee
@Entity
public class Employee {
  @Id
  private long emp_id;
  ...
  // The 'mappedBy = "owner"' attribute specifies that
  // the 'private Employee owner;' field in Phone owns the
  // relationship (i.e. contains the foreign key for the query to
  // find all phones for an employee.)
  @OneToMany(mappedBy = "owner")
  private List<Phone> phones;
  ...

Example of a ManyToOne relationship XML edit

<entity name="Phone" class="org.acme.Phone" access="FIELD">
    <attributes>
        <id name="id"/>
        <many-to-one name="owner" fetch="LAZY">
            <join-column name="OWNER_ID"/>
        </many-to-one>
    </attributes>
</entity>

See Also edit

Common Problems edit

Foreign key is also part of the primary key. edit
See Primary Keys through OneToOne Relationships.
Foreign key is also mapped as a basic. edit
If you use the same field in two different mappings, you typically require to make one of them read-only using insertable, updatable = false.
See Target Foreign Keys, Primary Key Join Columns, Cascade Primary Keys.
Constraint error on insert. edit
This typically occurs because you have incorrectly mapped the foreign key in a OneToOne relationship.
See Target Foreign Keys, Primary Key Join Columns, Cascade Primary Keys.
It can also occur if your JPA provider does not support referential integrity, or does not resolve bi-directional constraints. In this case you may either need to remove the constraint, or use EntityManager flush() to ensure the order your objects are written in.
Foreign key value is null edit
Ensure you set the value of the object's OneToOne, if the OneToOne is part of a bi-directional OneToMany relationship, ensure you set the object's OneToOne when adding an object to the OneToMany, JPA does not maintain bi-directional relationships for you.
Also check that you defined the JoinColumn correctly, ensure you did not set insertable, updateable = false or use a PrimaryKeyJoinColumn.

Advanced edit

Target Foreign Keys, Primary Key Join Columns, Cascade Primary Keys edit

In complex data models it may be required to use a target foreign key, or read-only JoinColumn in mapping a ManyToOne if the foreign key/JoinColumn is shared with other ManyToOne or Basic mappings.

See, Target Foreign Keys, Primary Key Join Columns, Cascade Primary Keys