automatically detect when a @Check refers to a @SecondaryTable
- also support named check constraints (multiple of them) - also support check constraints on collection tables
This commit is contained in:
parent
abb89a32b1
commit
1657c22aca
|
@ -6,10 +6,12 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.userguide.schema;
|
package org.hibernate.userguide.schema;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
import jakarta.persistence.PersistenceException;
|
import jakarta.persistence.PersistenceException;
|
||||||
|
|
||||||
|
import jakarta.persistence.SecondaryTable;
|
||||||
import org.hibernate.annotations.Check;
|
import org.hibernate.annotations.Check;
|
||||||
import org.hibernate.annotations.NaturalId;
|
import org.hibernate.annotations.NaturalId;
|
||||||
import org.hibernate.dialect.H2Dialect;
|
import org.hibernate.dialect.H2Dialect;
|
||||||
|
@ -20,6 +22,8 @@ import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase;
|
||||||
import org.hibernate.testing.RequiresDialect;
|
import org.hibernate.testing.RequiresDialect;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
@ -120,7 +124,9 @@ public class CheckTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
|
|
||||||
//tag::schema-generation-database-checks-example[]
|
//tag::schema-generation-database-checks-example[]
|
||||||
@Entity(name = "Book")
|
@Entity(name = "Book")
|
||||||
@Check(constraints = "CASE WHEN isbn IS NOT NULL THEN LENGTH(isbn) = 13 ELSE true END")
|
@Check(name = "ValidIsbn", constraints = "CASE WHEN isbn IS NOT NULL THEN LENGTH(isbn) = 13 ELSE true END")
|
||||||
|
@SecondaryTable(name = "BookEdition")
|
||||||
|
@Check(name = "PositiveEdition", constraints = "edition > 0")
|
||||||
public static class Book {
|
public static class Book {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
|
@ -133,6 +139,12 @@ public class CheckTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
|
|
||||||
private Double price;
|
private Double price;
|
||||||
|
|
||||||
|
@Column(table = "BookEdition")
|
||||||
|
private int edition = 1;
|
||||||
|
|
||||||
|
@Column(table = "BookEdition")
|
||||||
|
private LocalDate editionDate;
|
||||||
|
|
||||||
//Getters and setters omitted for brevity
|
//Getters and setters omitted for brevity
|
||||||
|
|
||||||
//end::schema-generation-database-checks-example[]
|
//end::schema-generation-database-checks-example[]
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.annotations;
|
package org.hibernate.annotations;
|
||||||
|
|
||||||
|
import java.lang.annotation.Repeatable;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@ -17,8 +18,19 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
/**
|
/**
|
||||||
* Specifies a {@code check} constraint to be included in the generated DDL.
|
* Specifies a {@code check} constraint to be included in the generated DDL.
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>When a field or property is annotated, the check constraint is added to the column definition.
|
* <li>When a basic-typed field or property is annotated, the check constraint is
|
||||||
* <li>When an entity class is annotated, the check constraint is added to the primary table.
|
* added to the {@linkplain jakarta.persistence.Column column} definition.
|
||||||
|
* <li>When a {@link jakarta.persistence.ManyToOne} association is annotated, the
|
||||||
|
* check constraint is added to the {@linkplain jakarta.persistence.JoinColumn
|
||||||
|
* join column} definition.
|
||||||
|
* <li>When an owned collection is annotated, the check constraint is added to the
|
||||||
|
* {@linkplain jakarta.persistence.CollectionTable collection table} or
|
||||||
|
* {@linkplain jakarta.persistence.JoinTable association join table}.
|
||||||
|
* <li>When an entity class is annotated, the check constraint is added to either
|
||||||
|
* the {@linkplain jakarta.persistence.Table primary table} or to a
|
||||||
|
* {@linkplain jakarta.persistence.SecondaryTable secondary table}, depending
|
||||||
|
* on which columns are involved in the constraint expression specified by
|
||||||
|
* {@link #constraints()}.
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @author Emmanuel Bernard
|
* @author Emmanuel Bernard
|
||||||
|
@ -27,7 +39,12 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
*/
|
*/
|
||||||
@Target({TYPE, METHOD, FIELD})
|
@Target({TYPE, METHOD, FIELD})
|
||||||
@Retention(RUNTIME)
|
@Retention(RUNTIME)
|
||||||
|
@Repeatable(Checks.class)
|
||||||
public @interface Check {
|
public @interface Check {
|
||||||
|
/**
|
||||||
|
* The optional name of the check constraint.
|
||||||
|
*/
|
||||||
|
String name() default "";
|
||||||
/**
|
/**
|
||||||
* The check constraint, written in native SQL.
|
* The check constraint, written in native SQL.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* 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.annotations;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import static java.lang.annotation.ElementType.TYPE;
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of {@link Check}s.
|
||||||
|
*/
|
||||||
|
@Target(TYPE)
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
public @interface Checks {
|
||||||
|
Check[] value();
|
||||||
|
}
|
|
@ -22,10 +22,16 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
*
|
*
|
||||||
* @see jakarta.persistence.Table
|
* @see jakarta.persistence.Table
|
||||||
* @see jakarta.persistence.SecondaryTable
|
* @see jakarta.persistence.SecondaryTable
|
||||||
|
*
|
||||||
|
* @deprecated The options available here are all now offered by other newer and better-designed
|
||||||
|
* annotations in this package. This annotation will soon be removed, since it's very
|
||||||
|
* annoying to have two annotations named {@code @Table}.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
@Target(TYPE)
|
@Target(TYPE)
|
||||||
@Retention(RUNTIME)
|
@Retention(RUNTIME)
|
||||||
@Repeatable(Tables.class)
|
@Repeatable(Tables.class)
|
||||||
|
@Deprecated(since = "6.2", forRemoval = true)
|
||||||
public @interface Table {
|
public @interface Table {
|
||||||
/**
|
/**
|
||||||
* The name of the targeted table.
|
* The name of the targeted table.
|
||||||
|
@ -43,11 +49,10 @@ public @interface Table {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A check constraint, written in native SQL.
|
* A check constraint, written in native SQL.
|
||||||
* <p>
|
|
||||||
* <em>Useful for secondary tables, otherwise use {@link Check}.</em>
|
|
||||||
*
|
*
|
||||||
* @see Check
|
* @deprecated use {@link Check}.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated(since = "6.2")
|
||||||
String checkConstraint() default "";
|
String checkConstraint() default "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -61,6 +66,7 @@ public @interface Table {
|
||||||
/**
|
/**
|
||||||
* Specifies a foreign key of a secondary table, which points back to the primary table.
|
* Specifies a foreign key of a secondary table, which points back to the primary table.
|
||||||
*
|
*
|
||||||
|
* @apiNote Only relevant to secondary tables
|
||||||
* @deprecated use {@link jakarta.persistence.SecondaryTable#foreignKey()}
|
* @deprecated use {@link jakarta.persistence.SecondaryTable#foreignKey()}
|
||||||
*/
|
*/
|
||||||
@Deprecated(since = "6.0", forRemoval = true)
|
@Deprecated(since = "6.0", forRemoval = true)
|
||||||
|
@ -74,9 +80,8 @@ public @interface Table {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If enabled, Hibernate will never insert or update the columns of the secondary table.
|
* If enabled, Hibernate will never insert or update the columns of the secondary table.
|
||||||
* <p>
|
|
||||||
* <em>Only applies to secondary tables.</em>
|
|
||||||
*
|
*
|
||||||
|
* @apiNote Only relevant to secondary tables
|
||||||
* @deprecated use {@link SecondaryRow#owned()}
|
* @deprecated use {@link SecondaryRow#owned()}
|
||||||
*/
|
*/
|
||||||
@Deprecated(since = "6.2")
|
@Deprecated(since = "6.2")
|
||||||
|
@ -87,7 +92,7 @@ public @interface Table {
|
||||||
* would not all be null, and will always use an outer join to read the columns. Thus,
|
* 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.
|
* by default, Hibernate avoids creating a row of null values.
|
||||||
*
|
*
|
||||||
* @apiNote Only relevant for secondary tables
|
* @apiNote Only relevant to secondary tables
|
||||||
* @deprecated use {@link SecondaryRow#optional()}
|
* @deprecated use {@link SecondaryRow#optional()}
|
||||||
*/
|
*/
|
||||||
@Deprecated(since = "6.2")
|
@Deprecated(since = "6.2")
|
||||||
|
@ -95,9 +100,8 @@ public @interface Table {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines a custom SQL insert statement.
|
* Defines a custom SQL insert statement.
|
||||||
* <p>
|
|
||||||
* <em>Only applies to secondary tables.</em>
|
|
||||||
*
|
*
|
||||||
|
* @apiNote Only relevant to secondary tables
|
||||||
* @deprecated use {@link SQLInsert#table()} to specify the secondary table
|
* @deprecated use {@link SQLInsert#table()} to specify the secondary table
|
||||||
*/
|
*/
|
||||||
@Deprecated(since="6.2")
|
@Deprecated(since="6.2")
|
||||||
|
@ -105,9 +109,8 @@ public @interface Table {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines a custom SQL update statement.
|
* Defines a custom SQL update statement.
|
||||||
* <p>
|
|
||||||
* <em>Only applies to secondary tables.</em>
|
|
||||||
*
|
*
|
||||||
|
* @apiNote Only relevant to secondary tables
|
||||||
* @deprecated use {@link SQLInsert#table()} to specify the secondary table
|
* @deprecated use {@link SQLInsert#table()} to specify the secondary table
|
||||||
*/
|
*/
|
||||||
@Deprecated(since="6.2")
|
@Deprecated(since="6.2")
|
||||||
|
@ -115,9 +118,8 @@ public @interface Table {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines a custom SQL delete statement.
|
* Defines a custom SQL delete statement.
|
||||||
* <p>
|
|
||||||
* <em>Only applies to secondary tables.</em>
|
|
||||||
*
|
*
|
||||||
|
* @apiNote Only relevant to secondary tables
|
||||||
* @deprecated use {@link SQLInsert#table()} to specify the secondary table
|
* @deprecated use {@link SQLInsert#table()} to specify the secondary table
|
||||||
*/
|
*/
|
||||||
@Deprecated(since="6.2")
|
@Deprecated(since="6.2")
|
||||||
|
|
|
@ -16,9 +16,12 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
* A grouping of {@link Table}s.
|
* A grouping of {@link Table}s.
|
||||||
*
|
*
|
||||||
* @author Emmanuel Bernard
|
* @author Emmanuel Bernard
|
||||||
|
*
|
||||||
|
* @deprecated since {@link Table} is deprecated
|
||||||
*/
|
*/
|
||||||
@Target(TYPE)
|
@Target(TYPE)
|
||||||
@Retention(RUNTIME)
|
@Retention(RUNTIME)
|
||||||
|
@Deprecated(since = "6.2", forRemoval = true)
|
||||||
public @interface Tables {
|
public @interface Tables {
|
||||||
/**
|
/**
|
||||||
* The table grouping.
|
* The table grouping.
|
||||||
|
|
|
@ -27,6 +27,7 @@ import org.hibernate.boot.spi.PropertyData;
|
||||||
import org.hibernate.internal.CoreMessageLogger;
|
import org.hibernate.internal.CoreMessageLogger;
|
||||||
import org.hibernate.internal.util.StringHelper;
|
import org.hibernate.internal.util.StringHelper;
|
||||||
import org.hibernate.mapping.AggregateColumn;
|
import org.hibernate.mapping.AggregateColumn;
|
||||||
|
import org.hibernate.mapping.CheckConstraint;
|
||||||
import org.hibernate.mapping.Column;
|
import org.hibernate.mapping.Column;
|
||||||
import org.hibernate.mapping.Component;
|
import org.hibernate.mapping.Component;
|
||||||
import org.hibernate.mapping.Formula;
|
import org.hibernate.mapping.Formula;
|
||||||
|
@ -83,6 +84,7 @@ public class AnnotatedColumn {
|
||||||
private String generatedAs;
|
private String generatedAs;
|
||||||
|
|
||||||
// private String comment;
|
// private String comment;
|
||||||
|
private String checkConstraintName;
|
||||||
private String checkConstraint;
|
private String checkConstraint;
|
||||||
|
|
||||||
private AnnotatedColumns parent;
|
private AnnotatedColumns parent;
|
||||||
|
@ -124,10 +126,6 @@ public class AnnotatedColumn {
|
||||||
return isNotEmpty( formulaString );
|
return isNotEmpty( formulaString );
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFormulaString() {
|
|
||||||
return formulaString;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getExplicitTableName() {
|
public String getExplicitTableName() {
|
||||||
return explicitTableName;
|
return explicitTableName;
|
||||||
}
|
}
|
||||||
|
@ -188,16 +186,13 @@ public class AnnotatedColumn {
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCheckConstraint() {
|
|
||||||
return checkConstraint;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDefaultValue(String defaultValue) {
|
public void setDefaultValue(String defaultValue) {
|
||||||
this.defaultValue = defaultValue;
|
this.defaultValue = defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCheckConstraint(String checkConstraint) {
|
public void setCheckConstraint(String name, String constraint) {
|
||||||
this.checkConstraint = checkConstraint;
|
this.checkConstraintName = name;
|
||||||
|
this.checkConstraint = constraint;
|
||||||
}
|
}
|
||||||
|
|
||||||
// public String getComment() {
|
// public String getComment() {
|
||||||
|
@ -241,7 +236,7 @@ public class AnnotatedColumn {
|
||||||
mappingColumn.setDefaultValue( defaultValue );
|
mappingColumn.setDefaultValue( defaultValue );
|
||||||
}
|
}
|
||||||
if ( checkConstraint != null ) {
|
if ( checkConstraint != null ) {
|
||||||
mappingColumn.setCheckConstraint( checkConstraint );
|
mappingColumn.setCheck( new CheckConstraint( checkConstraintName, checkConstraint ) );
|
||||||
}
|
}
|
||||||
// if ( isNotEmpty( comment ) ) {
|
// if ( isNotEmpty( comment ) ) {
|
||||||
// mappingColumn.setComment( comment );
|
// mappingColumn.setComment( comment );
|
||||||
|
@ -280,7 +275,9 @@ public class AnnotatedColumn {
|
||||||
mappingColumn.setNullable( nullable );
|
mappingColumn.setNullable( nullable );
|
||||||
mappingColumn.setSqlType( sqlType );
|
mappingColumn.setSqlType( sqlType );
|
||||||
mappingColumn.setUnique( unique );
|
mappingColumn.setUnique( unique );
|
||||||
mappingColumn.setCheckConstraint( checkConstraint );
|
if ( checkConstraint != null ) {
|
||||||
|
mappingColumn.setCheck( new CheckConstraint( checkConstraintName, checkConstraint ) );
|
||||||
|
}
|
||||||
mappingColumn.setDefaultValue( defaultValue );
|
mappingColumn.setDefaultValue( defaultValue );
|
||||||
|
|
||||||
if ( writeExpression != null ) {
|
if ( writeExpression != null ) {
|
||||||
|
@ -817,7 +814,7 @@ public class AnnotatedColumn {
|
||||||
throw new AnnotationException("'@Check' may only be applied to single-column mappings but '"
|
throw new AnnotationException("'@Check' may only be applied to single-column mappings but '"
|
||||||
+ property.getName() + "' maps to " + length + " columns (use a table-level '@Check')" );
|
+ property.getName() + "' maps to " + length + " columns (use a table-level '@Check')" );
|
||||||
}
|
}
|
||||||
setCheckConstraint( check.constraints() );
|
setCheckConstraint( check.name().isEmpty() ? null : check.name(), check.constraints() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -226,7 +226,7 @@ public class ClassPropertyHolder extends AbstractPropertyHolder {
|
||||||
return join;
|
return join;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addPropertyToPersistentClass(Property prop, XClass declaringClass) {
|
private void addPropertyToPersistentClass(Property property, XClass declaringClass) {
|
||||||
if ( declaringClass != null ) {
|
if ( declaringClass != null ) {
|
||||||
final InheritanceState inheritanceState = inheritanceStatePerClass.get( declaringClass );
|
final InheritanceState inheritanceState = inheritanceStatePerClass.get( declaringClass );
|
||||||
if ( inheritanceState == null ) {
|
if ( inheritanceState == null ) {
|
||||||
|
@ -235,15 +235,15 @@ public class ClassPropertyHolder extends AbstractPropertyHolder {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if ( inheritanceState.isEmbeddableSuperclass() ) {
|
if ( inheritanceState.isEmbeddableSuperclass() ) {
|
||||||
persistentClass.addMappedSuperclassProperty( prop );
|
persistentClass.addMappedSuperclassProperty( property );
|
||||||
addPropertyToMappedSuperclass( prop, declaringClass );
|
addPropertyToMappedSuperclass( property, declaringClass );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
persistentClass.addProperty( prop );
|
persistentClass.addProperty( property );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
persistentClass.addProperty( prop );
|
persistentClass.addProperty( property );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -359,7 +359,7 @@ public class ClassPropertyHolder extends AbstractPropertyHolder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addPropertyToJoin(Property prop, XClass declaringClass, Join join) {
|
private void addPropertyToJoin(Property property, XClass declaringClass, Join join) {
|
||||||
if ( declaringClass != null ) {
|
if ( declaringClass != null ) {
|
||||||
final InheritanceState inheritanceState = inheritanceStatePerClass.get( declaringClass );
|
final InheritanceState inheritanceState = inheritanceStatePerClass.get( declaringClass );
|
||||||
if ( inheritanceState == null ) {
|
if ( inheritanceState == null ) {
|
||||||
|
@ -368,15 +368,15 @@ public class ClassPropertyHolder extends AbstractPropertyHolder {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if ( inheritanceState.isEmbeddableSuperclass() ) {
|
if ( inheritanceState.isEmbeddableSuperclass() ) {
|
||||||
join.addMappedsuperclassProperty(prop);
|
join.addMappedsuperclassProperty( property );
|
||||||
addPropertyToMappedSuperclass( prop, declaringClass );
|
addPropertyToMappedSuperclass( property, declaringClass );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
join.addProperty( prop );
|
join.addProperty( property );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
join.addProperty( prop );
|
join.addProperty( property );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ import org.hibernate.annotations.Bag;
|
||||||
import org.hibernate.annotations.BatchSize;
|
import org.hibernate.annotations.BatchSize;
|
||||||
import org.hibernate.annotations.Cache;
|
import org.hibernate.annotations.Cache;
|
||||||
import org.hibernate.annotations.Cascade;
|
import org.hibernate.annotations.Cascade;
|
||||||
|
import org.hibernate.annotations.Check;
|
||||||
import org.hibernate.annotations.CollectionId;
|
import org.hibernate.annotations.CollectionId;
|
||||||
import org.hibernate.annotations.CollectionIdJavaType;
|
import org.hibernate.annotations.CollectionIdJavaType;
|
||||||
import org.hibernate.annotations.CollectionIdJdbcType;
|
import org.hibernate.annotations.CollectionIdJdbcType;
|
||||||
|
@ -84,6 +85,7 @@ import org.hibernate.internal.CoreMessageLogger;
|
||||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||||
import org.hibernate.mapping.Any;
|
import org.hibernate.mapping.Any;
|
||||||
import org.hibernate.mapping.Backref;
|
import org.hibernate.mapping.Backref;
|
||||||
|
import org.hibernate.mapping.CheckConstraint;
|
||||||
import org.hibernate.mapping.Collection;
|
import org.hibernate.mapping.Collection;
|
||||||
import org.hibernate.mapping.Column;
|
import org.hibernate.mapping.Column;
|
||||||
import org.hibernate.mapping.Component;
|
import org.hibernate.mapping.Component;
|
||||||
|
@ -1626,7 +1628,7 @@ public abstract class CollectionBinder {
|
||||||
handleWhere( false );
|
handleWhere( false );
|
||||||
|
|
||||||
final PersistentClass targetEntity = persistentClasses.get( getElementType().getName() );
|
final PersistentClass targetEntity = persistentClasses.get( getElementType().getName() );
|
||||||
bindCollectionSecondPass( targetEntity, foreignJoinColumns, onDeleteAction);
|
bindCollectionSecondPass( targetEntity, foreignJoinColumns );
|
||||||
|
|
||||||
if ( !collection.isInverse() && !collection.getKey().isNullable() ) {
|
if ( !collection.isInverse() && !collection.getKey().isNullable() ) {
|
||||||
createOneToManyBackref( oneToMany );
|
createOneToManyBackref( oneToMany );
|
||||||
|
@ -2056,84 +2058,35 @@ public abstract class CollectionBinder {
|
||||||
logManyToManySecondPass( oneToMany, isCollectionOfEntities, isManyToAny );
|
logManyToManySecondPass( oneToMany, isCollectionOfEntities, isManyToAny );
|
||||||
|
|
||||||
//check for user error
|
//check for user error
|
||||||
detectManyToManyProblems(
|
detectManyToManyProblems( elementType, isCollectionOfEntities, isManyToAny );
|
||||||
elementType,
|
|
||||||
property,
|
|
||||||
propertyHolder,
|
|
||||||
isCollectionOfEntities,
|
|
||||||
isManyToAny
|
|
||||||
);
|
|
||||||
|
|
||||||
if ( isUnownedCollection() ) {
|
if ( isUnownedCollection() ) {
|
||||||
handleUnownedManyToMany(
|
handleUnownedManyToMany( elementType, targetEntity, isCollectionOfEntities );
|
||||||
collection,
|
|
||||||
joinColumns,
|
|
||||||
elementType,
|
|
||||||
targetEntity,
|
|
||||||
isCollectionOfEntities
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
handleOwnedManyToMany(
|
handleOwnedManyToMany( targetEntity, isCollectionOfEntities );
|
||||||
collection,
|
|
||||||
joinColumns,
|
|
||||||
tableBinder,
|
|
||||||
property,
|
|
||||||
buildingContext,
|
|
||||||
targetEntity,
|
|
||||||
isCollectionOfEntities
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
bindFilters( isCollectionOfEntities );
|
bindFilters( isCollectionOfEntities );
|
||||||
handleWhere( isCollectionOfEntities );
|
handleWhere( isCollectionOfEntities );
|
||||||
|
|
||||||
bindCollectionSecondPass( targetEntity, joinColumns, onDeleteAction);
|
bindCollectionSecondPass( targetEntity, joinColumns );
|
||||||
|
|
||||||
if ( isCollectionOfEntities ) {
|
if ( isCollectionOfEntities ) {
|
||||||
final ManyToOne element = handleCollectionOfEntities(
|
final ManyToOne element = handleCollectionOfEntities( elementType, targetEntity, hqlOrderBy );
|
||||||
collection,
|
|
||||||
elementType,
|
|
||||||
notFoundAction,
|
|
||||||
property,
|
|
||||||
buildingContext,
|
|
||||||
targetEntity,
|
|
||||||
hqlOrderBy
|
|
||||||
);
|
|
||||||
bindManyToManyInverseForeignKey( targetEntity, inverseJoinColumns, element, oneToMany );
|
bindManyToManyInverseForeignKey( targetEntity, inverseJoinColumns, element, oneToMany );
|
||||||
}
|
}
|
||||||
else if ( isManyToAny ) {
|
else if ( isManyToAny ) {
|
||||||
handleManyToAny(
|
handleManyToAny();
|
||||||
collection,
|
|
||||||
inverseJoinColumns,
|
|
||||||
onDeleteAction,
|
|
||||||
property,
|
|
||||||
buildingContext
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
handleElementCollection(
|
handleElementCollection( elementType, hqlOrderBy );
|
||||||
collection,
|
|
||||||
elementColumns,
|
|
||||||
isEmbedded,
|
|
||||||
elementType,
|
|
||||||
property,
|
|
||||||
propertyHolder,
|
|
||||||
hqlOrderBy
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
checkFilterConditions( collection );
|
checkFilterConditions( collection );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleElementCollection(
|
private void handleElementCollection(XClass elementType, String hqlOrderBy) {
|
||||||
Collection collection,
|
// 'propertyHolder' is the PropertyHolder for the owner of the collection
|
||||||
AnnotatedColumns elementColumns,
|
|
||||||
boolean isEmbedded,
|
|
||||||
XClass elementType,
|
|
||||||
XProperty property,
|
|
||||||
PropertyHolder parentPropertyHolder,
|
|
||||||
String hqlOrderBy) {
|
|
||||||
// 'parentPropertyHolder' is the PropertyHolder for the owner of the collection
|
|
||||||
// 'holder' is the CollectionPropertyHolder.
|
// 'holder' is the CollectionPropertyHolder.
|
||||||
// 'property' is the collection XProperty
|
// 'property' is the collection XProperty
|
||||||
|
|
||||||
|
@ -2141,7 +2094,7 @@ public abstract class CollectionBinder {
|
||||||
final AnnotatedClassType classType = annotatedElementType( isEmbedded, property, elementType );
|
final AnnotatedClassType classType = annotatedElementType( isEmbedded, property, elementType );
|
||||||
final boolean primitive = classType == NONE;
|
final boolean primitive = classType == NONE;
|
||||||
if ( !primitive ) {
|
if ( !primitive ) {
|
||||||
parentPropertyHolder.startingProperty( property );
|
propertyHolder.startingProperty( property );
|
||||||
}
|
}
|
||||||
|
|
||||||
final CollectionPropertyHolder holder = buildPropertyHolder(
|
final CollectionPropertyHolder holder = buildPropertyHolder(
|
||||||
|
@ -2149,7 +2102,7 @@ public abstract class CollectionBinder {
|
||||||
collection.getRole(),
|
collection.getRole(),
|
||||||
elementClass,
|
elementClass,
|
||||||
property,
|
property,
|
||||||
parentPropertyHolder,
|
propertyHolder,
|
||||||
buildingContext
|
buildingContext
|
||||||
);
|
);
|
||||||
holder.prepare( property );
|
holder.prepare( property );
|
||||||
|
@ -2157,18 +2110,15 @@ public abstract class CollectionBinder {
|
||||||
final Class<? extends CompositeUserType<?>> compositeUserType =
|
final Class<? extends CompositeUserType<?>> compositeUserType =
|
||||||
resolveCompositeUserType( property, elementClass, buildingContext );
|
resolveCompositeUserType( property, elementClass, buildingContext );
|
||||||
if ( classType == EMBEDDABLE || compositeUserType != null ) {
|
if ( classType == EMBEDDABLE || compositeUserType != null ) {
|
||||||
handleCompositeCollectionElement( collection, property, hqlOrderBy, elementClass, holder, compositeUserType );
|
handleCompositeCollectionElement( hqlOrderBy, elementClass, holder, compositeUserType );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
handleCollectionElement( collection, elementColumns, elementType, property, hqlOrderBy, elementClass, holder );
|
handleCollectionElement( elementType, hqlOrderBy, elementClass, holder );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleCollectionElement(
|
private void handleCollectionElement(
|
||||||
Collection collection,
|
|
||||||
AnnotatedColumns elementColumns,
|
|
||||||
XClass elementType,
|
XClass elementType,
|
||||||
XProperty property,
|
|
||||||
String hqlOrderBy,
|
String hqlOrderBy,
|
||||||
XClass elementClass,
|
XClass elementClass,
|
||||||
CollectionPropertyHolder holder) {
|
CollectionPropertyHolder holder) {
|
||||||
|
@ -2199,8 +2149,6 @@ public abstract class CollectionBinder {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleCompositeCollectionElement(
|
private void handleCompositeCollectionElement(
|
||||||
Collection collection,
|
|
||||||
XProperty property,
|
|
||||||
String hqlOrderBy,
|
String hqlOrderBy,
|
||||||
XClass elementClass,
|
XClass elementClass,
|
||||||
CollectionPropertyHolder holder,
|
CollectionPropertyHolder holder,
|
||||||
|
@ -2256,7 +2204,7 @@ public abstract class CollectionBinder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AnnotatedClassType annotatedElementType(
|
private AnnotatedClassType annotatedElementType(
|
||||||
boolean isEmbedded,
|
boolean isEmbedded,
|
||||||
XProperty property,
|
XProperty property,
|
||||||
XClass elementType) {
|
XClass elementType) {
|
||||||
|
@ -2301,14 +2249,7 @@ public abstract class CollectionBinder {
|
||||||
return elementColumns;
|
return elementColumns;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ManyToOne handleCollectionOfEntities(
|
private ManyToOne handleCollectionOfEntities(XClass elementType, PersistentClass collectionEntity, String hqlOrderBy) {
|
||||||
Collection collection,
|
|
||||||
XClass elementType,
|
|
||||||
NotFoundAction notFoundAction,
|
|
||||||
XProperty property,
|
|
||||||
MetadataBuildingContext buildingContext,
|
|
||||||
PersistentClass collectionEntity,
|
|
||||||
String hqlOrderBy) {
|
|
||||||
final ManyToOne element = new ManyToOne( buildingContext, collection.getCollectionTable() );
|
final ManyToOne element = new ManyToOne( buildingContext, collection.getCollectionTable() );
|
||||||
collection.setElement( element );
|
collection.setElement( element );
|
||||||
element.setReferencedEntityName( elementType.getName() );
|
element.setReferencedEntityName( elementType.getName() );
|
||||||
|
@ -2339,8 +2280,9 @@ public abstract class CollectionBinder {
|
||||||
foreignKeyDefinition = joinColumnAnn.foreignKey().foreignKeyDefinition();
|
foreignKeyDefinition = joinColumnAnn.foreignKey().foreignKeyDefinition();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( joinTableAnn.inverseForeignKey().value() == NO_CONSTRAINT
|
final ConstraintMode constraintMode = joinTableAnn.inverseForeignKey().value();
|
||||||
|| joinTableAnn.inverseForeignKey().value() == PROVIDER_DEFAULT
|
if ( constraintMode == NO_CONSTRAINT
|
||||||
|
|| constraintMode == PROVIDER_DEFAULT
|
||||||
&& buildingContext.getBuildingOptions().isNoConstraintByDefault() ) {
|
&& buildingContext.getBuildingOptions().isNoConstraintByDefault() ) {
|
||||||
element.disableForeignKey();
|
element.disableForeignKey();
|
||||||
}
|
}
|
||||||
|
@ -2353,12 +2295,7 @@ public abstract class CollectionBinder {
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleManyToAny(
|
private void handleManyToAny() {
|
||||||
Collection collection,
|
|
||||||
AnnotatedJoinColumns inverseJoinColumns,
|
|
||||||
OnDeleteAction onDeleteAction,
|
|
||||||
XProperty property,
|
|
||||||
MetadataBuildingContext buildingContext) {
|
|
||||||
//@ManyToAny
|
//@ManyToAny
|
||||||
//Make sure that collTyp is never used during the @ManyToAny branch: it will be set to void.class
|
//Make sure that collTyp is never used during the @ManyToAny branch: it will be set to void.class
|
||||||
final PropertyData inferredData = new PropertyInferredData(
|
final PropertyData inferredData = new PropertyInferredData(
|
||||||
|
@ -2414,25 +2351,20 @@ public abstract class CollectionBinder {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleOwnedManyToMany(
|
private void handleOwnedManyToMany(
|
||||||
Collection collection,
|
|
||||||
AnnotatedJoinColumns joinColumns,
|
|
||||||
TableBinder associationTableBinder,
|
|
||||||
XProperty property,
|
|
||||||
MetadataBuildingContext context,
|
|
||||||
PersistentClass collectionEntity,
|
PersistentClass collectionEntity,
|
||||||
boolean isCollectionOfEntities) {
|
boolean isCollectionOfEntities) {
|
||||||
//TODO: only for implicit columns?
|
//TODO: only for implicit columns?
|
||||||
//FIXME NamingStrategy
|
//FIXME NamingStrategy
|
||||||
final InFlightMetadataCollector collector = context.getMetadataCollector();
|
final InFlightMetadataCollector collector = buildingContext.getMetadataCollector();
|
||||||
final PersistentClass owner = collection.getOwner();
|
final PersistentClass owner = collection.getOwner();
|
||||||
joinColumns.setMappedBy(
|
joinColumns.setMappedBy(
|
||||||
owner.getEntityName(),
|
owner.getEntityName(),
|
||||||
collector.getLogicalTableName( owner.getTable() ),
|
collector.getLogicalTableName( owner.getTable() ),
|
||||||
collector.getFromMappedBy( owner.getEntityName(), joinColumns.getPropertyName() )
|
collector.getFromMappedBy( owner.getEntityName(), joinColumns.getPropertyName() )
|
||||||
);
|
);
|
||||||
if ( isEmpty( associationTableBinder.getName() ) ) {
|
if ( isEmpty( tableBinder.getName() ) ) {
|
||||||
//default value
|
//default value
|
||||||
associationTableBinder.setDefaultName(
|
tableBinder.setDefaultName(
|
||||||
owner.getClassName(),
|
owner.getClassName(),
|
||||||
owner.getEntityName(),
|
owner.getEntityName(),
|
||||||
owner.getJpaEntityName(),
|
owner.getJpaEntityName(),
|
||||||
|
@ -2444,15 +2376,26 @@ public abstract class CollectionBinder {
|
||||||
joinColumns.getPropertyName()
|
joinColumns.getPropertyName()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
associationTableBinder.setJPA2ElementCollection(
|
tableBinder.setJPA2ElementCollection(
|
||||||
!isCollectionOfEntities && property.isAnnotationPresent( ElementCollection.class )
|
!isCollectionOfEntities && property.isAnnotationPresent( ElementCollection.class )
|
||||||
);
|
);
|
||||||
collection.setCollectionTable( associationTableBinder.bind() );
|
Table collectionTable = tableBinder.bind();
|
||||||
|
collection.setCollectionTable( collectionTable );
|
||||||
|
handleCheck( collectionTable );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleCheck(Table collectionTable) {
|
||||||
|
final Check check = getOverridableAnnotation( property, Check.class, buildingContext );
|
||||||
|
if ( check != null ) {
|
||||||
|
final String name = check.name();
|
||||||
|
final String constraint = check.constraints();
|
||||||
|
collectionTable.addCheck( name.isEmpty()
|
||||||
|
? new CheckConstraint( constraint )
|
||||||
|
: new CheckConstraint( name, constraint ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleUnownedManyToMany(
|
private void handleUnownedManyToMany(
|
||||||
Collection collection,
|
|
||||||
AnnotatedJoinColumns joinColumns,
|
|
||||||
XClass elementType,
|
XClass elementType,
|
||||||
PersistentClass collectionEntity,
|
PersistentClass collectionEntity,
|
||||||
boolean isCollectionOfEntities) {
|
boolean isCollectionOfEntities) {
|
||||||
|
@ -2484,8 +2427,6 @@ public abstract class CollectionBinder {
|
||||||
|
|
||||||
private void detectManyToManyProblems(
|
private void detectManyToManyProblems(
|
||||||
XClass elementType,
|
XClass elementType,
|
||||||
XProperty property,
|
|
||||||
PropertyHolder parentPropertyHolder,
|
|
||||||
boolean isCollectionOfEntities,
|
boolean isCollectionOfEntities,
|
||||||
boolean isManyToAny) {
|
boolean isManyToAny) {
|
||||||
|
|
||||||
|
@ -2495,13 +2436,13 @@ public abstract class CollectionBinder {
|
||||||
+ "' targets the type '" + elementType.getName() + "' which is not an '@Entity' type" );
|
+ "' targets the type '" + elementType.getName() + "' which is not an '@Entity' type" );
|
||||||
}
|
}
|
||||||
else if (isManyToAny) {
|
else if (isManyToAny) {
|
||||||
if ( parentPropertyHolder.getJoinTable( property ) == null ) {
|
if ( propertyHolder.getJoinTable( property ) == null ) {
|
||||||
throw new AnnotationException( "Association '" + safeCollectionRole()
|
throw new AnnotationException( "Association '" + safeCollectionRole()
|
||||||
+ "' is a '@ManyToAny' and must specify a '@JoinTable'" );
|
+ "' is a '@ManyToAny' and must specify a '@JoinTable'" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
final JoinTable joinTableAnn = parentPropertyHolder.getJoinTable( property );
|
final JoinTable joinTableAnn = propertyHolder.getJoinTable( property );
|
||||||
if ( joinTableAnn != null && joinTableAnn.inverseJoinColumns().length > 0 ) {
|
if ( joinTableAnn != null && joinTableAnn.inverseJoinColumns().length > 0 ) {
|
||||||
throw new AnnotationException( "Association '" + safeCollectionRole()
|
throw new AnnotationException( "Association '" + safeCollectionRole()
|
||||||
+ " has a '@JoinTable' with 'inverseJoinColumns' and targets the type '"
|
+ " has a '@JoinTable' with 'inverseJoinColumns' and targets the type '"
|
||||||
|
@ -2576,10 +2517,7 @@ public abstract class CollectionBinder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bindCollectionSecondPass(
|
private void bindCollectionSecondPass(PersistentClass targetEntity, AnnotatedJoinColumns joinColumns) {
|
||||||
PersistentClass targetEntity,
|
|
||||||
AnnotatedJoinColumns joinColumns,
|
|
||||||
OnDeleteAction onDeleteAction) {
|
|
||||||
|
|
||||||
if ( !isUnownedCollection() ) {
|
if ( !isUnownedCollection() ) {
|
||||||
createSyntheticPropertyReference(
|
createSyntheticPropertyReference(
|
||||||
|
@ -2710,8 +2648,8 @@ public abstract class CollectionBinder {
|
||||||
this.foreignJoinColumns = annotatedJoinColumns;
|
this.foreignJoinColumns = annotatedJoinColumns;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setExplicitAssociationTable(boolean explicitAssocTable) {
|
public void setExplicitAssociationTable(boolean isExplicitAssociationTable) {
|
||||||
this.isExplicitAssociationTable = explicitAssocTable;
|
this.isExplicitAssociationTable = isExplicitAssociationTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setElementColumns(AnnotatedColumns elementColumns) {
|
public void setElementColumns(AnnotatedColumns elementColumns) {
|
||||||
|
|
|
@ -45,6 +45,7 @@ import org.hibernate.annotations.BatchSize;
|
||||||
import org.hibernate.annotations.Cache;
|
import org.hibernate.annotations.Cache;
|
||||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||||
import org.hibernate.annotations.Check;
|
import org.hibernate.annotations.Check;
|
||||||
|
import org.hibernate.annotations.Checks;
|
||||||
import org.hibernate.annotations.DiscriminatorFormula;
|
import org.hibernate.annotations.DiscriminatorFormula;
|
||||||
import org.hibernate.annotations.DiscriminatorOptions;
|
import org.hibernate.annotations.DiscriminatorOptions;
|
||||||
import org.hibernate.annotations.DynamicInsert;
|
import org.hibernate.annotations.DynamicInsert;
|
||||||
|
@ -52,6 +53,7 @@ import org.hibernate.annotations.DynamicUpdate;
|
||||||
import org.hibernate.annotations.Filter;
|
import org.hibernate.annotations.Filter;
|
||||||
import org.hibernate.annotations.Filters;
|
import org.hibernate.annotations.Filters;
|
||||||
import org.hibernate.annotations.ForeignKey;
|
import org.hibernate.annotations.ForeignKey;
|
||||||
|
import org.hibernate.annotations.ForeignKey;
|
||||||
import org.hibernate.annotations.Immutable;
|
import org.hibernate.annotations.Immutable;
|
||||||
import org.hibernate.annotations.Loader;
|
import org.hibernate.annotations.Loader;
|
||||||
import org.hibernate.annotations.NaturalIdCache;
|
import org.hibernate.annotations.NaturalIdCache;
|
||||||
|
@ -101,6 +103,7 @@ import org.hibernate.engine.spi.FilterDefinition;
|
||||||
import org.hibernate.internal.CoreMessageLogger;
|
import org.hibernate.internal.CoreMessageLogger;
|
||||||
import org.hibernate.jpa.event.spi.CallbackType;
|
import org.hibernate.jpa.event.spi.CallbackType;
|
||||||
import org.hibernate.mapping.BasicValue;
|
import org.hibernate.mapping.BasicValue;
|
||||||
|
import org.hibernate.mapping.CheckConstraint;
|
||||||
import org.hibernate.mapping.Component;
|
import org.hibernate.mapping.Component;
|
||||||
import org.hibernate.mapping.DependantValue;
|
import org.hibernate.mapping.DependantValue;
|
||||||
import org.hibernate.mapping.Join;
|
import org.hibernate.mapping.Join;
|
||||||
|
@ -210,6 +213,7 @@ public class EntityBinder {
|
||||||
entityBinder.bindEntity();
|
entityBinder.bindEntity();
|
||||||
entityBinder.handleClassTable( inheritanceState, superEntity );
|
entityBinder.handleClassTable( inheritanceState, superEntity );
|
||||||
entityBinder.handleSecondaryTables();
|
entityBinder.handleSecondaryTables();
|
||||||
|
entityBinder.handleCheck();
|
||||||
final PropertyHolder holder = buildPropertyHolder(
|
final PropertyHolder holder = buildPropertyHolder(
|
||||||
clazzToProcess,
|
clazzToProcess,
|
||||||
persistentClass,
|
persistentClass,
|
||||||
|
@ -238,6 +242,33 @@ public class EntityBinder {
|
||||||
entityBinder.callTypeBinders( persistentClass );
|
entityBinder.callTypeBinders( persistentClass );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleCheck() {
|
||||||
|
if ( annotatedClass.isAnnotationPresent( Checks.class ) ) {
|
||||||
|
// if we have more than one of them they are not overrideable :-/
|
||||||
|
for ( Check check : annotatedClass.getAnnotation( Checks.class ).value() ) {
|
||||||
|
addCheckToEntity( check );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final Check check = getOverridableAnnotation( annotatedClass, Check.class, context );
|
||||||
|
if ( check != null ) {
|
||||||
|
addCheckToEntity( check );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For now, we store it on the entity.
|
||||||
|
* Later we will come back and figure out which table it belongs to.
|
||||||
|
*/
|
||||||
|
private void addCheckToEntity(Check check) {
|
||||||
|
final String name = check.name();
|
||||||
|
final String constraint = check.constraints();
|
||||||
|
persistentClass.addCheckConstraint( name.isEmpty()
|
||||||
|
? new CheckConstraint( constraint )
|
||||||
|
: new CheckConstraint( name, constraint ) );
|
||||||
|
}
|
||||||
|
|
||||||
private void callTypeBinders(PersistentClass persistentClass) {
|
private void callTypeBinders(PersistentClass persistentClass) {
|
||||||
for ( Annotation containingAnnotation : findContainingAnnotations( annotatedClass, TypeBinderType.class ) ) {
|
for ( Annotation containingAnnotation : findContainingAnnotations( annotatedClass, TypeBinderType.class ) ) {
|
||||||
final TypeBinderType binderType = containingAnnotation.annotationType().getAnnotation( TypeBinderType.class );
|
final TypeBinderType binderType = containingAnnotation.annotationType().getAnnotation( TypeBinderType.class );
|
||||||
|
@ -643,14 +674,12 @@ public class EntityBinder {
|
||||||
String catalog,
|
String catalog,
|
||||||
List<UniqueConstraintHolder> uniqueConstraints,
|
List<UniqueConstraintHolder> uniqueConstraints,
|
||||||
InFlightMetadataCollector collector) {
|
InFlightMetadataCollector collector) {
|
||||||
final Check check = getOverridableAnnotation( annotatedClass, Check.class, context );
|
|
||||||
final RowId rowId = annotatedClass.getAnnotation( RowId.class );
|
final RowId rowId = annotatedClass.getAnnotation( RowId.class );
|
||||||
bindTable(
|
bindTable(
|
||||||
schema,
|
schema,
|
||||||
catalog,
|
catalog,
|
||||||
table,
|
table,
|
||||||
uniqueConstraints,
|
uniqueConstraints,
|
||||||
check == null ? null : check.constraints(),
|
|
||||||
rowId == null ? null : rowId.value(),
|
rowId == null ? null : rowId.value(),
|
||||||
inheritanceState.hasDenormalizedTable()
|
inheritanceState.hasDenormalizedTable()
|
||||||
? collector.getEntityTableXref( superEntity.getEntityName() )
|
? collector.getEntityTableXref( superEntity.getEntityName() )
|
||||||
|
@ -1662,7 +1691,6 @@ public class EntityBinder {
|
||||||
String catalog,
|
String catalog,
|
||||||
String tableName,
|
String tableName,
|
||||||
List<UniqueConstraintHolder> uniqueConstraints,
|
List<UniqueConstraintHolder> uniqueConstraints,
|
||||||
String checkConstraint,
|
|
||||||
String rowId,
|
String rowId,
|
||||||
InFlightMetadataCollector.EntityTableXref denormalizedSuperTableXref) {
|
InFlightMetadataCollector.EntityTableXref denormalizedSuperTableXref) {
|
||||||
|
|
||||||
|
@ -1687,9 +1715,6 @@ public class EntityBinder {
|
||||||
);
|
);
|
||||||
|
|
||||||
table.setRowId( rowId );
|
table.setRowId( rowId );
|
||||||
if ( checkConstraint != null ) {
|
|
||||||
table.addCheckConstraint( checkConstraint );
|
|
||||||
}
|
|
||||||
|
|
||||||
// final Comment comment = annotatedClass.getAnnotation( Comment.class );
|
// final Comment comment = annotatedClass.getAnnotation( Comment.class );
|
||||||
// if ( comment != null ) {
|
// if ( comment != null ) {
|
||||||
|
|
|
@ -182,19 +182,8 @@ public class OneToOneSecondPass implements SecondPass {
|
||||||
manyToOne.markAsLogicalOneToOne();
|
manyToOne.markAsLogicalOneToOne();
|
||||||
property.setValue( manyToOne );
|
property.setValue( manyToOne );
|
||||||
for ( Column column: otherSideJoin.getKey().getColumns() ) {
|
for ( Column column: otherSideJoin.getKey().getColumns() ) {
|
||||||
Column copy = new Column();
|
Column copy = column.clone();
|
||||||
copy.setLength( column.getLength() );
|
|
||||||
copy.setScale( column.getScale() );
|
|
||||||
copy.setValue( manyToOne );
|
copy.setValue( manyToOne );
|
||||||
copy.setName( column.getQuotedName() );
|
|
||||||
copy.setNullable( column.isNullable() );
|
|
||||||
copy.setPrecision( column.getPrecision() );
|
|
||||||
copy.setUnique( column.isUnique() );
|
|
||||||
copy.setSqlType( column.getSqlType() );
|
|
||||||
copy.setCheckConstraint( column.getCheckConstraint() );
|
|
||||||
copy.setComment( column.getComment() );
|
|
||||||
copy.setDefaultValue( column.getDefaultValue() );
|
|
||||||
copy.setGeneratedAs( column.getGeneratedAs() );
|
|
||||||
manyToOne.addColumn( copy );
|
manyToOne.addColumn( copy );
|
||||||
}
|
}
|
||||||
mappedByJoin.addProperty( property );
|
mappedByJoin.addProperty( property );
|
||||||
|
@ -275,25 +264,16 @@ public class OneToOneSecondPass implements SecondPass {
|
||||||
join.setOptional( true );
|
join.setOptional( true );
|
||||||
key.setOnDeleteAction( null );
|
key.setOnDeleteAction( null );
|
||||||
for ( Column column: otherSideProperty.getValue().getColumns() ) {
|
for ( Column column: otherSideProperty.getValue().getColumns() ) {
|
||||||
Column copy = new Column();
|
Column copy = column.clone();
|
||||||
copy.setLength( column.getLength() );
|
|
||||||
copy.setScale( column.getScale() );
|
|
||||||
copy.setValue( key );
|
copy.setValue( key );
|
||||||
copy.setName( column.getQuotedName() );
|
|
||||||
copy.setNullable( column.isNullable() );
|
|
||||||
copy.setPrecision( column.getPrecision() );
|
|
||||||
copy.setUnique( column.isUnique() );
|
|
||||||
copy.setSqlType( column.getSqlType() );
|
|
||||||
copy.setCheckConstraint( column.getCheckConstraint() );
|
|
||||||
copy.setComment( column.getComment() );
|
|
||||||
copy.setDefaultValue( column.getDefaultValue() );
|
|
||||||
column.setGeneratedAs( column.getGeneratedAs() );
|
|
||||||
key.addColumn( copy );
|
key.addColumn( copy );
|
||||||
}
|
}
|
||||||
if ( otherSideProperty.getValue() instanceof SortableValue
|
if ( otherSideProperty.getValue() instanceof SortableValue ) {
|
||||||
&& !( (SortableValue) otherSideProperty.getValue() ).isSorted() ) {
|
final SortableValue value = (SortableValue) otherSideProperty.getValue();
|
||||||
|
if ( !value.isSorted() ) {
|
||||||
key.sortProperties();
|
key.sortProperties();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
persistentClass.addJoin( join );
|
persistentClass.addJoin( join );
|
||||||
return join;
|
return join;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ public class AggregateColumn extends Column {
|
||||||
setSqlType( column.getSqlType() );
|
setSqlType( column.getSqlType() );
|
||||||
setSqlTypeCode( column.getSqlTypeCode() );
|
setSqlTypeCode( column.getSqlTypeCode() );
|
||||||
uniqueInteger = column.uniqueInteger; //usually useless
|
uniqueInteger = column.uniqueInteger; //usually useless
|
||||||
setCheckConstraint( column.getCheckConstraint() );
|
checkConstraint = column.checkConstraint;
|
||||||
setComment( column.getComment() );
|
setComment( column.getComment() );
|
||||||
setDefaultValue( column.getDefaultValue() );
|
setDefaultValue( column.getDefaultValue() );
|
||||||
setGeneratedAs( column.getGeneratedAs() );
|
setGeneratedAs( column.getGeneratedAs() );
|
||||||
|
|
|
@ -334,18 +334,18 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( resolution.getValueConverter() != null ) {
|
if ( resolution.getValueConverter() != null ) {
|
||||||
column.setSpecializedTypeDeclaration(
|
final String declaration = resolution.getLegacyResolvedBasicType().getSpecializedTypeDeclaration(dialect);
|
||||||
resolution.getLegacyResolvedBasicType().getSpecializedTypeDeclaration( dialect )
|
if ( declaration != null ) {
|
||||||
);
|
column.setSpecializedTypeDeclaration( declaration );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( dialect.supportsColumnCheck() && !column.hasCheckConstraint() ) {
|
if ( dialect.supportsColumnCheck() && !column.hasCheckConstraint() ) {
|
||||||
column.setCheckConstraint(
|
final String checkCondition = resolution.getLegacyResolvedBasicType()
|
||||||
resolution.getLegacyResolvedBasicType().getCheckCondition(
|
.getCheckCondition( column.getQuotedName( dialect ), dialect );
|
||||||
column.getQuotedName( dialect ),
|
if ( checkCondition != null ) {
|
||||||
dialect
|
column.setCheck( new CheckConstraint( checkCondition ) );
|
||||||
)
|
}
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* 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.mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a table or column level {@code check} constraint.
|
||||||
|
*
|
||||||
|
* @author Gavin King
|
||||||
|
*/
|
||||||
|
public class CheckConstraint {
|
||||||
|
private String name;
|
||||||
|
private String constraint;
|
||||||
|
|
||||||
|
public CheckConstraint(String name, String constraint) {
|
||||||
|
this.name = name;
|
||||||
|
this.constraint = constraint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CheckConstraint(String constraint) {
|
||||||
|
this.constraint = constraint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getConstraint() {
|
||||||
|
return constraint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConstraint(String constraint) {
|
||||||
|
this.constraint = constraint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String constraintString() {
|
||||||
|
return name == null
|
||||||
|
? " check (" + constraint + ")"
|
||||||
|
: " constraint " + name + " check (" + constraint + ")";
|
||||||
|
}
|
||||||
|
}
|
|
@ -58,7 +58,7 @@ public class Column implements Selectable, Serializable, Cloneable, ColumnTypeIn
|
||||||
private Integer sqlTypeCode;
|
private Integer sqlTypeCode;
|
||||||
private boolean quoted;
|
private boolean quoted;
|
||||||
int uniqueInteger;
|
int uniqueInteger;
|
||||||
private String checkConstraint;
|
CheckConstraint checkConstraint;
|
||||||
private String comment;
|
private String comment;
|
||||||
private String defaultValue;
|
private String defaultValue;
|
||||||
private String generatedAs;
|
private String generatedAs;
|
||||||
|
@ -490,20 +490,31 @@ public class Column implements Selectable, Serializable, Cloneable, ColumnTypeIn
|
||||||
return specializedTypeDeclaration != null;
|
return specializedTypeDeclaration != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated(since = "6.2")
|
||||||
public String getCheckConstraint() {
|
public String getCheckConstraint() {
|
||||||
return checkConstraint;
|
return checkConstraint == null ? null : checkConstraint.getConstraint();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCheckConstraint(String checkConstraint) {
|
@Deprecated(since = "6.2")
|
||||||
this.checkConstraint = checkConstraint;
|
public void setCheckConstraint(String constraint) {
|
||||||
|
checkConstraint = constraint == null ? null : new CheckConstraint( constraint );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCheck(CheckConstraint check) {
|
||||||
|
checkConstraint = check;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasCheckConstraint() {
|
public boolean hasCheckConstraint() {
|
||||||
return checkConstraint != null;
|
return checkConstraint != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated(since = "6.2")
|
||||||
public String checkConstraint() {
|
public String checkConstraint() {
|
||||||
return checkConstraint == null ? null : " check (" + checkConstraint + ")";
|
return checkConstraint == null ? null : checkConstraint.constraintString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CheckConstraint getCheck() {
|
||||||
|
return checkConstraint;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -632,24 +643,27 @@ public class Column implements Selectable, Serializable, Cloneable, ColumnTypeIn
|
||||||
@Override
|
@Override
|
||||||
public Column clone() {
|
public Column clone() {
|
||||||
Column copy = new Column();
|
Column copy = new Column();
|
||||||
copy.setLength( length );
|
copy.length = length;
|
||||||
copy.setScale( scale );
|
copy.precision = precision;
|
||||||
copy.setValue( value );
|
copy.scale = scale;
|
||||||
copy.setTypeIndex( typeIndex );
|
copy.value = value;
|
||||||
copy.setName( getQuotedName() );
|
copy.typeIndex = typeIndex;
|
||||||
copy.setNullable( nullable );
|
copy.name = name;
|
||||||
copy.setPrecision( precision );
|
copy.quoted = quoted;
|
||||||
copy.setUnique( unique );
|
copy.nullable = nullable;
|
||||||
copy.setSqlType( sqlTypeName );
|
copy.unique = unique;
|
||||||
copy.setSqlTypeCode( sqlTypeCode );
|
copy.sqlTypeName = sqlTypeName;
|
||||||
|
copy.sqlTypeCode = sqlTypeCode;
|
||||||
copy.uniqueInteger = uniqueInteger; //usually useless
|
copy.uniqueInteger = uniqueInteger; //usually useless
|
||||||
copy.setCheckConstraint( checkConstraint );
|
copy.checkConstraint = checkConstraint;
|
||||||
copy.setComment( comment );
|
copy.comment = comment;
|
||||||
copy.setDefaultValue( defaultValue );
|
copy.defaultValue = defaultValue;
|
||||||
copy.setGeneratedAs( generatedAs );
|
copy.generatedAs = generatedAs;
|
||||||
copy.setAssignmentExpression( assignmentExpression );
|
copy.assignmentExpression = assignmentExpression;
|
||||||
copy.setCustomRead( customRead );
|
copy.customRead = customRead;
|
||||||
copy.setCustomWrite( customWrite );
|
copy.customWrite = customWrite;
|
||||||
|
copy.specializedTypeDeclaration = specializedTypeDeclaration;
|
||||||
|
copy.columnSize = columnSize;
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,15 +48,15 @@ public class Join implements AttributeContainer, Serializable {
|
||||||
private ExecuteUpdateResultCheckStyle deleteCheckStyle;
|
private ExecuteUpdateResultCheckStyle deleteCheckStyle;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addProperty(Property prop) {
|
public void addProperty(Property property) {
|
||||||
properties.add(prop);
|
properties.add( property );
|
||||||
declaredProperties.add(prop);
|
declaredProperties.add( property );
|
||||||
prop.setPersistentClass( getPersistentClass() );
|
property.setPersistentClass( getPersistentClass() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addMappedsuperclassProperty(Property prop) {
|
public void addMappedsuperclassProperty( Property property ) {
|
||||||
properties.add(prop);
|
properties.add( property );
|
||||||
prop.setPersistentClass( getPersistentClass() );
|
property.setPersistentClass( getPersistentClass() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Property> getDeclaredProperties() {
|
public List<Property> getDeclaredProperties() {
|
||||||
|
@ -72,8 +72,8 @@ public class Join implements AttributeContainer, Serializable {
|
||||||
return declaredProperties.iterator();
|
return declaredProperties.iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean containsProperty(Property prop) {
|
public boolean containsProperty(Property property) {
|
||||||
return properties.contains(prop);
|
return properties.contains( property );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated(since = "6.0")
|
@Deprecated(since = "6.0")
|
||||||
|
@ -84,6 +84,7 @@ public class Join implements AttributeContainer, Serializable {
|
||||||
public Table getTable() {
|
public Table getTable() {
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTable(Table table) {
|
public void setTable(Table table) {
|
||||||
this.table = table;
|
this.table = table;
|
||||||
}
|
}
|
||||||
|
@ -91,6 +92,7 @@ public class Join implements AttributeContainer, Serializable {
|
||||||
public KeyValue getKey() {
|
public KeyValue getKey() {
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setKey(KeyValue key) {
|
public void setKey(KeyValue key) {
|
||||||
this.key = key;
|
this.key = key;
|
||||||
}
|
}
|
||||||
|
@ -116,11 +118,11 @@ public class Join implements AttributeContainer, Serializable {
|
||||||
|
|
||||||
public void createPrimaryKey() {
|
public void createPrimaryKey() {
|
||||||
//Primary key constraint
|
//Primary key constraint
|
||||||
PrimaryKey pk = new PrimaryKey( table );
|
PrimaryKey primaryKey = new PrimaryKey( table );
|
||||||
pk.setName( PK_ALIAS.toAliasString( table.getName() ) );
|
primaryKey.setName( PK_ALIAS.toAliasString( table.getName() ) );
|
||||||
table.setPrimaryKey(pk);
|
table.setPrimaryKey(primaryKey);
|
||||||
|
|
||||||
pk.addColumns( getKey() );
|
primaryKey.addColumns( getKey() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getPropertySpan() {
|
public int getPropertySpan() {
|
||||||
|
@ -194,9 +196,8 @@ public class Join implements AttributeContainer, Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isLazy() {
|
public boolean isLazy() {
|
||||||
Iterator<Property> iter = getPropertyIterator();
|
for ( Property property : properties ) {
|
||||||
while ( iter.hasNext() ) {
|
if ( !property.isLazy() ) {
|
||||||
if ( !iter.next().isLazy() ) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ package org.hibernate.mapping;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -26,19 +25,24 @@ import org.hibernate.boot.spi.ClassLoaderAccess;
|
||||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||||
import org.hibernate.engine.OptimisticLockStyle;
|
import org.hibernate.engine.OptimisticLockStyle;
|
||||||
import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
|
import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
|
||||||
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.internal.FilterConfiguration;
|
import org.hibernate.internal.FilterConfiguration;
|
||||||
import org.hibernate.internal.util.StringHelper;
|
|
||||||
import org.hibernate.internal.util.collections.JoinedIterator;
|
import org.hibernate.internal.util.collections.JoinedIterator;
|
||||||
import org.hibernate.internal.util.collections.JoinedList;
|
import org.hibernate.internal.util.collections.JoinedList;
|
||||||
import org.hibernate.internal.util.collections.SingletonIterator;
|
import org.hibernate.internal.util.collections.SingletonIterator;
|
||||||
|
import org.hibernate.metamodel.MappingMetamodel;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.jpa.event.spi.CallbackDefinition;
|
import org.hibernate.jpa.event.spi.CallbackDefinition;
|
||||||
import org.hibernate.service.ServiceRegistry;
|
import org.hibernate.service.ServiceRegistry;
|
||||||
import org.hibernate.sql.Alias;
|
import org.hibernate.sql.Alias;
|
||||||
|
import org.hibernate.sql.Template;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
import org.hibernate.type.spi.TypeConfiguration;
|
||||||
|
|
||||||
import static java.util.Collections.emptyList;
|
import static java.util.Collections.emptyList;
|
||||||
import static java.util.Collections.unmodifiableList;
|
import static java.util.Collections.unmodifiableList;
|
||||||
|
import static java.util.Comparator.comparing;
|
||||||
|
import static org.hibernate.internal.util.StringHelper.qualify;
|
||||||
import static org.hibernate.internal.util.StringHelper.root;
|
import static org.hibernate.internal.util.StringHelper.root;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -98,6 +102,8 @@ public abstract class PersistentClass implements AttributeContainer, Serializabl
|
||||||
private Component identifierMapper;
|
private Component identifierMapper;
|
||||||
private List<CallbackDefinition> callbackDefinitions;
|
private List<CallbackDefinition> callbackDefinitions;
|
||||||
|
|
||||||
|
private final List<CheckConstraint> checkConstraints = new ArrayList<>();
|
||||||
|
|
||||||
// Custom SQL
|
// Custom SQL
|
||||||
private String customSQLInsert;
|
private String customSQLInsert;
|
||||||
private boolean customInsertCallable;
|
private boolean customInsertCallable;
|
||||||
|
@ -727,7 +733,7 @@ public abstract class PersistentClass implements AttributeContainer, Serializabl
|
||||||
final int actualColumns = prop.getColumnSpan();
|
final int actualColumns = prop.getColumnSpan();
|
||||||
final int requiredColumns = type.getColumnSpan( mapping );
|
final int requiredColumns = type.getColumnSpan( mapping );
|
||||||
throw new MappingException(
|
throw new MappingException(
|
||||||
"Property '" + StringHelper.qualify( getEntityName(), prop.getName() )
|
"Property '" + qualify( getEntityName(), prop.getName() )
|
||||||
+ "' maps to " + actualColumns + " columns but " + requiredColumns
|
+ "' maps to " + actualColumns + " columns but " + requiredColumns
|
||||||
+ " columns are required (type '" + type.getName()
|
+ " columns are required (type '" + type.getName()
|
||||||
+ "' spans " + requiredColumns + " columns)"
|
+ "' spans " + requiredColumns + " columns)"
|
||||||
|
@ -1219,7 +1225,52 @@ public abstract class PersistentClass implements AttributeContainer, Serializabl
|
||||||
// End of @MappedSuperclass support
|
// End of @MappedSuperclass support
|
||||||
|
|
||||||
public void prepareForMappingModel() {
|
public void prepareForMappingModel() {
|
||||||
properties.sort( Comparator.comparing( Property::getName ) );
|
properties.sort( comparing( Property::getName ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void mappingModelReady(MappingMetamodel mappingMetamodel) {
|
||||||
|
for ( CheckConstraint checkConstraint : checkConstraints ) {
|
||||||
|
final TypeConfiguration typeConfiguration = mappingMetamodel.getTypeConfiguration();
|
||||||
|
final SessionFactoryImplementor sessionFactory = typeConfiguration.getSessionFactory();
|
||||||
|
final List<String> constrainedColumnNames =
|
||||||
|
Template.collectColumnNames( checkConstraint.getConstraint(), typeConfiguration, sessionFactory );
|
||||||
|
final Table primary = getTable();
|
||||||
|
long matches = matchesInTable( constrainedColumnNames, primary );
|
||||||
|
if ( matches == constrainedColumnNames.size() ) {
|
||||||
|
// perfect, all columns matched in the primary table
|
||||||
|
primary.addCheck( checkConstraint );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// go searching for a secondary table which better matches
|
||||||
|
Table table = primary;
|
||||||
|
long max = matches;
|
||||||
|
for ( Join join : getJoins() ) {
|
||||||
|
final Table secondary = join.getTable();
|
||||||
|
long secondaryMatches = matchesInTable( constrainedColumnNames, secondary );
|
||||||
|
if ( secondaryMatches > max ) {
|
||||||
|
table = secondary;
|
||||||
|
max = secondaryMatches;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
table.addCheck( checkConstraint );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long matchesInTable(List<String> names, Table table) {
|
||||||
|
return table.getColumns().stream()
|
||||||
|
.filter( col -> col.isQuoted()
|
||||||
|
? names.contains( col.getName() )
|
||||||
|
: names.stream().anyMatch( name -> name.equalsIgnoreCase( col.getName() ) )
|
||||||
|
)
|
||||||
|
.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addCheckConstraint(CheckConstraint checkConstraint) {
|
||||||
|
checkConstraints.add( checkConstraint );
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<CheckConstraint> getCheckConstraints() {
|
||||||
|
return checkConstraints;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,7 @@ import org.jboss.logging.Logger;
|
||||||
import static java.util.Collections.emptyList;
|
import static java.util.Collections.emptyList;
|
||||||
import static java.util.Collections.unmodifiableList;
|
import static java.util.Collections.unmodifiableList;
|
||||||
import static java.util.Collections.unmodifiableMap;
|
import static java.util.Collections.unmodifiableMap;
|
||||||
|
import static java.util.stream.Collectors.toList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A mapping model object representing a relational database {@linkplain jakarta.persistence.Table table}.
|
* A mapping model object representing a relational database {@linkplain jakarta.persistence.Table table}.
|
||||||
|
@ -64,7 +65,7 @@ public class Table implements Serializable, ContributableDatabaseObject {
|
||||||
private final Map<String, Index> indexes = new LinkedHashMap<>();
|
private final Map<String, Index> indexes = new LinkedHashMap<>();
|
||||||
private final Map<String,UniqueKey> uniqueKeys = new LinkedHashMap<>();
|
private final Map<String,UniqueKey> uniqueKeys = new LinkedHashMap<>();
|
||||||
private int uniqueInteger;
|
private int uniqueInteger;
|
||||||
private final List<String> checkConstraints = new ArrayList<>();
|
private final List<CheckConstraint> checkConstraints = new ArrayList<>();
|
||||||
private String rowId;
|
private String rowId;
|
||||||
private String subselect;
|
private String subselect;
|
||||||
private boolean isAbstract;
|
private boolean isAbstract;
|
||||||
|
@ -593,8 +594,13 @@ public class Table implements Serializable, ContributableDatabaseObject {
|
||||||
return idValue;
|
return idValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated(since = "6.2")
|
||||||
public void addCheckConstraint(String constraint) {
|
public void addCheckConstraint(String constraint) {
|
||||||
checkConstraints.add( constraint );
|
addCheck( new CheckConstraint( constraint ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addCheck(CheckConstraint check) {
|
||||||
|
checkConstraints.add( check );
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean containsColumn(Column column) {
|
public boolean containsColumn(Column column) {
|
||||||
|
@ -672,7 +678,12 @@ public class Table implements Serializable, ContributableDatabaseObject {
|
||||||
return getCheckConstraints().iterator();
|
return getCheckConstraints().iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated(since = "6.2")
|
||||||
public List<String> getCheckConstraints() {
|
public List<String> getCheckConstraints() {
|
||||||
|
return checkConstraints.stream().map( CheckConstraint::getConstraint ).collect( toList() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<CheckConstraint> getChecks() {
|
||||||
return unmodifiableList( checkConstraints );
|
return unmodifiableList( checkConstraints );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -252,6 +252,9 @@ public class MappingMetamodelImpl implements MappingMetamodelImplementor, Metamo
|
||||||
bootModel.getNamedEntityGraphs().values(),
|
bootModel.getNamedEntityGraphs().values(),
|
||||||
runtimeModelCreationContext
|
runtimeModelCreationContext
|
||||||
);
|
);
|
||||||
|
|
||||||
|
bootModel.getEntityBindings().forEach( persistentClass -> persistentClass.mappingModelReady( this ) );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerEmbeddableMappingType(MetadataImplementor bootModel) {
|
private void registerEmbeddableMappingType(MetadataImplementor bootModel) {
|
||||||
|
|
|
@ -15,6 +15,7 @@ import java.util.StringTokenizer;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
|
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
|
||||||
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
|
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
|
||||||
import org.hibernate.type.spi.TypeConfiguration;
|
import org.hibernate.type.spi.TypeConfiguration;
|
||||||
|
@ -31,6 +32,8 @@ public final class Template {
|
||||||
private static final Set<String> KEYWORDS = new HashSet<>();
|
private static final Set<String> KEYWORDS = new HashSet<>();
|
||||||
private static final Set<String> BEFORE_TABLE_KEYWORDS = new HashSet<>();
|
private static final Set<String> BEFORE_TABLE_KEYWORDS = new HashSet<>();
|
||||||
private static final Set<String> FUNCTION_KEYWORDS = new HashSet<>();
|
private static final Set<String> FUNCTION_KEYWORDS = new HashSet<>();
|
||||||
|
public static final String PUNCTUATION = "=><!+-*/()',|&`";
|
||||||
|
|
||||||
static {
|
static {
|
||||||
KEYWORDS.add("and");
|
KEYWORDS.add("and");
|
||||||
KEYWORDS.add("or");
|
KEYWORDS.add("or");
|
||||||
|
@ -128,7 +131,7 @@ public final class Template {
|
||||||
// identifier references.
|
// identifier references.
|
||||||
|
|
||||||
String symbols = new StringBuilder()
|
String symbols = new StringBuilder()
|
||||||
.append( "=><!+-*/()',|&`" )
|
.append( PUNCTUATION )
|
||||||
.append( WHITESPACE )
|
.append( WHITESPACE )
|
||||||
.append( dialect.openQuote() )
|
.append( dialect.openQuote() )
|
||||||
.append( dialect.closeQuote() )
|
.append( dialect.closeQuote() )
|
||||||
|
@ -358,6 +361,40 @@ public final class Template {
|
||||||
return result.toString();
|
return result.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<String> collectColumnNames(
|
||||||
|
String checkConstraint,
|
||||||
|
TypeConfiguration typeConfiguration,
|
||||||
|
SessionFactoryImplementor sessionFactory) {
|
||||||
|
final String template = renderWhereStringTemplate(
|
||||||
|
checkConstraint,
|
||||||
|
sessionFactory.getJdbcServices().getDialect(),
|
||||||
|
typeConfiguration,
|
||||||
|
sessionFactory.getQueryEngine().getSqmFunctionRegistry()
|
||||||
|
);
|
||||||
|
final List<String> names = new ArrayList<>();
|
||||||
|
int begin = 0;
|
||||||
|
int match;
|
||||||
|
while ( ( match = template.indexOf(TEMPLATE, begin) ) >= 0 ) {
|
||||||
|
int start = match + TEMPLATE.length() + 1;
|
||||||
|
for ( int loc = start;; loc++ ) {
|
||||||
|
if ( loc == template.length() - 1 ) {
|
||||||
|
names.add( template.substring( start ) );
|
||||||
|
begin = template.length();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
char ch = template.charAt( loc );
|
||||||
|
if ( PUNCTUATION.indexOf(ch) >= 0 || WHITESPACE.indexOf(ch) >= 0 ) {
|
||||||
|
names.add( template.substring( start, loc ) );
|
||||||
|
begin = loc;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
// /**
|
// /**
|
||||||
// * Takes the where condition provided in the mapping attribute and interpolates the alias.
|
// * Takes the where condition provided in the mapping attribute and interpolates the alias.
|
||||||
// * Handles sub-selects, quoted identifiers, quoted strings, expressions, SQL functions,
|
// * Handles sub-selects, quoted identifiers, quoted strings, expressions, SQL functions,
|
||||||
|
|
|
@ -101,7 +101,7 @@ class ColumnDefinitions {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( dialect.supportsColumnCheck() && column.hasCheckConstraint() ) {
|
if ( dialect.supportsColumnCheck() && column.hasCheckConstraint() ) {
|
||||||
definition.append( column.checkConstraint() );
|
definition.append( column.getCheck().constraintString() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ import org.hibernate.boot.model.relational.SqlStringGenerationContext;
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.dialect.aggregate.AggregateSupport;
|
import org.hibernate.dialect.aggregate.AggregateSupport;
|
||||||
import org.hibernate.mapping.AggregateColumn;
|
import org.hibernate.mapping.AggregateColumn;
|
||||||
|
import org.hibernate.mapping.CheckConstraint;
|
||||||
import org.hibernate.mapping.Column;
|
import org.hibernate.mapping.Column;
|
||||||
import org.hibernate.mapping.Component;
|
import org.hibernate.mapping.Component;
|
||||||
import org.hibernate.mapping.Property;
|
import org.hibernate.mapping.Property;
|
||||||
|
@ -151,8 +152,8 @@ public class StandardTableExporter implements Exporter<Table> {
|
||||||
|
|
||||||
protected void applyTableCheck(Table table, StringBuilder buf) {
|
protected void applyTableCheck(Table table, StringBuilder buf) {
|
||||||
if ( dialect.supportsTableCheck() ) {
|
if ( dialect.supportsTableCheck() ) {
|
||||||
for ( String constraint : table.getCheckConstraints() ) {
|
for ( CheckConstraint constraint : table.getChecks() ) {
|
||||||
buf.append( ", check (" ).append( constraint ).append( ')' );
|
buf.append( "," ).append( constraint.constraintString() );
|
||||||
}
|
}
|
||||||
final AggregateSupport aggregateSupport = dialect.getAggregateSupport();
|
final AggregateSupport aggregateSupport = dialect.getAggregateSupport();
|
||||||
if ( aggregateSupport != null && aggregateSupport.supportsComponentCheckConstraints() ) {
|
if ( aggregateSupport != null && aggregateSupport.supportsComponentCheckConstraints() ) {
|
||||||
|
@ -231,7 +232,8 @@ public class StandardTableExporter implements Exporter<Table> {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for ( Column subColumn : value.getColumns() ) {
|
for ( Column subColumn : value.getColumns() ) {
|
||||||
final String checkConstraint = subColumn.getCheckConstraint();
|
final CheckConstraint check = subColumn.getCheck();
|
||||||
|
final String checkConstraint = check == null ? null : check.getConstraint();
|
||||||
if ( !subColumn.isNullable() || checkConstraint != null ) {
|
if ( !subColumn.isNullable() || checkConstraint != null ) {
|
||||||
final String subColumnName = subColumn.getQuotedName( dialect );
|
final String subColumnName = subColumn.getQuotedName( dialect );
|
||||||
final String columnExpression = aggregateSupport.aggregateComponentCustomReadExpression(
|
final String columnExpression = aggregateSupport.aggregateComponentCustomReadExpression(
|
||||||
|
|
Loading…
Reference in New Issue