5.2.1.4.2. Related Entities Processing Policy
The platform offers a mechanism for managing related entities when deleting, which is largely similar to ON DELETE rules for database foreign keys. This mechanism works on the middle tier and uses @OnDelete, @OnDeleteInverse annotations on entity attributes.
@OnDelete annotation is processed when the entity in which this annotation is found is deleted, but not the one pointed to by this annotation (this is the main difference from cascade deletion at the database level).
@OnDeleteInverse annotation is processed when the entity which it points to is deleted (which is similar to cascade deletion at foreign key level in the database). This annotation is useful when the object being deleted has no attribute that can be checked before deletion. Typically, the object being checked has a reference to the object being deleted, and this is the attribute that should be annotated with @OnDeleteInverse.
Annotation value can be:
-
DeletePolicy.DENY– prohibits entity deletion, if the annotated attribute is notnullor not an empty collection. -
DeletePolicy.CASCADE– cascade deletion of the annotated attribute. -
DeletePolicy.UNLINK– disconnect the link with the annotated attribute. It is reasonable to disconnect the link only in the owner side of the association – the one with@JoinColumnannotation in the entity class.
Examples:
-
Prohibit deletion of entity with references:
DeletePolicyExceptionwill be thrown if you try to deleteCustomerinstance, which is referred to by at least oneOrder.Order.java@ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "CUSTOMER_ID") @OnDeleteInverse(DeletePolicy.DENY) protected Customer customer;Customer.java@OneToMany(mappedBy = "customer") protected List<Order> orders;Messages in the exception window can be localized in the main message pack. Use the following keys:
-
deletePolicy.caption- notification caption. -
deletePolicy.references.message- notification message. -
deletePolicy.caption.sales$Customer- notification caption for concrete entity. -
deletePolicy.references.message.sales$Customer- notification message for concrete entity.
-
-
Cascade deletion of related collection elements: deletion of
Roleinstance causes allPermissioninstances to be deleted as well.Role.java@OneToMany(mappedBy = "role") @OnDelete(DeletePolicy.CASCADE) protected Set<Permission> permissions;Permission.java@ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "ROLE_ID") protected Role role; -
Disconnect the links with related collection elements: deletion of
Roleinstance leads to setting to null references to thisRolefor allPermissioninstances included in the collection.Role.java@OneToMany(mappedBy = "role") protected Set<Permission> permissions;Permission.java@ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "ROLE_ID") @OnDeleteInverse(DeletePolicy.UNLINK) protected Role role;
Implementation notes:
-
Related entities policy is processed on Middleware when saving entities to the database.
-
Be careful when using
@OnDeleteInversetogether withCASCADEandUNLINKpolicies. During this process, all instances of the related objects are fetched from the database, modified and then saved.For example, if
@OnDeleteInverse(CASCADE)policy is set onJob.customerattribute in aCustomer–Jobassociation with many jobs to one customer, if you set@OnDeleteInverse(CASCADE)policy onJob.customerattribute, all jobs will be retrieved and modified when deleting a Customer instance. This may overload the application server or the database.On the other hand, using
@OnDeleteInverse(DENY)is safe, as it only involves counting the number of the related objects. If there are more than0, an exception is thrown. This makes use of@OnDeleteInverse(DENY)suitable forJob.customerattribute. -
The
UNLINKpolicy for one-to-many and many-to-many collection attributes is not supported:UnsupportedOperationExceptionwill be thrown if you try to delete an entity instance on the owner side of the association. For example, the following delete policy will not work:Owner.java@JoinTable(name = "SAMPLE_OWNER_SUBORDINATE_LINK", joinColumns = @JoinColumn(name = "OWNER_ID"), inverseJoinColumns = @JoinColumn(name = "SUBORDINATE_ID")) @OnDelete(DeletePolicy.UNLINK) @ManyToMany protected List<Subordinate> subordinate;