HHH-6287 Bind @UniqueConstraint
This commit is contained in:
parent
77e555ff05
commit
632150ad72
|
@ -108,6 +108,7 @@ public class MultipleHiLoPerTableGenerator implements PersistentIdentifierGenera
|
||||||
private Identifier qualifiedValueColumnName;
|
private Identifier qualifiedValueColumnName;
|
||||||
|
|
||||||
private String tableName;
|
private String tableName;
|
||||||
|
private Table table;
|
||||||
private String pkColumnName;
|
private String pkColumnName;
|
||||||
private String valueColumnName;
|
private String valueColumnName;
|
||||||
|
|
||||||
|
@ -129,6 +130,15 @@ public class MultipleHiLoPerTableGenerator implements PersistentIdentifierGenera
|
||||||
return tableName;
|
return tableName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bound Table for this generator.
|
||||||
|
*
|
||||||
|
* @return The table.
|
||||||
|
*/
|
||||||
|
public final Table getTable() {
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized Serializable generate(final SessionImplementor session, Object obj) {
|
public synchronized Serializable generate(final SessionImplementor session, Object obj) {
|
||||||
final WorkExecutorVisitable<IntegralDataTypeHolder> work = new AbstractReturningWork<IntegralDataTypeHolder>() {
|
final WorkExecutorVisitable<IntegralDataTypeHolder> work = new AbstractReturningWork<IntegralDataTypeHolder>() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -279,7 +289,7 @@ public class MultipleHiLoPerTableGenerator implements PersistentIdentifierGenera
|
||||||
final Dialect dialect = database.getJdbcEnvironment().getDialect();
|
final Dialect dialect = database.getJdbcEnvironment().getDialect();
|
||||||
|
|
||||||
final Schema schema = database.getSchemaFor( qualifiedTableName );
|
final Schema schema = database.getSchemaFor( qualifiedTableName );
|
||||||
final Table table = schema.createTable( qualifiedTableName.getName(), qualifiedTableName.getName() );
|
table = schema.createTable( qualifiedTableName.getName(), qualifiedTableName.getName() );
|
||||||
|
|
||||||
final Column pkColumn = table.createColumn( qualifiedPkColumnName );
|
final Column pkColumn = table.createColumn( qualifiedPkColumnName );
|
||||||
table.getPrimaryKey().addColumn( pkColumn );
|
table.getPrimaryKey().addColumn( pkColumn );
|
||||||
|
|
|
@ -33,8 +33,6 @@ import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.LockOptions;
|
import org.hibernate.LockOptions;
|
||||||
|
@ -58,7 +56,9 @@ import org.hibernate.metamodel.spi.relational.Column;
|
||||||
import org.hibernate.metamodel.spi.relational.Database;
|
import org.hibernate.metamodel.spi.relational.Database;
|
||||||
import org.hibernate.metamodel.spi.relational.Identifier;
|
import org.hibernate.metamodel.spi.relational.Identifier;
|
||||||
import org.hibernate.metamodel.spi.relational.ObjectName;
|
import org.hibernate.metamodel.spi.relational.ObjectName;
|
||||||
|
import org.hibernate.metamodel.spi.relational.Table;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An enhanced version of table-based id generation.
|
* An enhanced version of table-based id generation.
|
||||||
|
@ -170,6 +170,7 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab
|
||||||
private Identifier qualifiedValueColumnName;
|
private Identifier qualifiedValueColumnName;
|
||||||
|
|
||||||
private String tableName;
|
private String tableName;
|
||||||
|
private Table table;
|
||||||
|
|
||||||
private String segmentColumnName;
|
private String segmentColumnName;
|
||||||
private String segmentValue;
|
private String segmentValue;
|
||||||
|
@ -209,6 +210,15 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab
|
||||||
return tableName;
|
return tableName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bound Table for this generator.
|
||||||
|
*
|
||||||
|
* @return The table.
|
||||||
|
*/
|
||||||
|
public final Table getTable() {
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the column in which we store the segment to which each row
|
* The name of the column in which we store the segment to which each row
|
||||||
* belongs. The value here acts as PK.
|
* belongs. The value here acts as PK.
|
||||||
|
@ -563,7 +573,7 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab
|
||||||
public void registerExportables(Database database) {
|
public void registerExportables(Database database) {
|
||||||
final Dialect dialect = database.getJdbcEnvironment().getDialect();
|
final Dialect dialect = database.getJdbcEnvironment().getDialect();
|
||||||
|
|
||||||
org.hibernate.metamodel.spi.relational.Table table = database.getSchemaFor( qualifiedTableName )
|
table = database.getSchemaFor( qualifiedTableName )
|
||||||
.createTable( qualifiedTableName.getName(), qualifiedTableName.getName() );
|
.createTable( qualifiedTableName.getName(), qualifiedTableName.getName() );
|
||||||
|
|
||||||
Column segmentColumn = table.createColumn( qualifiedSegmentColumnName );
|
Column segmentColumn = table.createColumn( qualifiedSegmentColumnName );
|
||||||
|
|
|
@ -25,7 +25,6 @@ package org.hibernate.metamodel.internal;
|
||||||
|
|
||||||
import static org.hibernate.engine.spi.SyntheticAttributeHelper.SYNTHETIC_COMPOSITE_ID_ATTRIBUTE_NAME;
|
import static org.hibernate.engine.spi.SyntheticAttributeHelper.SYNTHETIC_COMPOSITE_ID_ATTRIBUTE_NAME;
|
||||||
|
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
@ -56,7 +55,9 @@ import org.hibernate.engine.spi.FilterDefinition;
|
||||||
import org.hibernate.id.EntityIdentifierNature;
|
import org.hibernate.id.EntityIdentifierNature;
|
||||||
import org.hibernate.id.IdentifierGenerator;
|
import org.hibernate.id.IdentifierGenerator;
|
||||||
import org.hibernate.id.IdentityGenerator;
|
import org.hibernate.id.IdentityGenerator;
|
||||||
|
import org.hibernate.id.MultipleHiLoPerTableGenerator;
|
||||||
import org.hibernate.id.PersistentIdentifierGenerator;
|
import org.hibernate.id.PersistentIdentifierGenerator;
|
||||||
|
import org.hibernate.id.enhanced.TableGenerator;
|
||||||
import org.hibernate.id.factory.IdentifierGeneratorFactory;
|
import org.hibernate.id.factory.IdentifierGeneratorFactory;
|
||||||
import org.hibernate.internal.CoreMessageLogger;
|
import org.hibernate.internal.CoreMessageLogger;
|
||||||
import org.hibernate.internal.FilterConfiguration;
|
import org.hibernate.internal.FilterConfiguration;
|
||||||
|
@ -2887,7 +2888,8 @@ public class Binder {
|
||||||
if ( UniqueConstraintSource.class.isInstance( constraintSource ) ) {
|
if ( UniqueConstraintSource.class.isInstance( constraintSource ) ) {
|
||||||
UniqueKey uk = new UniqueKey();
|
UniqueKey uk = new UniqueKey();
|
||||||
|
|
||||||
final TableSpecification table = entityBinding.locateTable( constraintSource.getTableName() );
|
TableSpecification table = findUniqueConstraintTable( entityBinding, constraintSource.getTableName() );
|
||||||
|
|
||||||
final List<String> columnNames = constraintSource.columnNames();
|
final List<String> columnNames = constraintSource.columnNames();
|
||||||
final String constraintName = StringHelper.isEmpty( constraintSource.name() )
|
final String constraintName = StringHelper.isEmpty( constraintSource.name() )
|
||||||
? UniqueKey.generateName( table, columnNames.toArray( new String[columnNames.size()] ) )
|
? UniqueKey.generateName( table, columnNames.toArray( new String[columnNames.size()] ) )
|
||||||
|
@ -2901,6 +2903,52 @@ public class Binder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private TableSpecification findUniqueConstraintTable(EntityBinding entityBinding, String tableName) {
|
||||||
|
try {
|
||||||
|
return entityBinding.locateTable( tableName );
|
||||||
|
}
|
||||||
|
catch ( AssertionFailure e ) {
|
||||||
|
Identifier identifier = Identifier.toIdentifier( tableName );
|
||||||
|
|
||||||
|
// TODO: Make TableGenerator & MultipleHiLoPerTableGenerator extend an abstract?
|
||||||
|
// @TableGenerator
|
||||||
|
IdentifierGenerator idGenerator = entityBinding.getHierarchyDetails().getEntityIdentifier().getIdentifierGenerator();
|
||||||
|
if (idGenerator instanceof TableGenerator) {
|
||||||
|
Table generatorTable = ((TableGenerator) idGenerator).getTable();
|
||||||
|
if (generatorTable != null && generatorTable.getLogicalName().equals( identifier ) ) {
|
||||||
|
return generatorTable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (idGenerator instanceof MultipleHiLoPerTableGenerator) {
|
||||||
|
Table generatorTable = ((MultipleHiLoPerTableGenerator) idGenerator).getTable();
|
||||||
|
if (generatorTable != null && generatorTable.getLogicalName().equals( identifier ) ) {
|
||||||
|
return generatorTable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// @JoinTable and @CollectionTable
|
||||||
|
Iterator<AttributeBinding> attributeBindings = entityBinding.attributeBindings().iterator();
|
||||||
|
while (attributeBindings.hasNext()) {
|
||||||
|
AttributeBinding attributeBinding = attributeBindings.next();
|
||||||
|
if (attributeBinding instanceof PluralAttributeBinding) {
|
||||||
|
PluralAttributeBinding pluralAttributeBinding = (PluralAttributeBinding) attributeBinding;
|
||||||
|
|
||||||
|
TableSpecification pluralTable = pluralAttributeBinding.getPluralAttributeKeyBinding().getCollectionTable();
|
||||||
|
if (pluralTable != null && pluralTable.getLogicalName().equals( identifier ) ) {
|
||||||
|
return pluralTable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new AssertionFailure(
|
||||||
|
String.format(
|
||||||
|
"Unable to find locate table %s",
|
||||||
|
tableName
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private List<RelationalValueBinding> bindValues(
|
private List<RelationalValueBinding> bindValues(
|
||||||
final AttributeBindingContainer attributeBindingContainer,
|
final AttributeBindingContainer attributeBindingContainer,
|
||||||
|
|
|
@ -331,6 +331,36 @@ public class EntitySourceImpl implements EntitySource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( entityClass.hostsAnnotation( JPADotNames.COLLECTION_TABLE ) ) {
|
||||||
|
List<AnnotationInstance> collectionTables = JandexHelper.getAnnotations(
|
||||||
|
entityClass.getClassInfo(), JPADotNames.COLLECTION_TABLE );
|
||||||
|
for (AnnotationInstance collectionTable : collectionTables) {
|
||||||
|
String tableName = JandexHelper.getValue( collectionTable, "name", String.class );
|
||||||
|
addUniqueConstraints( constraintSources, collectionTable, tableName );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( entityClass.hostsAnnotation( JPADotNames.JOIN_TABLE ) ) {
|
||||||
|
List<AnnotationInstance> joinTables = JandexHelper.getAnnotations(
|
||||||
|
entityClass.getClassInfo(), JPADotNames.JOIN_TABLE );
|
||||||
|
for (AnnotationInstance joinTable : joinTables) {
|
||||||
|
String tableName = JandexHelper.getValue( joinTable, "name", String.class );
|
||||||
|
addUniqueConstraints( constraintSources, joinTable, tableName );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( entityClass.hostsAnnotation( JPADotNames.TABLE_GENERATOR ) ) {
|
||||||
|
List<AnnotationInstance> tableGenerators = JandexHelper.getAnnotations(
|
||||||
|
entityClass.getClassInfo(), JPADotNames.TABLE_GENERATOR );
|
||||||
|
for (AnnotationInstance tableGenerator : tableGenerators) {
|
||||||
|
String tableName = JandexHelper.getValue( tableGenerator, "table", String.class );
|
||||||
|
addUniqueConstraints( constraintSources, tableGenerator, tableName );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
return constraintSources;
|
return constraintSources;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,44 +24,66 @@
|
||||||
|
|
||||||
package org.hibernate.metamodel.internal.source.annotations.entity;
|
package org.hibernate.metamodel.internal.source.annotations.entity;
|
||||||
|
|
||||||
import javax.persistence.Entity;
|
|
||||||
import javax.persistence.Id;
|
|
||||||
import javax.persistence.Table;
|
|
||||||
import javax.persistence.UniqueConstraint;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import org.hibernate.metamodel.spi.binding.EntityBinding;
|
|
||||||
import org.hibernate.metamodel.spi.relational.TableSpecification;
|
|
||||||
import org.hibernate.metamodel.spi.relational.UniqueKey;
|
|
||||||
import org.hibernate.testing.junit4.BaseAnnotationBindingTestCase;
|
|
||||||
import org.hibernate.testing.junit4.Resources;
|
|
||||||
|
|
||||||
import static junit.framework.Assert.assertEquals;
|
import static junit.framework.Assert.assertEquals;
|
||||||
import static junit.framework.Assert.assertNotNull;
|
import static junit.framework.Assert.assertNotNull;
|
||||||
import static junit.framework.Assert.assertTrue;
|
import static junit.framework.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.persistence.CollectionTable;
|
||||||
|
import javax.persistence.ElementCollection;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.GenerationType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.JoinTable;
|
||||||
|
import javax.persistence.ManyToMany;
|
||||||
|
import javax.persistence.OrderColumn;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import javax.persistence.TableGenerator;
|
||||||
|
import javax.persistence.UniqueConstraint;
|
||||||
|
|
||||||
|
import org.hibernate.id.MultipleHiLoPerTableGenerator;
|
||||||
|
import org.hibernate.metamodel.spi.binding.EntityBinding;
|
||||||
|
import org.hibernate.metamodel.spi.relational.TableSpecification;
|
||||||
|
import org.hibernate.metamodel.spi.relational.UniqueKey;
|
||||||
|
import org.hibernate.test.util.SchemaUtil;
|
||||||
|
import org.hibernate.testing.junit4.BaseAnnotationBindingTestCase;
|
||||||
|
import org.hibernate.testing.junit4.Resources;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* test for {@link javax.persistence.UniqueConstraint}
|
* test for {@link javax.persistence.UniqueConstraint}
|
||||||
*
|
*
|
||||||
* @author Strong Liu
|
* @author Strong Liu
|
||||||
|
* @author Brett Meyer
|
||||||
*/
|
*/
|
||||||
public class UniqueConstraintBindingTest extends BaseAnnotationBindingTestCase {
|
public class UniqueConstraintBindingTest extends BaseAnnotationBindingTestCase {
|
||||||
@Test
|
@Test
|
||||||
@Resources(annotatedClasses = TableWithUniqueConstraint.class)
|
@Resources(annotatedClasses = { TableWithUniqueConstraint.class, SecondTable.class })
|
||||||
public void testTableUniqueConstraints() {
|
public void testTableUniqueConstraints() {
|
||||||
EntityBinding binding = getEntityBinding( TableWithUniqueConstraint.class );
|
EntityBinding binding = getEntityBinding( TableWithUniqueConstraint.class );
|
||||||
TableSpecification table = binding.getPrimaryTable();
|
testTableUniqueConstraints( binding.getPrimaryTable(), "u1", 2 );
|
||||||
|
testTableUniqueConstraints( ( (MultipleHiLoPerTableGenerator) binding.getHierarchyDetails()
|
||||||
|
.getEntityIdentifier().getIdentifierGenerator() ).getTable(), "u2", 1 );
|
||||||
|
testTableUniqueConstraints( SchemaUtil.getCollection( TableWithUniqueConstraint.class, "secondTables", meta )
|
||||||
|
.getPluralAttributeKeyBinding().getCollectionTable(), "u3", 2 );
|
||||||
|
testTableUniqueConstraints( SchemaUtil.getCollection( TableWithUniqueConstraint.class, "elements", meta )
|
||||||
|
.getPluralAttributeKeyBinding().getCollectionTable(), "u4", 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testTableUniqueConstraints(TableSpecification table, String ukName, int ukNumColumns) {
|
||||||
Iterable<UniqueKey> uniqueKeyIterable = table.getUniqueKeys();
|
Iterable<UniqueKey> uniqueKeyIterable = table.getUniqueKeys();
|
||||||
assertNotNull( uniqueKeyIterable );
|
assertNotNull( uniqueKeyIterable );
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for ( UniqueKey key : uniqueKeyIterable ) {
|
for ( UniqueKey key : uniqueKeyIterable ) {
|
||||||
i++;
|
i++;
|
||||||
assertEquals( "u1", key.getName() );
|
assertEquals( ukName, key.getName() );
|
||||||
assertTrue( table == key.getTable() );
|
assertTrue( table == key.getTable() );
|
||||||
assertNotNull( key.getColumns() );
|
assertNotNull( key.getColumns() );
|
||||||
assertEquals( "There should be two columns in the unique constraint", 2, key.getColumns().size() );
|
assertEquals( "There should be two columns in the unique constraint", ukNumColumns, key.getColumns().size() );
|
||||||
assertEquals( "There should be two columns in the unique constraint", 2, key.getColumnSpan() );
|
assertEquals( "There should be two columns in the unique constraint", ukNumColumns, key.getColumnSpan() );
|
||||||
}
|
}
|
||||||
assertEquals( "There should only be one unique constraint", 1, i );
|
assertEquals( "There should only be one unique constraint", 1, i );
|
||||||
}
|
}
|
||||||
|
@ -70,8 +92,36 @@ public class UniqueConstraintBindingTest extends BaseAnnotationBindingTestCase {
|
||||||
@Table(uniqueConstraints = { @UniqueConstraint(name = "u1", columnNames = { "name", "age" }) })
|
@Table(uniqueConstraints = { @UniqueConstraint(name = "u1", columnNames = { "name", "age" }) })
|
||||||
class TableWithUniqueConstraint {
|
class TableWithUniqueConstraint {
|
||||||
@Id
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.TABLE, generator = "fooGenerator")
|
||||||
|
@TableGenerator(name = "fooGenerator", table = "foo_generator_table", valueColumnName = "fooGeneratorValue", uniqueConstraints = @UniqueConstraint(columnNames = "fooGeneratorValue", name = "u2"))
|
||||||
int id;
|
int id;
|
||||||
|
|
||||||
String name;
|
String name;
|
||||||
|
|
||||||
int age;
|
int age;
|
||||||
|
|
||||||
|
@ManyToMany
|
||||||
|
@JoinTable(name = "JoinTable", joinColumns = @JoinColumn(name = "secondTable"), inverseJoinColumns = @JoinColumn(name = "tableWithUniqueConstraint"), uniqueConstraints = @UniqueConstraint(columnNames = {
|
||||||
|
"secondTable", "tableWithUniqueConstraint" }, name = "u3"))
|
||||||
|
Set<SecondTable> secondTables;
|
||||||
|
|
||||||
|
@ElementCollection
|
||||||
|
@CollectionTable(name = "CollectionTable", joinColumns = @JoinColumn(name = "element"), uniqueConstraints = @UniqueConstraint(columnNames = "element", name = "u4"))
|
||||||
|
@OrderColumn(name = "element_index")
|
||||||
|
public int[] elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
class SecondTable {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
int id;
|
||||||
|
|
||||||
|
String name;
|
||||||
|
|
||||||
|
int age;
|
||||||
|
|
||||||
|
@ManyToMany(mappedBy = "secondTables")
|
||||||
|
Set<TableWithUniqueConstraint> tableWithUniqueConstraint;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue