When defining your objects to be persisted and the relationships between them, it is often required
to define dependencies between these related objects. When persisting an object should we also persist
any related objects? What should happen to a related object when an object is deleted ?
Can the related object exist in its own right beyond the lifecycle of the other object, or should
it be deleted along with the other object ?
This behaviour can be defined with JPA and with DataNucleus. Lets take an example
@Entity
public class Owner
{
@OneToOne
private DrivingLicense license;
@OneToMany(mappedBy="owner")
private Collection cars;
...
}
@Entity
public class DrivingLicense
{
private String serialNumber;
...
}
@Entity
public class Car
{
private String registrationNumber;
@ManyToOne
private Owner owner;
...
}
So we have an
Owner
of a collection of vintage
Car
's, and the
Owner
has a
DrivingLicense
. We want to define lifecycle dependencies to match the relationships that we
have between these objects. So in our example what we are going to do is
-
When an object is persisted/updated its related objects are also persisted/updated.
-
When an
Owner
object is deleted, its
DrivingLicense
is deleted too (since it
cant exist without the person!
-
When an
Owner
object is deleted, the
Car
s continue to exist (since someone will
buy them)
-
When a
Car
object is deleted, the
Owner
continues to exist (unless he/she dies
in the Car, but that will be handled by a different mechanism in our application).
So we update our class to reflect this
@Entity
public class Owner
{
@OneToOne(cascade=CascadeType.ALL)
private DrivingLicense license;
@OneToMany(mappedBy="owner", cascade={CascadeType.PERSIST, CascadeType.MERGE})
private Collection cars;
...
}
@Entity
public class DrivingLicense
{
private String serialNumber;
...
}
@Entity
public class Car
{
private String registrationNumber;
@ManyToOne(cascade={CascadeType.PERSIST, CascadeType.MERGE})
private Owner owner;
...
}
So we make use of the
cascade
attribute of the relation annotations. We could express this
similarly in XML
<entity-mappings>
<entity class="mydomain.Owner">
<attributes>
<one-to-many name="cars">
<cascade>
<cascade-persist/>
<cascade-merge/>
</cascade>
</one-to-many>
<one-to-one name="license">
<cascade>
<cascade-all/>
</cascade>
</one-to-one>
...
</attributes>
</entity>
<entity class="mydomain.DrivingLicense">
...
</entity>
<entity class="mydomain.Car">
<attributes>
<many-to-one name="owner">
<cascade>
<cascade-persist/>
<cascade-merge/>
</cascade>
</many-to-one>
...
</attributes>
</entity>
</entity-mappings>
When an element is removed from a collection, or when a 1-1 relation is nulled, sometimes it is
desirable to delete the other object. JPA2 defines a facility of removing "orphans" by specifying
metadata for a 1-1 or 1-N relation. Let's take an example. In the above relation between
Owner
and
DrivingLicense
if we set the owners license field to null, this should
mean that the license is deleted. So we could change it to be
@Entity
public class Owner
{
@OneToOne(cascade={CascadeType.PERSIST, CascadeType.MERGE}, orphanRemoval=true)
private DrivingLicense license;
...
}
@Entity
public class DrivingLicense
{
private String serialNumber;
...
}
So from now on, if we delete the
Owner
we delete the
DrivingLicense
, and if we set
the
license
field of
DrivingLicense
to null then we also delete the
DrivingLicense
.