Skip to main content

Entity Table

To enable logical deletion support for an entity, add a flag property annotated with org.babyfish.jimmer.sql.LogicalDeleted to indicate whether the data is normal or already deleted.

Once a logical deletion property is configured for an entity:

  • By default, when developers call APIs to delete an entity object, Jimmer will NOT actually delete the data with SQL delete statements. Instead, it will use update statements to set the logical deletion property of the entity to "already deleted".

    Other cases: Even if an entity has a logical deletion property, Jimmer also provides APIs for developers to forcibly truly delete objects by passing additional parameters.

  • By default, all SQL queries against the entity will be automatically appended with a where logicalDeleteFlag <> already deleted condition to create the illusion that some data has been deleted.

info

This doc only covers the mapping configuration of the logical deletion flag field. For how to use the logical deletion functionality, see Global Filters / Logical Deletion.

Usage

The logical deletion flag property can be one of the following types:

  • boolean: must be non-null
  • int: must be non-null
  • enum: must be non-null
  • long/Long:either null or non-null
  • UUID: either null or non-null
  • date: must be nullable
TypeCodeDeleted StateInitialized State
boolean
@LogicalDeleted("true")
boolean deleted();
truefalse
@LogicalDeleted("false")
val active: Boolean;
falsetrue
int
@Default("0")
@LogicalDeleted("1")
int state();
10
Enum
@Default("INITIALIZED")
@LogicalDeleted("DELETED")
State state();
DELETEDINITIALIZED

long

@LogicalDeleted
long deletedMillis();
Current milliseconds0L

Nullable Long

@LogicalDeleted
Long deletedMillis();
Current millisecondsnull

UUID

@LogicalDeleted
UUID deletedData();
Random UUIDUUID with all bytes as 0

Nullable UUID

@Nullable
@LogicalDeleted
UUID deletedData();
Random UUIDnull

Nullable LocalDateTime

@Nullable
@LogicalDeleted("now")
UUID deletedTime();
Current timenull
@Nullable
@LogicalDeleted("null")
UUID createdTime();
nullCurrent time

Where

  • ✩ in the first or second column indicates that the current configuration method supports multi-version data to be discussed in the next section.

    info

    Supporting logical deletion but not considering multi-version data issues is a less mature consideration. Therefore, it is recommended to use the logical deletion configuration that supports multi-version data.

  • Current milliseconds, the default behavior is System.currentMillis(), which is the behavior of the default org.babyfish.jimmer.sql.meta.LogicalDeletedLongGenerator.

    If this behavior is unsatisfactory, a custom class can be implemented that implements the LogicalDeletedValueGenerator<Long> interface, and configured with:

    • @LogicalDeleted(generatedType = YourGenerator.class)

    • @LogicalDeleted(generatedRef = YourGenerator.class), where generatorRef indicates the name of the object in the IOC container management framework

  • Random UUID, the default behavior is UUID.randomUUID(), which is the behavior of the default org.babyfish.jimmer.sql.meta.LogicalDeletedUUIDGenerator.

    If this behavior is unsatisfactory, a custom class can be implemented that implements the LogicalDeletedValueGenerator<UUID> interface, and configured with:

    • @LogicalDeleted(generatedType = YourGenerator.class)

    • @LogicalDeleted(generatedRef = YourGenerator.class), where generatorRef indicates the name of the object in the IOC container management framework

Multi-Version Data

Logical deletion does not actually delete data, it only hides the data. This means that data appears in multiple versions. This issue is also described in Key / Multi-version Support.

Take the example of long type logical deletion that supports multiple versions

@Entity  
public interface Book {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
long id();

@Key
String name();

@Key
int edition();

@LogicalDeleted
long deletedMillis();

BigDecimal price();

@ManyToOne
BookStore store();
}

Although the Key of the Book object is name and edition, because the deletedMillis property is the logical deletion flag, the non-primary key UNIQUE constraint at the database level should be:

alter table BOOK
add constraint uq_key_BOOK
unique(NAME, EDITION, DELETED_MILLIS);

If the table input is as follows:

IDNAMEEDITIONPRICESTORE_IDDELETED_MILLIS
1027SQL in Action149.99230
1026SQL in Action155.99221708796420956
1025SQL in Action147.99231708234681901
3131SQL in Action259.99230
3130SQL in Action253.99221708722582793
3129SQL in Action258.99231708664484823

There are 4 associated data records hidden, leaving only two valid data records:

IDNAMEEDITIONPRICESTORE_IDDELETED_MILLIS
1027SQL in Action149.99230
3131SQL in Action259.99230

Effects on Middle Tables

If an entity is logically deleted, what effect does it have on associations based on middle tables (using the @JoinTable annotation)?

  • If the middle table also supports logical deletion, that is, the logicalDeletedFilter of the @JoinTable annotation is specified, the middle table records related to the logically deleted entity will also be logically deleted.

    In [the next document] (./join-table), we will discuss in detail the logical deletion of middle tables.

  • If the deletedWhenEndpointIsLogicallyDeleted of the @JoinTable annotation is set to true, the middle table records related to the logically deleted entity will be physically deleted.

  • If neither of the above two conditions is met, the middle table records related to the logically deleted entity will not be processed at all.