Skip to main content

OnDissociate

Concepts

@org.babyfish.jimmer.sql.OnDissociate is used together with Modification/Save Command and Modification/Delete Command

  • Modification/Save Command

    Existing data structure in databaseData structure expected to be saved by user
    +-BookStore(id=2)
    |
    +-----Book(id=10)
    |
    +-----Book(id=11)
    |
    \-----Book(id=12)


    +-BookStore(id=2)
    |
    +-----Book(id=10)
    |
    |
    |
    |
    |
    \-----Book(id=9)

    This means:

    • The association between BookStore-2 and Book-10 remains unchanged

    • The association between BookStore-2 and Book-9 needs to be created

    • BookStore-2 needs to be disassociated from Book-11 and Book-12.

  • Modification/Delete Command

    This is easy to understand. Child objects need to be disassociated before deleting the parent object.

@OnDissociate can only be used on foreign key based many-to-one associations, for example:

Book.java
@Entity
public interface Book {

@Null
@ManyToOne
@OnDissociate(DissociateAction.SET_NULL)
BookStore store();
...
}
info

Although disassociation of child objects is caused by a one-to-many association (or inverse one-to-one) (that is, the parent object abandons some child objects. The one-to-many association here is BookStore.books), the disassociation mode is configured for the inverse many-to-one association (here Book.store). This design is to maintain similarity with configuring cascade properties of foreign keys in database DDLs.

For Jimmer, a one-to-many association must be bidirectional, so the many-to-one association that is the mirror image of a known one-to-many association is always known. So there is no problem with this design.

Dissociation Modes

The parameter of the OnDissociate annotation in the above code is called the dissociation mode:

There are 5 modes for child object dissociation operations

ModeDescription

NONE (Default)

Depends on global configuration jimmer.default-dissociate-action-checking

LAX

Dissociation operation performs no action.

  • If the foreign key is real (see Real and Fake Foreign Keys), when parent object is deleted:

    • If cascade delete behavior is configured for the database foreign key (on cascade set null or on delete delete), database automatically clears the foreign key of dissociated child objects or automatically deletes the dissociated child objects

      Although database-level cascade modification performs better than ORM-level cascade modification, the ORM is unaware of this. Use with caution in projects requiring cache consistency

    • Otherwise, database reports an error and the save command is terminated

  • If the foreign key is fake (see Real and Fake Foreign Keys), when parent object is deleted, no additional behavior occurs, allowing dangling issues with child object foreign key values

    Even if fake foreign key values are invalid dangling values, jimmer queries won't error - the query system will return null for parent objects rather than error due to non-existent parent

CHECKDoes not support dissociation operations. Throws exception to prevent operation if current parent object in database has child objects that need to be dissociated.
SET_NULLSets the foreign key of dissociated child objects to null. This mode requires that the child object's foreign key property is nullable; otherwise attempting this configuration will cause an exception.
DELETEDeletes the dissociated child objects.

This article only introduces the configuration of OnDissociate. For how to use it further, please refer to Save Command/Dissociation Operations and Delete Commands.

Dynamic Overrides

Configuration specified by the annotation @OnDissociate is called static configuration.

Sometimes, different businesses may have different requirements for dissociation operations. Therefore, dissociation configurations can be dynamically overridden at runtime.

  • Modification/Save Command

    sqlClient
    .getEntities()
    .saveCommand(book)
    .setDissociateAction(BookProps.STORE, DissociateAction.SET_NULL)
    .execute();
  • Modification/Delete Command

    DeleteResult result = sqlClient
    .getEntities()
    .deleteCommand(BookStore.class, 1L)
    .configure(it ->
    it
    .setDissociateAction(
    BookProps.STORE,
    DissociateAction.SET_NULL
    )
    )
    .execute();