HHH-6287 Bind @UniqueConstraint

This commit is contained in:
Brett Meyer 2013-06-10 16:49:12 -04:00
parent 77e555ff05
commit 632150ad72
5 changed files with 173 additions and 25 deletions

View File

@ -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 );

View File

@ -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 );

View File

@ -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,

View File

@ -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;
} }

View File

@ -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;
} }
} }