HHH-17164 - Proper, first-class soft-delete support

HHH-17311 - Reversed soft delete support

https://hibernate.atlassian.net/browse/HHH-17164
https://hibernate.atlassian.net/browse/HHH-17311
This commit is contained in:
Steve Ebersole 2023-10-25 15:29:13 -05:00
parent ae3c88ab66
commit 5b49d5efba
4 changed files with 71 additions and 54 deletions

View File

@ -23,7 +23,7 @@ Soft delete support is defined by 3 main parts -
1. The <<soft-delete-column,column>> which contains the indicator.
2. A <<soft-delete-conversion,conversion>> from `Boolean` indicator value to the proper database type
3. Whether to <<soft-delete-reverse,reverse>> the indicator values, tracking active/inactive instead
3. A <<soft-delete-type,strategy>> for interpreting the stored indicator values.
[[soft-delete-column]]
@ -31,8 +31,12 @@ Soft delete support is defined by 3 main parts -
The column where the indicator value is stored is defined using `@SoftDelete#columnName` attribute.
When using <<soft-delete-reverse,reversed>> mappings, the column name defaults to `active`; otherwise, it
defaults to the name `deleted`.
The default column name depends on the <<soft-delete-type,strategy>> being used -
ACTIVE::
The default column name is `active`.
DELETED::
The default column name is `deleted`.
See <<soft-delete-basic-example>> for an example of customizing the column name.
@ -42,11 +46,11 @@ Depending on the conversion type, an appropriate check constraint may be applied
[[soft-delete-conversion]]
==== Indicator conversion
The conversion is defined using a JPA <<basic-jpa-convert,AttributeConverter>>. The "domain type" is always
`boolean`. The "relational type" can be any type, as defined by the converter; generally `BOOLEAN`, `BIT`, `INTEGER` or `CHAR`.
The conversion is defined using a Jakarta Persistence <<basic-jpa-convert,AttributeConverter>>. The domain-type is always
`boolean`. The relational-type can be any type, as defined by the converter; generally `BOOLEAN`, `BIT`, `INTEGER` or `CHAR`.
An explicit conversion can be specified using `@SoftDelete#converter`. See <<soft-delete-basic-example>>
for an example of specifying an explicit conversion. Explicit conversions can specify a custom converter or leverage the 3
for an example of specifying an explicit conversion. Explicit conversions can specify a custom converter or leverage
Hibernate-provided converters for the 3 most common cases -
`NumericBooleanConverter`:: Defines conversion using `0` for `false` and `1` for `true`
@ -60,6 +64,8 @@ boolean (and bit):: the underlying type is boolean / bit and no conversion is ap
numeric:: the underlying type is integer and values are converted according to `NumericBooleanConverter`
character:: the underlying type is char and values are converted according to `TrueFalseConverter`
IMPORTANT: The converter should simply convert the `true` and `false`, irrespective of the <<soft-delete-type,strategy>> used. Hibernate will handle applying the strategy.
[[soft-delete-entity]]
==== Entity soft delete
@ -133,35 +139,17 @@ The `@SoftDelete` annotation may also be placed at the package level, in which c
entities and collections defined within the package.
[[soft-delete-reverse]]
==== Reversed soft delete
[[soft-delete-type]]
==== Strategy - SoftDeleteType
A common requirement in applications using soft delete is to track rows which are active as opposed to removed,
reversing the boolean value. For example:
Given truth values, there are 2 valid ways to interpret the values stored in the database. This
interpretation is defined by the SoftDeleteType enumeration and can be configured per-usage using
`@SoftDelete(..., strategy=ACTIVE)` or `@SoftDelete(..., strategy=DELETED)` -
[[soft-delete-reverse-example]]
.Reversed soft-delete
====
[source,java]
----
include::{testing-dir}/converter/reversed/TheEntity.java[tag=example-soft-delete-reverse, indent=0]
----
====
ACTIVE::
Tracks rows which are active. A `true` value in the database indicates that the row is active
(non-deleted); a `false` value indicates inactive (deleted).
DELETED::
Tracks rows which are deleted. A `true` value in the database indicates that the row is deleted;
a `false` value indicates that the row is non-deleted.
When an instance of `TheEntity` is persisted, the value `'Y'` will be inserted into the
`active` column. When an instance of `TheEntity` is removed, the column's value is updated to `'N'`.
This example explicitly specifies the built-in `YesNoConverter`, but reversal works with any conversion
even implicit conversions -
[[soft-delete-reverse-example-2]]
.Reversed soft-delete with implicit conversion
====
[source,java]
----
include::{testing-dir}/converter/reversed/TheEntity2.java[tag=example-soft-delete-reverse, indent=0]
----
====
The important thing to remember is that the stored values are reversed from the "normal" soft delete state.
`active == true` is the same as `deleted == false` - both describe the same state.

View File

@ -62,8 +62,7 @@ public @interface SoftDelete {
/**
* (Optional) The name of the column.
* <p/>
* Default depends on {@linkplain #trackActive()} - {@code deleted} if {@code false} and
* {@code active} if {@code true}.
* Default depends on the {@linkplain #strategy() strategy} being used.
*
* @see SoftDeleteType#getDefaultColumnName()
*/

View File

@ -19,20 +19,14 @@ earlier versions, see any other pertinent migration guides as well.
[[soft-delete]]
== Soft Delete
6.4 adds support for soft deletes against an entity's primary table and collection tables, using the
new `@SoftDelete` annotation.
[source,java]
----
@Entity
@SoftDelete
class Account {
...
}
----
6.4 adds support for soft deletes, using the new `@SoftDelete` annotation.
See the link:{userGuideBase}#soft-delete[User Guide] for details.
In previous versions, support for soft-deletes was somewhat implementable using
a combination of any or all of event-listeners, filters, `@Where`, etc.
Applications using such implementations are encouraged to switch.
[[custom-tenant-identifier-type]]
== Custom tenant identifier type

View File

@ -1,20 +1,56 @@
:family: 6.3
:version: 6.3.0.Final
= Hibernate {version}
Steve Ebersole
:awestruct-tags: ["Hibernate ORM", "Releases"]
:awestruct-layout: blog-post
:version: 6.4.0.CR1
:family: 6.4
:docs-url: https://docs.jboss.org/hibernate/orm/{family}
:javadocs-url: {docs-url}/javadocs
:migration-guide-url: {docs-url}/migration-guide/migration-guide.html
:intro-guide-url: {docs-url}/introduction/html_single/Hibernate_Introduction.html
:user-guide-url: {docs-url}/userguide/html_single/Hibernate_User_Guide.html
// Text ...
6.4 adds some cool new features, in addition to many improvements and fixes.
[[soft-delete]]
== Soft Delete
== Conclusion
6.4 adds support for soft deletes using the new `@SoftDelete` annotation.
[source,java]
----
@Entity
@SoftDelete
class Account {
...
}
----
Dealing with values as deleted/non-deleted versus active/inactive (reversed) is simple using an annotation attribute:
This has the ability to easily handle active v. deleted tracking using a simple annotation attribute:
[source,java]
----
@Entity
@SoftDelete(strategy=ACTIVE)
class Account {
...
}
----
It even supports pluggable converters for storing the indicator value into the database.strategy
See the link:{userGuideBase}#soft-delete[User Guide] for details.
== Finally,
For additional details, see: