Java Persistence/ManyToOne
ManyToOne
[edit | edit source]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 | edit source]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 | edit source]@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 | edit source]<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 | edit source]Common Problems
[edit | edit source]Foreign key is also part of the primary key.
[edit | edit source]Foreign key is also mapped as a basic.
[edit | edit source]- 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 | edit source]- This typically occurs because you have incorrectly mapped the foreign key in a
OneToOne
relationship.
- 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 | edit source]- Ensure you set the value of the object's
OneToOne
, if theOneToOne
is part of a bi-directionalOneToMany
relationship, ensure you set the object'sOneToOne
when adding an object to theOneToMany
, JPA does not maintain bi-directional relationships for you. - Also check that you defined the
JoinColumn
correctly, ensure you did not setinsertable, updateable = false
or use aPrimaryKeyJoinColumn
.
Advanced
[edit | edit source]Target Foreign Keys, Primary Key Join Columns, Cascade Primary Keys
[edit | edit source]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