Relationship Pair
Most often we can think of @OneToMany
and @ManyToOne
as
a pair representing 2 sides of a relationship. As such @OneToMany has the "many"
side of the relationship and @ManyToOne has the "one"
side of the relationship.
mappedBy
The mappedBy
attribute should be defined in most @OneToMany.
The mappedBy attribute effectively refers to the other side of the relationship.
Example: Customer has many Contacts
@Entity
public class Customer ...
// mappedBy referring to the other side of this relationship
@OneToMany(mappedBy="customer")
List<Contact> contacts;
...
On the other side of the relationship in the Contact entity bean we define the
@ManyToOne
property that the mappedBy
refers to.
@Entity
public class Contact ...
// the customer property referred to by @OneToMany(mappedBy="customer")
@ManyToOne(optional=false)
Customer customer;
...
Bi-directional
When we map both sides of the relationship with a @OneToMany
and @ManyToOne
pair we can describe this as a bi-directional relationship. The relationship can be viewed, navigated
and loaded from both directions.
There are no restrictions or limitations when we have a bi-directional relationship.
Not mapping the @OneToMany
The reason we might choose to not map the @OneToMany
side of a relationship is
when the cardinality is high (say thousands)
and we deem that we never want to
allow the application to navigate the relationship in that direction as doing so naively
might load too many of objects.
For example if a Customer had 1 million Orders and we naively navigated from that Customer to
all their orders we could load 1 millions Order instances into memory which is generally something
we don't want to do. In this case we could use filterMany
on a Customer query
to filter the orders for each customer (e.g. orders created in the last week). Alternatively we can
load the graph in the other direction (From Order to Customer).
Omitting a @OneToMany effectively means we can't navigate or load the relationship from that direction and instead it forces the application to always use the other direction (to build object graphs).
Not mapping the @ManyToOne
When we do not map the @ManyToOne this adds a restriction and implies an ownership relationship
.
For example take the case of Order
having many OrderDetail
. When we don't map
the @ManyToOne side in OrderDetail:
Order has details:
@Entity
@Table(name = "orders")
public class Order ...
// we MUST have cascade persist here for this
// unidirectional case (no @ManyToOne)
@OneToMany(cascade = CascadeType.ALL)
List<OrderDetail> details;
...
OrderDetail has no matching @ManyToOne:
@Entity
public class OrderDetail ...
// Does not have - @ManyToOne(optional = false) Order order;
This effectively adds the restriction that to insert new OrderDetails we must
cascade persist from Order to do so. That is, the @ManyToOne effectively represents
the foreign key column that is on the underlying table for OrderDetail and to populate
that foreign key column we must use cascade persist from Order
.
This also implies that the foreign key value can never change and hence we can view
this conceptually as an 'ownership' relationship
.
In this example each OrderDetail is 'owned' by an Order.
Personally I always map the @ManyToOne