HHH-12423 - SecondaryTable is not taking into account the schema while mapping the entity

This commit is contained in:
Vlad Mihalcea 2018-03-22 16:12:45 +02:00 committed by Steve Ebersole
parent a2a52c32e5
commit 511a5a3618
4 changed files with 178 additions and 12 deletions

View File

@ -48,6 +48,7 @@ import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject;
import org.hibernate.boot.model.relational.Database;
import org.hibernate.boot.model.relational.ExportableProducer;
import org.hibernate.boot.model.relational.Namespace;
import org.hibernate.boot.model.relational.QualifiedTableName;
import org.hibernate.boot.model.source.internal.ImplicitColumnNamingSecondPass;
import org.hibernate.boot.model.source.spi.LocalMetadataBuildingContext;
import org.hibernate.boot.spi.InFlightMetadataCollector;
@ -1400,8 +1401,17 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
}
@Override
public void addSecondaryTable(Identifier logicalName, Join secondaryTableJoin) {
if ( Identifier.areEqual( primaryTableLogicalName, logicalName ) ) {
public void addSecondaryTable(QualifiedTableName logicalQualifiedTableName, Join secondaryTableJoin) {
Identifier logicalName = logicalQualifiedTableName.getTableName();
if ( Identifier.areEqual(
Identifier.toIdentifier(
new QualifiedTableName(
Identifier.toIdentifier( primaryTable.getCatalog() ),
Identifier.toIdentifier( primaryTable.getSchema() ),
primaryTableLogicalName
).render()
),
Identifier.toIdentifier( logicalQualifiedTableName.render() ) ) ) {
throw new DuplicateSecondaryTableException( logicalName );
}

View File

@ -26,6 +26,7 @@ import org.hibernate.boot.model.convert.spi.ConverterDescriptor;
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject;
import org.hibernate.boot.model.relational.Database;
import org.hibernate.boot.model.relational.QualifiedTableName;
import org.hibernate.boot.model.source.spi.LocalMetadataBuildingContext;
import org.hibernate.cfg.AnnotatedClassType;
import org.hibernate.cfg.AttributeConverterDefinition;
@ -323,7 +324,7 @@ public interface InFlightMetadataCollector extends Mapping, MetadataImplementor
interface EntityTableXref {
void addSecondaryTable(LocalMetadataBuildingContext buildingContext, Identifier logicalName, Join secondaryTableJoin);
void addSecondaryTable(Identifier logicalName, Join secondaryTableJoin);
void addSecondaryTable(QualifiedTableName logicalName, Join secondaryTableJoin);
Table resolveTable(Identifier tableName);
Table getPrimaryTable();
Join locateJoin(Identifier tableName);

View File

@ -64,6 +64,7 @@ import org.hibernate.boot.model.naming.EntityNaming;
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.ImplicitEntityNameSource;
import org.hibernate.boot.model.naming.NamingStrategyHelper;
import org.hibernate.boot.model.relational.QualifiedTableName;
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
import org.hibernate.boot.spi.InFlightMetadataCollector;
import org.hibernate.boot.spi.MetadataBuildingContext;
@ -1111,26 +1112,34 @@ public class EntityBinder {
final Object joinColumns;
final List<UniqueConstraintHolder> uniqueConstraintHolders;
final Identifier logicalName;
final QualifiedTableName logicalName;
if ( secondaryTable != null ) {
schema = secondaryTable.schema();
catalog = secondaryTable.catalog();
logicalName = context.getMetadataCollector()
logicalName = new QualifiedTableName(
Identifier.toIdentifier( catalog ),
Identifier.toIdentifier( schema ),
context.getMetadataCollector()
.getDatabase()
.getJdbcEnvironment()
.getIdentifierHelper()
.toIdentifier( secondaryTable.name() );
.toIdentifier( secondaryTable.name() )
);
joinColumns = secondaryTable.pkJoinColumns();
uniqueConstraintHolders = TableBinder.buildUniqueConstraintHolders( secondaryTable.uniqueConstraints() );
}
else if ( joinTable != null ) {
schema = joinTable.schema();
catalog = joinTable.catalog();
logicalName = context.getMetadataCollector()
.getDatabase()
.getJdbcEnvironment()
.getIdentifierHelper()
.toIdentifier( joinTable.name() );
logicalName = new QualifiedTableName(
Identifier.toIdentifier( catalog ),
Identifier.toIdentifier( schema ),
context.getMetadataCollector()
.getDatabase()
.getJdbcEnvironment()
.getIdentifierHelper()
.toIdentifier( joinTable.name() )
);
joinColumns = joinTable.joinColumns();
uniqueConstraintHolders = TableBinder.buildUniqueConstraintHolders( joinTable.uniqueConstraints() );
}
@ -1141,7 +1150,7 @@ public class EntityBinder {
final Table table = TableBinder.buildAndFillTable(
schema,
catalog,
logicalName,
logicalName.getTableName(),
false,
uniqueConstraintHolders,
null,

View File

@ -0,0 +1,146 @@
/*
* 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.test.annotations.secondarytable;
import java.io.Serializable;
import java.net.URL;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.ForeignKey;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.SecondaryTable;
import javax.persistence.Table;
import org.hibernate.Criteria;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.OptimisticLockType;
import org.hibernate.annotations.OptimisticLocking;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.testing.RequiresDialect;
import org.hibernate.testing.transaction.TransactionUtil;
import org.hibernate.test.schemaupdate.foreignkeys.definition.AbstractForeignKeyDefinitionTest;
import org.junit.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
import static org.junit.Assert.assertTrue;
/**
* @author Vlad Mihalcea
*/
@RequiresDialect(value = H2Dialect.class)
public class SecondaryTableSchemaTest
extends BaseEntityManagerFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
Cluster.class,
};
}
protected void addConfigOptions(Map options) {
options.put(
AvailableSettings.URL,
options.get( AvailableSettings.URL ) + ";INIT=CREATE SCHEMA IF NOT EXISTS schema1\\;CREATE SCHEMA IF NOT EXISTS schema2;"
);
}
@Test
public void test() {
doInJPA( this::entityManagerFactory, entityManager -> {
List<Cluster> clusters = entityManager.createQuery( "select c from Cluster c" ).getResultList();
assertTrue(clusters.isEmpty());
} );
}
@Entity(name = "Cluster")
@Table(name = "cluster", schema = "schema1")
@SecondaryTable(name = "Cluster", schema="schema2", pkJoinColumns = { @PrimaryKeyJoinColumn(name = "clusterid") })
@org.hibernate.annotations.Table(appliesTo = "Cluster", optional = false)
@OptimisticLocking(type = OptimisticLockType.DIRTY)
@DynamicUpdate
public static class Cluster implements Serializable {
private static final long serialVersionUID = 3965099001305947412L;
@Id
@Column(name = "objid")
private Long id;
private String uuid;
private String resourceKey;
private String name;
@Column(name = "lastSync", table = "Cluster")
private Long lastSync;
@Column(name = "healthStatus", table = "Cluster")
private Integer healthStatus;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getResourceKey() {
return resourceKey;
}
public void setResourceKey(String resourceKey) {
this.resourceKey = resourceKey;
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
public Long getLastSync() {
return lastSync;
}
public void setLastSync(Long lastSync) {
this.lastSync = lastSync;
}
public Integer getHealthStatus() {
return healthStatus;
}
public void setHealthStatus(Integer healthStatus) {
this.healthStatus = healthStatus;
}
}
}