diff --git a/documentation/src/test/java/org/hibernate/userguide/schema/CheckTest.java b/documentation/src/test/java/org/hibernate/userguide/schema/CheckTest.java index 8f740070b3..f16546666a 100644 --- a/documentation/src/test/java/org/hibernate/userguide/schema/CheckTest.java +++ b/documentation/src/test/java/org/hibernate/userguide/schema/CheckTest.java @@ -12,7 +12,8 @@ import jakarta.persistence.PersistenceException; import org.hibernate.annotations.Check; import org.hibernate.annotations.NaturalId; -import org.hibernate.dialect.PostgreSQL81Dialect; +import org.hibernate.dialect.H2Dialect; +import org.hibernate.dialect.PostgreSQLDialect; import org.hibernate.exception.ConstraintViolationException; import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase; @@ -26,7 +27,8 @@ import static org.junit.Assert.fail; /** * @author Vlad Mihalcea */ -@RequiresDialect(PostgreSQL81Dialect.class) +@RequiresDialect(PostgreSQLDialect.class) +@RequiresDialect(H2Dialect.class) public class CheckTest extends BaseEntityManagerFunctionalTestCase { @Override @@ -81,7 +83,6 @@ public class CheckTest extends BaseEntityManagerFunctionalTestCase { } @Entity(name = "Person") - @Check(constraints = "code > 0") public static class Person { @Id @@ -89,8 +90,7 @@ public class CheckTest extends BaseEntityManagerFunctionalTestCase { private String name; - // This one does not work! Only the entity-level annotation works. - // @Check(constraints = "code > 0") + @Check(constraints = "code > 0") private Long code; public Long getId() { diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/Check.java b/hibernate-core/src/main/java/org/hibernate/annotations/Check.java index 261e871ffa..71b19d6e56 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/Check.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/Check.java @@ -15,7 +15,11 @@ import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; /** - * Arbitrary SQL CHECK constraints which can be defined at the class, property or collection level. + * Specifies a {@code check} constraint to be included in the generated DDL. + *
+ * Only applies to secondary tables. */ FetchMode fetch() default FetchMode.JOIN; /** - * If true, Hibernate will not try to insert or update the properties defined by this join. - * - * Only applies to secondary tables + * If enabled, Hibernate will never insert or update the columns of the secondary table. + *
+ * Only applies to secondary tables. */ boolean inverse() default false; /** - * If enabled, Hibernate will insert a row only if the properties defined by this join are non-null - * and will always use an outer join to retrieve the properties. - * - * Only applies to secondary tables + * If enabled, Hibernate will insert a row only if the columns of the secondary table + * would not all be null, and will always use an outer join to read the columns. Thus, + * by default, Hibernate avoids creating a row of null values. + *
+ * Only applies to secondary tables. */ boolean optional() default true; /** * Defines a custom SQL insert statement. + *
+ * Only applies to secondary tables. * - * Only applies to secondary tables + * @see SQLInsert */ SQLInsert sqlInsert() default @SQLInsert(sql=""); /** * Defines a custom SQL update statement. + *
+ * Only applies to secondary tables. * - * Only applies to secondary tables + * @see SQLUpdate */ SQLUpdate sqlUpdate() default @SQLUpdate(sql=""); /** * Defines a custom SQL delete statement. + *
+ * Only applies to secondary tables. * - * Only applies to secondary tables + * @see SQLDelete */ SQLDelete sqlDelete() default @SQLDelete(sql=""); } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotatedColumn.java b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotatedColumn.java index 5c6e5f2ff0..3782cdf9ff 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotatedColumn.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotatedColumn.java @@ -11,6 +11,7 @@ import java.util.Map; import org.hibernate.AnnotationException; import org.hibernate.AssertionFailure; import org.hibernate.MappingException; +import org.hibernate.annotations.Check; import org.hibernate.annotations.ColumnDefault; import org.hibernate.annotations.GeneratedColumn; import org.hibernate.annotations.ColumnTransformer; @@ -73,6 +74,7 @@ public class AnnotatedColumn { private String generatedAs; private String comment; + private String checkConstraint; public void setTable(Table table) { this.table = table; @@ -193,10 +195,18 @@ public class AnnotatedColumn { return defaultValue; } + public String getCheckConstraint() { + return checkConstraint; + } + public void setDefaultValue(String defaultValue) { this.defaultValue = defaultValue; } + public void setCheckConstraint(String checkConstraint) { + this.checkConstraint = checkConstraint; + } + public String getComment() { return comment; } @@ -229,6 +239,9 @@ public class AnnotatedColumn { if ( defaultValue != null ) { mappingColumn.setDefaultValue( defaultValue ); } + if ( checkConstraint !=null ) { + mappingColumn.setCheckConstraint( checkConstraint ); + } if ( StringHelper.isNotEmpty( comment ) ) { mappingColumn.setComment( comment ); } @@ -266,6 +279,7 @@ public class AnnotatedColumn { this.mappingColumn.setNullable( nullable ); this.mappingColumn.setSqlType( sqlType ); this.mappingColumn.setUnique( unique ); + this.mappingColumn.setCheckConstraint( checkConstraint ); if ( writeExpression != null ) { final int numberOfJdbcParams = StringHelper.count( writeExpression, '?' ); @@ -645,6 +659,7 @@ public class AnnotatedColumn { column.setBuildingContext( context ); column.applyColumnDefault( inferredData, length ); column.applyGeneratedAs( inferredData, length ); + column.applyCheckConstraint( inferredData, length ); column.extractDataFromPropertyData(inferredData); column.bind(); columns[index] = column; @@ -685,7 +700,25 @@ public class AnnotatedColumn { } else { LOG.trace( - "Could not perform @ColumnGeneratedAlways lookup as 'PropertyData' did not give access to XProperty" + "Could not perform @GeneratedColumn lookup as 'PropertyData' did not give access to XProperty" + ); + } + } + + private void applyCheckConstraint(PropertyData inferredData, int length) { + final XProperty xProperty = inferredData.getProperty(); + if ( xProperty != null ) { + Check columnDefaultAnn = xProperty.getAnnotation( Check.class ); + if ( columnDefaultAnn != null ) { + if (length!=1) { + throw new MappingException("@Check may only be applied to single-column mappings (use a table-level @Check)"); + } + setCheckConstraint( columnDefaultAnn.constraints() ); + } + } + else { + LOG.trace( + "Could not perform @Check lookup as 'PropertyData' did not give access to XProperty" ); } } @@ -761,6 +794,7 @@ public class AnnotatedColumn { column.setImplicit( implicit ); column.applyColumnDefault( inferredData, 1 ); column.applyGeneratedAs( inferredData, 1 ); + column.applyCheckConstraint( inferredData, 1 ); column.extractDataFromPropertyData( inferredData ); column.bind(); diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotatedJoinColumn.java b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotatedJoinColumn.java index 7af1bf71b6..0741e63258 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotatedJoinColumn.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotatedJoinColumn.java @@ -894,18 +894,19 @@ public class AnnotatedJoinColumn extends AnnotatedColumn { * @param column the referenced column. */ public void overrideFromReferencedColumnIfNecessary(Column column) { - if (getMappingColumn() != null) { + Column mappingColumn = getMappingColumn(); + if (mappingColumn != null) { // columnDefinition can also be specified using @JoinColumn, hence we have to check // whether it is set or not if ( StringHelper.isEmpty( sqlType ) ) { sqlType = column.getSqlType(); - getMappingColumn().setSqlType( sqlType ); + mappingColumn.setSqlType( sqlType ); } // these properties can only be applied on the referenced column - we can just take them over - getMappingColumn().setLength(column.getLength()); - getMappingColumn().setPrecision(column.getPrecision()); - getMappingColumn().setScale(column.getScale()); + mappingColumn.setLength( column.getLength() ); + mappingColumn.setPrecision( column.getPrecision() ); + mappingColumn.setScale( column.getScale() ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/EntityBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/EntityBinder.java index 1210f9ea77..93fe2b15df 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/EntityBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/EntityBinder.java @@ -1230,6 +1230,9 @@ public class EntityBinder { if ( !BinderHelper.isEmptyAnnotationValue( table.comment() ) ) { hibTable.setComment( table.comment() ); } + if ( !BinderHelper.isEmptyAnnotationValue( table.checkConstraint() ) ) { + hibTable.addCheckConstraint( table.checkConstraint() ); + } TableBinder.addIndexes( hibTable, table.indexes(), context ); }