Add soft-delete module: @SoftDelete (DELETED/ACTIVE/TIMESTAMP) vs @SQLDelete + @SQLRestriction on Hibernate 7.4.14.Final, H2 and PostgreSQL 17

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_017ic4b7rnC7jppGGdHGESvy
This commit is contained in:
2026-10-28 18:22:03 +00:00
co-authored by Claude Sonnet 5.5
parent aea104f021
commit c9faf35e61
43 changed files with 2084 additions and 0 deletions
+107
View File
@@ -0,0 +1,107 @@
DDL and generated SQL: DELETED vs ACTIVE vs TIMESTAMP vs @SQLDelete
######## H2 ########
database: H2Dialect / H2 2.4.240 (2025-09-22)
== DDL Hibernate generates
create table article_active (active boolean not null, id bigint generated by default as identity, title varchar(255), primary key (id));
create table article_deleted (deleted boolean not null, id bigint generated by default as identity, title varchar(255), primary key (id));
create table article_manual (deleted boolean not null, id bigint generated by default as identity, title varchar(255), primary key (id));
create table article_stamped (deleted_at timestamp(6) with time zone, id bigint generated by default as identity, title varchar(255), primary key (id));
== SoftDeleteType.DELETED (default)
-- insert
sql> insert into article_deleted (title,deleted,id) values (?,false,default)
-- remove(first)
sql> select ad1_0.id,ad1_0.title from article_deleted ad1_0 where ad1_0.deleted=false and ad1_0.id=?
sql> update article_deleted set deleted=true where id=? and deleted=false
raw rows : [1 | first | true, 2 | second | false]
-- find(first) after delete -> null
sql> select ad1_0.id,ad1_0.title from article_deleted ad1_0 where ad1_0.deleted=false and ad1_0.id=?
-- HQL: select count(a) from ArticleDeleted a
sql> select count(ad1_0.id) from article_deleted ad1_0 where ad1_0.deleted=false
== SoftDeleteType.ACTIVE
-- remove(x)
sql> select aa1_0.id,aa1_0.title from article_active aa1_0 where aa1_0.active=true and aa1_0.id=?
sql> update article_active set active=false where id=? and active=true
raw rows : [1 | x | false]
== SoftDeleteType.TIMESTAMP
before delete: [1 | y | false]
-- insert
sql> insert into article_stamped (title,deleted_at,id) values (?,null,default)
-- remove(y)
sql> select as1_0.id,as1_0.title from article_stamped as1_0 where as1_0.deleted_at is null and as1_0.id=?
sql> update article_stamped set deleted_at=localtimestamp where id=? and deleted_at is null
after delete : [1 | y | true, 2 | z | false]
-- find(y) after delete -> null
sql> select as1_0.id,as1_0.title from article_stamped as1_0 where as1_0.deleted_at is null and as1_0.id=?
== @SQLDelete + @SQLRestriction
-- insert
sql> insert into article_manual (deleted,title,id) values (?,?,default)
-- remove(m)
sql> select am1_0.id,am1_0.deleted,am1_0.title from article_manual am1_0 where am1_0.id=? and (am1_0.deleted = false)
sql> update article_manual set deleted = true where id = ?
raw rows : [1 | m | true, 2 | n | false]
-- find(m) after delete -> null
sql> select am1_0.id,am1_0.deleted,am1_0.title from article_manual am1_0 where am1_0.id=? and (am1_0.deleted = false)
== Deleting a row somebody else already soft-deleted
-- s1.flush()
sql> update article_deleted set deleted=true where id=? and deleted=false
flush failed: OptimisticLockException -> StaleStateException: Unexpected row count (expected row count 1 but was 0) [update article_deleted set deleted=true where id=? and deleted=false]
######## POSTGRES ########
database: PostgreSQLDialect / PostgreSQL 17.11
== DDL Hibernate generates
create table article_active (active boolean not null, id bigint generated by default as identity, title varchar(255), primary key (id));
create table article_deleted (deleted boolean not null, id bigint generated by default as identity, title varchar(255), primary key (id));
create table article_manual (deleted boolean not null, id bigint generated by default as identity, title varchar(255), primary key (id));
create table article_stamped (deleted_at timestamp(6) with time zone, id bigint generated by default as identity, title varchar(255), primary key (id));
== SoftDeleteType.DELETED (default)
-- insert
sql> insert into article_deleted (title,deleted) values (?,false)
-- remove(first)
sql> select ad1_0.id,ad1_0.title from article_deleted ad1_0 where ad1_0.deleted=false and ad1_0.id=?
sql> update article_deleted set deleted=true where id=? and deleted=false
raw rows : [1 | first | true, 2 | second | false]
-- find(first) after delete -> null
sql> select ad1_0.id,ad1_0.title from article_deleted ad1_0 where ad1_0.deleted=false and ad1_0.id=?
-- HQL: select count(a) from ArticleDeleted a
sql> select count(ad1_0.id) from article_deleted ad1_0 where ad1_0.deleted=false
== SoftDeleteType.ACTIVE
-- remove(x)
sql> select aa1_0.id,aa1_0.title from article_active aa1_0 where aa1_0.active=true and aa1_0.id=?
sql> update article_active set active=false where id=? and active=true
raw rows : [1 | x | false]
== SoftDeleteType.TIMESTAMP
before delete: [1 | y | false]
-- insert
sql> insert into article_stamped (title,deleted_at) values (?,null)
-- remove(y)
sql> select as1_0.id,as1_0.title from article_stamped as1_0 where as1_0.deleted_at is null and as1_0.id=?
sql> update article_stamped set deleted_at=localtimestamp where id=? and deleted_at is null
after delete : [1 | y | true, 2 | z | false]
-- find(y) after delete -> null
sql> select as1_0.id,as1_0.title from article_stamped as1_0 where as1_0.deleted_at is null and as1_0.id=?
== @SQLDelete + @SQLRestriction
-- insert
sql> insert into article_manual (deleted,title) values (?,?)
-- remove(m)
sql> select am1_0.id,am1_0.deleted,am1_0.title from article_manual am1_0 where am1_0.id=? and (am1_0.deleted = false)
sql> update article_manual set deleted = true where id = ?
raw rows : [1 | m | true, 2 | n | false]
-- find(m) after delete -> null
sql> select am1_0.id,am1_0.deleted,am1_0.title from article_manual am1_0 where am1_0.id=? and (am1_0.deleted = false)
== Deleting a row somebody else already soft-deleted
-- s1.flush()
sql> update article_deleted set deleted=true where id=? and deleted=false
flush failed: OptimisticLockException -> StaleStateException: Unexpected row count (expected row count 1 but was 0) [update article_deleted set deleted=true where id=? and deleted=false]