From 70c8ea03bb945cd93ad731dbc58878acba42704f Mon Sep 17 00:00:00 2001 From: Marco Belladelli Date: Tue, 5 Dec 2023 12:50:37 +0100 Subject: [PATCH] HHH-17461 Include soft-delete column in duplication check --- .../hibernate/mapping/PersistentClass.java | 3 + .../SoftDeleteMappedColumnTest.java | 120 ++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/softdelete/SoftDeleteMappedColumnTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/PersistentClass.java b/hibernate-core/src/main/java/org/hibernate/mapping/PersistentClass.java index 0008092a4b..331c18c385 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/PersistentClass.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/PersistentClass.java @@ -932,6 +932,9 @@ public abstract class PersistentClass implements IdentifiableTypeClass, Attribut if ( isDiscriminatorInsertable() && getDiscriminator() != null ) { getDiscriminator().checkColumnDuplication( cols, owner ); } + if ( getRootClass().getSoftDeleteColumn() != null ) { + getRootClass().getSoftDeleteColumn().getValue().checkColumnDuplication( cols, owner ); + } checkPropertyColumnDuplication( cols, getNonDuplicatedProperties(), owner ); for ( Join join : getJoins() ) { cols.clear(); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/softdelete/SoftDeleteMappedColumnTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/softdelete/SoftDeleteMappedColumnTest.java new file mode 100644 index 0000000000..d4c1c08cff --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/softdelete/SoftDeleteMappedColumnTest.java @@ -0,0 +1,120 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.orm.test.softdelete; + +import org.hibernate.MappingException; +import org.hibernate.SessionFactory; +import org.hibernate.annotations.SoftDelete; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cfg.Configuration; +import org.hibernate.tool.schema.Action; + +import org.hibernate.testing.orm.junit.Jira; +import org.hibernate.testing.util.ServiceRegistryUtil; +import org.junit.jupiter.api.Test; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.fail; + +/** + * @author Marco Belladelli + */ +@Jira( "https://hibernate.atlassian.net/browse/HHH-17461" ) +public class SoftDeleteMappedColumnTest { + @Test + public void testValid() { + try (final SessionFactory sf = buildSessionFactory( ValidEntity.class )) { + sf.inTransaction( session -> { + final ValidEntity validEntity = new ValidEntity( 1L, "valid1" ); + session.persist( validEntity ); + session.flush(); + assertThat( validEntity.isDeleted() ).isFalse(); + session.remove( validEntity ); + } ); + sf.inSession( session -> assertThat( session.find( ValidEntity.class, 1L ) ).isNull() ); + } + } + + @Test + public void testInvalid() { + try (final SessionFactory sf = buildSessionFactory( InvalidEntity.class )) { + sf.inTransaction( session -> { + final InvalidEntity entity = new InvalidEntity( 2L, "invalid2" ); + session.persist( entity ); + } ); + fail( "Duplicate soft-delete column should fail" ); + } + catch (Exception e) { + assertThat( e ).isInstanceOf( MappingException.class ); + assertThat( e.getMessage() ).contains( "Column 'is_deleted' is duplicated" ); + } + } + + private SessionFactory buildSessionFactory(Class entityClass) { + final Configuration cfg = new Configuration() + .setProperty( AvailableSettings.JAKARTA_HBM2DDL_DATABASE_ACTION, Action.ACTION_CREATE_THEN_DROP ) + .addAnnotatedClass( entityClass ); + ServiceRegistryUtil.applySettings( cfg.getStandardServiceRegistryBuilder() ); + return cfg.buildSessionFactory(); + } + + @Entity( name = "ValidEntity" ) + @SoftDelete( columnName = "is_deleted" ) + public static class ValidEntity { + @Id + private Long id; + + private String name; + + @Column( name = "is_deleted", insertable = false, updatable = false ) + private boolean deleted; + + public ValidEntity() { + } + + public ValidEntity(Long id, String name) { + this.id = id; + this.name = name; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public boolean isDeleted() { + return deleted; + } + } + + @Entity( name = "InvalidEntity" ) + @SoftDelete( columnName = "is_deleted" ) + public static class InvalidEntity { + @Id + private Long id; + + private String name; + + @Column( name = "is_deleted" ) + private boolean deleted; + + public InvalidEntity() { + } + + public InvalidEntity(Long id, String name) { + this.id = id; + this.name = name; + } + } +}