Skip to main content

Join Table

To enable logical deletion for the middle table, the property needs to be specified for the org.babyfish.jimmer.sql.JoinTable annotation to indicate whether the data is normal or has been deleted.

  • Once a logical deletion attribute is configured for the middle table, when any entity on either end is logically deleted, all related middle table records will be logically deleted.

  • All JOIN operations for the current association will be automatically added with the condition and logical deletion flag <> already deleted to give the illusion that some associations have been deleted.

Usage

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

  • boolean: must be non-null
  • int: must be non-null
  • enum: must be non-null
  • long/Long: can be null or non-null
  • UUID: must be non-null
  • Date: must be nullable
TypeCodeDeleted StateInitialized State
boolean
@ManyToMany
@JoinTable(
...Omit other arguments...,
logicalDeletedFilter =
@JoinTable.LogicalDeletedFilter(
columnName = "DELETED",
type = boolean.class,
value = "true"
)
)
List<Author> authors();
truefalse
@ManyToMany
@JoinTable(
...Omit other arguments...,
logicalDeletedFilter =
@JoinTable.LogicalDeletedFilter(
columnName = "ACTIVE",
type = boolean.class,
value = "false"
)
)
List<Author> authors();
falsetrue
int
@ManyToMany
@JoinTable(
...Omit other arguments...,
logicalDeletedFilter =
@JoinTable.LogicalDeletedFilter(
columnName = "STATE",
type = int.class,
value = "1",
intializedValue = "0"
)
)
List<Author> authors();
10
Enum
@ManyToMany
@JoinTable(
...Omit other arguments...,
logicalDeletedFilter =
@JoinTable.LogicalDeletedFilter(
columnName = "STATE",
type = State.class,
value = "DELETED",
intializedValue = "INITIALIZED"
)
)
List<Author> authors();
DELETEDINITIALIZED

long

@ManyToMany
@JoinTable(
...Omit other arguments...,
logicalDeletedFilter =
@JoinTable.LogicalDeletedFilter(
columnName = "DELETED_MILLIS",
type = long.class
)
)
List<Author> authors();
Current milliseconds0L

Nullable Long

@ManyToMany
@JoinTable(
...Omit other arguments...,
logicalDeletedFilter =
@JoinTable.LogicalDeletedFilter(
columnName = "DELETED_MILLIS",
type = Long.class,
nullable = true
)
)
List<Author> authors();
Current millisecondsnull

UUID

@ManyToMany
@JoinTable(
...Omit other arguments...,
logicalDeletedFilter =
@JoinTable.LogicalDeletedFilter(
columnName = "DELETED_DATA",
type = UUID.class
)
)
List<Author> authors();
Random UUIDUUID with all bytes as 0

Nullable UUID

@ManyToMany
@JoinTable(
...Omit other arguments...,
logicalDeletedFilter =
@JoinTable.LogicalDeletedFilter(
columnName = "DELETED_DATA",
type = UUID.class,
nullable = true
)
)
List<Author> authors();
Random UUIDnull

Nullable LocalDateTime

@ManyToMany
@JoinTable(
...Omit other arguments...,
logicalDeletedFilter =
@JoinTable.LogicalDeletedFilter(
columnName = "DELETED_TIME",
type = LocalDateTime.class,
nullable = true,
value = "now"
)
)
List<Author> authors();
Current Timenull
@ManyToMany
@JoinTable(
...Omit other arguments...,
logicalDeletedFilter =
@JoinTable.LogicalDeletedFilter(
columnName = "CREATED_TIME",
type = LocalDateTime.class,
nullable = true,
value = "null"
)
)
List<Author> authors();
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 without considering multi-version data issues is less mature. 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:

    • @JoinTable.LogicalDeletedFilter(generatedType = YourGenerator.class)

    • @JoinTable.LogicalDeletedFilter(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:

    • @JoinTable.LogicalDeletedFilter(generatedType = YourGenerator.class)

    • @JoinTable.LogicalDeletedFilter(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 it. This means that data appears in multiple versions.

Take the configuration that supports multi-version data as an example:

@ManyToMany
@JoinTable(
name = "BOOK_AUTHOR_MAPPING",
joinColumnName = "BOOK_ID",
inverseJoinColumnName = "AUTHOR_ID",
logicalDeletedFilter =
@JoinTable.LogicalDeletedFilter(
columnName = "DELETED_MILLIS",
type = long.class
)
)
List<Author> authors();

For example, the BOOK_AUTHOR_MAPPING table has three columns, all as part of the primary key

alter table BOOK_AUTHOR_MAPPING
add pk_BOOK_AUTHOR_MAPPING
primary key(
BOOK_ID,
AUTHOR_ID,
DELETED_MILLIS
);

If the table input is as follows:

BOOK_IDAUTHOR_IDDELETED_MILLIS
97230
97231708796420956
97231708234681901
249110
249111708722582793
249111708664484823

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

BOOK_IDAUTHOR_IDDELETED_MILLIS
97230
249110