Implement Composite Foreign Key for EmbeddedId
This commit is contained in:
parent
903bb292e7
commit
7f4c25095e
|
@ -98,7 +98,6 @@ class DatabaseSnapshotExecutor {
|
|||
);
|
||||
final List<DomainResult> domainResults = new ArrayList<>();
|
||||
|
||||
final NavigablePath idPath = rootPath.append( EntityIdentifierMapping.ROLE_LOCAL_NAME );
|
||||
entityDescriptor.getIdentifierMapping().visitColumns(
|
||||
(tab, col, jdbcMapping) -> {
|
||||
final TableReference tableReference = rootTableGroup.resolveTableReference( tab );
|
||||
|
|
|
@ -28,6 +28,7 @@ import org.hibernate.internal.FilterHelper.TransformResult;
|
|||
import org.hibernate.loader.ast.spi.Loadable;
|
||||
import org.hibernate.loader.ast.spi.Loader;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
|
@ -477,8 +478,11 @@ public class LoaderSelectBuilder {
|
|||
LoaderSqlAstCreationState creationState,
|
||||
List<Fetch> fetches) {
|
||||
return (fetchable, isKeyFetchable) -> {
|
||||
|
||||
final NavigablePath fetchablePath = fetchParent.getNavigablePath().append( fetchable.getFetchableName() );
|
||||
NavigablePath navigablePath = fetchParent.getNavigablePath();
|
||||
if ( isKeyFetchable ) {
|
||||
navigablePath = navigablePath.append( EntityIdentifierMapping.ROLE_LOCAL_NAME );
|
||||
}
|
||||
final NavigablePath fetchablePath = navigablePath.append( fetchable.getFetchableName() );
|
||||
|
||||
final Fetch biDirectionalFetch = fetchable.resolveCircularFetch(
|
||||
fetchablePath,
|
||||
|
|
|
@ -155,7 +155,9 @@ public class LoaderSqlAstCreationState
|
|||
if ( tableGroup.getNavigablePath().equals( navigablePath ) ) {
|
||||
return tableGroup;
|
||||
}
|
||||
if(tableGroup.getNavigablePath().getIdentifierForTableGroup().equals( navigablePath.getIdentifierForTableGroup() )){
|
||||
if ( tableGroup.getNavigablePath()
|
||||
.getIdentifierForTableGroup()
|
||||
.equals( navigablePath.getIdentifierForTableGroup() ) ) {
|
||||
return tableGroup;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.hibernate.loader.internal.AliasConstantsHelper;
|
|||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
|
||||
import org.hibernate.sql.Template;
|
||||
import org.hibernate.type.ComponentType;
|
||||
import org.hibernate.type.EntityType;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
|
@ -245,7 +246,10 @@ public class Column implements Selectable, Serializable, Cloneable {
|
|||
&& size.getScale() == null && size.getPrecision() == null ) {
|
||||
if ( type instanceof EntityType ) {
|
||||
//ManyToOneType doesn't implement JdbcMapping
|
||||
type = mapping.getIdentifierType( ((EntityType) type).getAssociatedEntityName() );
|
||||
type = mapping.getIdentifierType( ( (EntityType) type ).getAssociatedEntityName() );
|
||||
if ( type instanceof ComponentType ) {
|
||||
type = ( (ComponentType) type ).getSubtypes()[getTypeIndex()];
|
||||
}
|
||||
}
|
||||
if ( type instanceof JdbcMapping ) {
|
||||
size = dialect.getDefaultSizeStrategy().resolveDefaultSize(
|
||||
|
|
|
@ -318,16 +318,18 @@ public class EmbeddableMappingType implements ManagedMappingType {
|
|||
|
||||
@Override
|
||||
public Object disassemble(Object value, SharedSessionContractImplementor session) {
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
}
|
||||
final Collection<AttributeMapping> attributeMappings = getAttributeMappings();
|
||||
|
||||
@Override
|
||||
public void visitDisassembledJdbcValues(
|
||||
Object value,
|
||||
Clause clause,
|
||||
JdbcValuesConsumer valuesConsumer,
|
||||
SharedSessionContractImplementor session) {
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
Object[] result = new Object[attributeMappings.size()];
|
||||
int i = 0;
|
||||
final Iterator<AttributeMapping> iterator = attributeMappings.iterator();
|
||||
while ( iterator.hasNext() ) {
|
||||
AttributeMapping mapping = iterator.next();
|
||||
Object o = mapping.getPropertyAccess().getGetter().get( value );
|
||||
result[i] = mapping.disassemble( o, session );
|
||||
i++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -344,6 +346,23 @@ public class EmbeddableMappingType implements ManagedMappingType {
|
|||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitDisassembledJdbcValues(
|
||||
Object value,
|
||||
Clause clause,
|
||||
JdbcValuesConsumer valuesConsumer,
|
||||
SharedSessionContractImplementor session) {
|
||||
final Collection<AttributeMapping> attributeMappings = getAttributeMappings();
|
||||
final Iterator<AttributeMapping> iterator = attributeMappings.iterator();
|
||||
final Object[] values = (Object[]) value;
|
||||
int i = 0;
|
||||
while ( iterator.hasNext() ) {
|
||||
AttributeMapping mapping = iterator.next();
|
||||
mapping.visitDisassembledJdbcValues( values[i], clause, valuesConsumer, session );
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
public void visitColumns(ColumnConsumer consumer) {
|
||||
attributeMappings.values().forEach(
|
||||
attributeMapping -> attributeMapping.visitColumns( consumer )
|
||||
|
|
|
@ -68,7 +68,7 @@ public interface EntityValuedModelPart extends FetchableContainer {
|
|||
Consumer<JdbcMapping> action,
|
||||
Clause clause,
|
||||
TypeConfiguration typeConfiguration) {
|
||||
getEntityMappingType().getJdbcTypeCount( typeConfiguration );
|
||||
getEntityMappingType().visitJdbcTypes( action, clause, typeConfiguration );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -25,7 +25,7 @@ public interface ForeignKeyDescriptor extends VirtualModelPart {
|
|||
|
||||
ForeignKeyDirection getDirection();
|
||||
|
||||
DomainResult createCollectionFecthDomainResult(
|
||||
DomainResult createCollectionFetchDomainResult(
|
||||
NavigablePath collectionPath,
|
||||
TableGroup tableGroup,
|
||||
DomainResultCreationState creationState);
|
||||
|
@ -54,6 +54,10 @@ public interface ForeignKeyDescriptor extends VirtualModelPart {
|
|||
return PART_NAME;
|
||||
}
|
||||
|
||||
String getReferringTableExpression();
|
||||
|
||||
String getTargetTableExpression();
|
||||
|
||||
/**
|
||||
* Visits the FK "referring" columns
|
||||
*/
|
||||
|
@ -62,36 +66,10 @@ public interface ForeignKeyDescriptor extends VirtualModelPart {
|
|||
visitReferringColumns( consumer );
|
||||
}
|
||||
|
||||
String getReferringTableExpression();
|
||||
|
||||
void visitReferringColumns(ColumnConsumer consumer);
|
||||
|
||||
String getTargetTableExpression();
|
||||
|
||||
void visitTargetColumns(ColumnConsumer consumer);
|
||||
|
||||
void visitColumnMappings(FkColumnMappingConsumer consumer);
|
||||
|
||||
<T> T visitColumnMapping(FkColumnMappingFunction<T> function);
|
||||
|
||||
// todo (6.0): the 2 interfaces does not take into account composite keys, referringColumn
|
||||
// and targetColumn should be collections
|
||||
interface FkColumnMappingConsumer {
|
||||
void consume(
|
||||
String referringTable,
|
||||
String referringColumn,
|
||||
String targetTable,
|
||||
String targetColumn,
|
||||
JdbcMapping jdbcMapping);
|
||||
}
|
||||
|
||||
interface FkColumnMappingFunction<T> {
|
||||
T apply(
|
||||
String referringTable,
|
||||
String referringColumn,
|
||||
String targetTable,
|
||||
String targetColumn,
|
||||
JdbcMapping jdbcMapping);
|
||||
}
|
||||
|
||||
boolean areTargetColumnNamesEqualsTo(String[] columnNames);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,571 @@
|
|||
/*
|
||||
* 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.metamodel.mapping.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.engine.FetchStrategy;
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.metamodel.mapping.ColumnConsumer;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.MappingType;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
|
||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||
import org.hibernate.query.ComparisonOperator;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
|
||||
import org.hibernate.sql.ast.Clause;
|
||||
import org.hibernate.sql.ast.SqlAstJoinType;
|
||||
import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator;
|
||||
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
||||
import org.hibernate.sql.ast.spi.SqlAstCreationState;
|
||||
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.expression.SqlTuple;
|
||||
import org.hibernate.sql.ast.tree.from.CompositeTableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
import org.hibernate.sql.ast.tree.from.TableReferenceJoin;
|
||||
import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate;
|
||||
import org.hibernate.sql.ast.tree.predicate.Junction;
|
||||
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||
import org.hibernate.sql.results.graph.Fetch;
|
||||
import org.hibernate.sql.results.graph.FetchParent;
|
||||
import org.hibernate.sql.results.graph.embeddable.EmbeddableValuedFetchable;
|
||||
import org.hibernate.sql.results.graph.embeddable.internal.EmbeddableFetchImpl;
|
||||
import org.hibernate.sql.results.graph.embeddable.internal.EmbeddableForeignKeyResultImpl;
|
||||
import org.hibernate.type.ForeignKeyDirection;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* @author Andrea Boriero
|
||||
*/
|
||||
public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor, EmbeddableValuedFetchable {
|
||||
|
||||
private String name;
|
||||
private StateArrayContributorMetadataAccess attributeMetadataAccess;
|
||||
private final String keyColumnContainingTable;
|
||||
private final List<String> keyColumnExpressions;
|
||||
private final String targetColumnContainingTable;
|
||||
private final List<String> targetColumnExpressions;
|
||||
private final EmbeddableValuedModelPart mappingType;
|
||||
private final List<JdbcMapping> jdbcMappings;
|
||||
private final ForeignKeyDirection fKeyDirection;
|
||||
private final int hasCode;
|
||||
|
||||
public EmbeddedForeignKeyDescriptor(
|
||||
String attributeName,
|
||||
EmbeddedIdentifierMappingImpl mappingType,
|
||||
StateArrayContributorMetadataAccess attributeMetadataAccess,
|
||||
ForeignKeyDirection fKeyDirection,
|
||||
String keyColumnContainingTable,
|
||||
List<String> keyColumnExpressions,
|
||||
String targetColumnContainingTable,
|
||||
List<String> targetColumnExpressions,
|
||||
MappingModelCreationProcess creationProcess) {
|
||||
name = attributeName;
|
||||
this.attributeMetadataAccess = attributeMetadataAccess;
|
||||
this.keyColumnContainingTable = keyColumnContainingTable;
|
||||
this.keyColumnExpressions = keyColumnExpressions;
|
||||
this.targetColumnContainingTable = targetColumnContainingTable;
|
||||
this.targetColumnExpressions = targetColumnExpressions;
|
||||
this.mappingType = mappingType;
|
||||
this.fKeyDirection = fKeyDirection;
|
||||
jdbcMappings = new ArrayList<>();
|
||||
mappingType.getAttributes().forEach(
|
||||
attribute -> {
|
||||
final TypeConfiguration typeConfiguration = creationProcess.getCreationContext()
|
||||
.getTypeConfiguration();
|
||||
if ( attribute instanceof SingularAssociationAttributeMapping ) {
|
||||
SingularAssociationAttributeMapping associationAttributeMapping = (SingularAssociationAttributeMapping) attribute;
|
||||
associationAttributeMapping.getAssociatedEntityMappingType()
|
||||
.getEntityPersister()
|
||||
.getIdentifierMapping()
|
||||
.visitJdbcTypes(
|
||||
jdbcMapping ->
|
||||
jdbcMappings.add( jdbcMapping )
|
||||
,
|
||||
null,
|
||||
typeConfiguration
|
||||
);
|
||||
}
|
||||
else {
|
||||
attribute.visitJdbcTypes(
|
||||
jdbcMapping -> {
|
||||
jdbcMappings.add( jdbcMapping );
|
||||
},
|
||||
null,
|
||||
typeConfiguration
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
this.hasCode = Objects.hash(
|
||||
keyColumnContainingTable,
|
||||
keyColumnExpressions,
|
||||
targetColumnContainingTable,
|
||||
targetColumnExpressions
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ForeignKeyDirection getDirection() {
|
||||
return fKeyDirection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainResult createCollectionFetchDomainResult(
|
||||
NavigablePath collectionPath,
|
||||
TableGroup tableGroup,
|
||||
DomainResultCreationState creationState) {
|
||||
if ( targetColumnContainingTable.equals( keyColumnContainingTable ) ) {
|
||||
final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState();
|
||||
final SqlExpressionResolver sqlExpressionResolver = sqlAstCreationState.getSqlExpressionResolver();
|
||||
final TableReference tableReference = tableGroup.resolveTableReference( keyColumnContainingTable );
|
||||
final String identificationVariable = tableReference.getIdentificationVariable();
|
||||
|
||||
List<SqlSelection> sqlSelections = new ArrayList<>();
|
||||
for ( int i = 0; i < keyColumnExpressions.size(); i++ ) {
|
||||
final JdbcMapping jdbcMapping = jdbcMappings.get( i );
|
||||
final String columnExpression = targetColumnExpressions.get( i );
|
||||
final SqlSelection sqlSelection = sqlExpressionResolver.resolveSqlSelection(
|
||||
sqlExpressionResolver.resolveSqlExpression(
|
||||
SqlExpressionResolver.createColumnReferenceKey(
|
||||
tableReference,
|
||||
columnExpression
|
||||
),
|
||||
s ->
|
||||
new ColumnReference(
|
||||
identificationVariable,
|
||||
columnExpression,
|
||||
jdbcMapping,
|
||||
creationState.getSqlAstCreationState()
|
||||
.getCreationContext()
|
||||
.getSessionFactory()
|
||||
)
|
||||
|
||||
),
|
||||
jdbcMapping.getJavaTypeDescriptor(),
|
||||
sqlAstCreationState.getCreationContext().getDomainModel().getTypeConfiguration()
|
||||
);
|
||||
sqlSelections.add( sqlSelection );
|
||||
}
|
||||
|
||||
return new EmbeddableForeignKeyResultImpl(
|
||||
sqlSelections,
|
||||
collectionPath,
|
||||
mappingType,
|
||||
null,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
else {
|
||||
return createDomainResult( collectionPath, tableGroup, creationState );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainResult createDomainResult(
|
||||
NavigablePath collectionPath,
|
||||
TableGroup tableGroup,
|
||||
DomainResultCreationState creationState) {
|
||||
//noinspection unchecked
|
||||
final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState();
|
||||
final SqlExpressionResolver sqlExpressionResolver = sqlAstCreationState.getSqlExpressionResolver();
|
||||
final TableReference tableReference = tableGroup.resolveTableReference( keyColumnContainingTable );
|
||||
final String identificationVariable = tableReference.getIdentificationVariable();
|
||||
int size = keyColumnExpressions.size();
|
||||
List<SqlSelection> sqlSelections = new ArrayList<>(size);
|
||||
for ( int i = 0; i < size; i++ ) {
|
||||
final String columnExpression = keyColumnExpressions.get( i );
|
||||
final JdbcMapping jdbcMapping = jdbcMappings.get( i );
|
||||
final SqlSelection sqlSelection = sqlExpressionResolver.resolveSqlSelection(
|
||||
sqlExpressionResolver.resolveSqlExpression(
|
||||
SqlExpressionResolver.createColumnReferenceKey(
|
||||
tableReference,
|
||||
columnExpression
|
||||
),
|
||||
s ->
|
||||
new ColumnReference(
|
||||
identificationVariable,
|
||||
columnExpression,
|
||||
jdbcMapping,
|
||||
creationState.getSqlAstCreationState()
|
||||
.getCreationContext()
|
||||
.getSessionFactory()
|
||||
)
|
||||
),
|
||||
jdbcMapping.getJavaTypeDescriptor(),
|
||||
sqlAstCreationState.getCreationContext().getDomainModel().getTypeConfiguration()
|
||||
);
|
||||
sqlSelections.add( sqlSelection );
|
||||
}
|
||||
|
||||
return new EmbeddableForeignKeyResultImpl(
|
||||
sqlSelections,
|
||||
collectionPath,
|
||||
mappingType,
|
||||
null,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate generateJoinPredicate(
|
||||
TableGroup lhs,
|
||||
TableGroup tableGroup,
|
||||
SqlAstJoinType sqlAstJoinType,
|
||||
SqlExpressionResolver sqlExpressionResolver,
|
||||
SqlAstCreationContext creationContext) {
|
||||
TableReference lhsTableReference;
|
||||
TableReference rhsTableKeyReference;
|
||||
if ( targetColumnContainingTable.equals( keyColumnContainingTable ) ) {
|
||||
lhsTableReference = getTableReferenceWhenTargetEqualsKey( lhs, tableGroup, keyColumnContainingTable );
|
||||
|
||||
rhsTableKeyReference = getTableReference(
|
||||
lhs,
|
||||
tableGroup,
|
||||
targetColumnContainingTable
|
||||
);
|
||||
}
|
||||
else {
|
||||
lhsTableReference = getTableReference( lhs, tableGroup, keyColumnContainingTable );
|
||||
|
||||
rhsTableKeyReference = getTableReference(
|
||||
lhs,
|
||||
tableGroup,
|
||||
targetColumnContainingTable
|
||||
);
|
||||
}
|
||||
|
||||
return generateJoinPredicate(
|
||||
lhsTableReference,
|
||||
rhsTableKeyReference,
|
||||
sqlAstJoinType,
|
||||
sqlExpressionResolver,
|
||||
creationContext
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate generateJoinPredicate(
|
||||
TableReference lhs,
|
||||
TableReference rhs,
|
||||
SqlAstJoinType sqlAstJoinType,
|
||||
SqlExpressionResolver sqlExpressionResolver,
|
||||
SqlAstCreationContext creationContext) {
|
||||
final String rhsTableExpression = rhs.getTableExpression();
|
||||
final String lhsTableExpression = lhs.getTableExpression();
|
||||
if ( lhsTableExpression.equals( keyColumnContainingTable ) ) {
|
||||
assert rhsTableExpression.equals( targetColumnContainingTable );
|
||||
return getPredicate( lhs, rhs, creationContext, keyColumnExpressions, targetColumnExpressions );
|
||||
}
|
||||
else {
|
||||
assert rhsTableExpression.equals( keyColumnContainingTable );
|
||||
return getPredicate( lhs, rhs, creationContext, targetColumnExpressions, keyColumnExpressions );
|
||||
}
|
||||
}
|
||||
|
||||
private Predicate getPredicate(
|
||||
TableReference lhs,
|
||||
TableReference rhs,
|
||||
SqlAstCreationContext creationContext,
|
||||
List<String> lhsExpressions,
|
||||
List<String> rhsColumnExpressions) {
|
||||
final Junction predicate = new Junction( Junction.Nature.CONJUNCTION );
|
||||
for ( int i = 0; i < lhsExpressions.size(); i++ ) {
|
||||
JdbcMapping jdbcMapping = jdbcMappings.get( i );
|
||||
ComparisonPredicate comparisonPredicate =
|
||||
new ComparisonPredicate(
|
||||
new ColumnReference(
|
||||
lhs,
|
||||
lhsExpressions.get( i ),
|
||||
jdbcMapping,
|
||||
creationContext.getSessionFactory()
|
||||
),
|
||||
ComparisonOperator.EQUAL,
|
||||
new ColumnReference(
|
||||
rhs,
|
||||
rhsColumnExpressions.get( i ),
|
||||
jdbcMapping,
|
||||
creationContext.getSessionFactory()
|
||||
)
|
||||
);
|
||||
predicate.add( comparisonPredicate );
|
||||
}
|
||||
return predicate;
|
||||
}
|
||||
|
||||
protected TableReference getTableReferenceWhenTargetEqualsKey(TableGroup lhs, TableGroup tableGroup, String table) {
|
||||
if ( tableGroup.getPrimaryTableReference().getTableExpression().equals( table ) ) {
|
||||
return tableGroup.getPrimaryTableReference();
|
||||
}
|
||||
if ( lhs.getPrimaryTableReference().getTableExpression().equals( table ) ) {
|
||||
return lhs.getPrimaryTableReference();
|
||||
}
|
||||
|
||||
for ( TableReferenceJoin tableJoin : lhs.getTableReferenceJoins() ) {
|
||||
if ( tableJoin.getJoinedTableReference().getTableExpression().equals( table ) ) {
|
||||
return tableJoin.getJoinedTableReference();
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalStateException( "Could not resolve binding for table `" + table + "`" );
|
||||
}
|
||||
|
||||
protected TableReference getTableReference(TableGroup lhs, TableGroup tableGroup, String table) {
|
||||
if ( lhs.getPrimaryTableReference().getTableExpression().equals( table ) ) {
|
||||
return lhs.getPrimaryTableReference();
|
||||
}
|
||||
else if ( tableGroup.getPrimaryTableReference().getTableExpression().equals( table ) ) {
|
||||
return tableGroup.getPrimaryTableReference();
|
||||
}
|
||||
|
||||
final TableReference tableReference = lhs.resolveTableReference( table );
|
||||
if ( tableReference != null ) {
|
||||
return tableReference;
|
||||
}
|
||||
|
||||
throw new IllegalStateException( "Could not resolve binding for table `" + table + "`" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReferringTableExpression() {
|
||||
return keyColumnContainingTable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTargetTableExpression() {
|
||||
return targetColumnContainingTable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReferringColumns(ColumnConsumer consumer) {
|
||||
for ( int i = 0; i < keyColumnExpressions.size(); i++ ) {
|
||||
consumer.accept( keyColumnContainingTable, keyColumnExpressions.get( i ), jdbcMappings.get( i ) );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTargetColumns(ColumnConsumer consumer) {
|
||||
for ( int i = 0; i < keyColumnExpressions.size(); i++ ) {
|
||||
consumer.accept( targetColumnContainingTable, targetColumnExpressions.get( i ), jdbcMappings.get( i ) );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areTargetColumnNamesEqualsTo(String[] columnNames) {
|
||||
int length = columnNames.length;
|
||||
if ( length != targetColumnExpressions.size() ) {
|
||||
return false;
|
||||
}
|
||||
for ( int i = 0; i < length; i++ ) {
|
||||
if ( !targetColumnExpressions.contains( columnNames[i] ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingType getPartMappingType() {
|
||||
throw new HibernateException( "Unexpected call to SimpleForeignKeyDescriptor#getPartMappingType" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaTypeDescriptor getJavaTypeDescriptor() {
|
||||
return mappingType.getJavaTypeDescriptor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigableRole getNavigableRole() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityMappingType findContainingEntityMapping() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if ( this == o ) {
|
||||
return true;
|
||||
}
|
||||
if ( o == null || getClass() != o.getClass() ) {
|
||||
return false;
|
||||
}
|
||||
EmbeddedForeignKeyDescriptor that = (EmbeddedForeignKeyDescriptor) o;
|
||||
return keyColumnContainingTable.equals( that.keyColumnContainingTable ) &&
|
||||
keyColumnExpressions.equals( that.keyColumnExpressions ) &&
|
||||
targetColumnContainingTable.equals( that.targetColumnContainingTable ) &&
|
||||
targetColumnExpressions.equals( that.targetColumnExpressions );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return hasCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableGroupJoin createTableGroupJoin(
|
||||
NavigablePath navigablePath,
|
||||
TableGroup lhs,
|
||||
String explicitSourceAlias,
|
||||
SqlAstJoinType sqlAstJoinType,
|
||||
LockMode lockMode,
|
||||
SqlAliasBaseGenerator aliasBaseGenerator,
|
||||
SqlExpressionResolver sqlExpressionResolver,
|
||||
SqlAstCreationContext creationContext) {
|
||||
final CompositeTableGroup compositeTableGroup = new CompositeTableGroup(
|
||||
navigablePath,
|
||||
this,
|
||||
lhs
|
||||
);
|
||||
|
||||
lhs.addTableGroupJoin( new TableGroupJoin( navigablePath, SqlAstJoinType.INNER, compositeTableGroup, null ) );
|
||||
|
||||
return new TableGroupJoin(
|
||||
navigablePath,
|
||||
sqlAstJoinType,
|
||||
compositeTableGroup
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EmbeddableMappingType getEmbeddableTypeDescriptor() {
|
||||
return (EmbeddableMappingType) mappingType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContainingTableExpression() {
|
||||
return keyColumnContainingTable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getMappedColumnExpressions() {
|
||||
return keyColumnExpressions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SingularAttributeMapping getParentInjectionAttributeMapping() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression toSqlExpression(
|
||||
TableGroup tableGroup,
|
||||
Clause clause,
|
||||
SqmToSqlAstConverter walker,
|
||||
SqlAstCreationState sqlAstCreationState) {
|
||||
final List<ColumnReference> columnReferences = CollectionHelper.arrayList( keyColumnExpressions.size() );
|
||||
final TableReference tableReference = tableGroup.resolveTableReference( getContainingTableExpression() );
|
||||
getEmbeddableTypeDescriptor().visitJdbcTypes(
|
||||
new Consumer<JdbcMapping>() {
|
||||
private int index = 0;
|
||||
|
||||
@Override
|
||||
public void accept(JdbcMapping jdbcMapping) {
|
||||
final String attrColumnExpr = keyColumnExpressions.get( index++ );
|
||||
|
||||
final Expression columnReference = sqlAstCreationState.getSqlExpressionResolver().resolveSqlExpression(
|
||||
SqlExpressionResolver.createColumnReferenceKey(
|
||||
tableReference,
|
||||
attrColumnExpr
|
||||
),
|
||||
sqlAstProcessingState -> new ColumnReference(
|
||||
tableReference.getIdentificationVariable(),
|
||||
attrColumnExpr,
|
||||
jdbcMapping,
|
||||
sqlAstCreationState.getCreationContext().getSessionFactory()
|
||||
)
|
||||
);
|
||||
|
||||
columnReferences.add( (ColumnReference) columnReference );
|
||||
}
|
||||
},
|
||||
clause,
|
||||
sqlAstCreationState.getCreationContext().getSessionFactory().getTypeConfiguration()
|
||||
);
|
||||
|
||||
return new SqlTuple( columnReferences, this );
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getSqlAliasStem() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelPart findSubPart(
|
||||
String name, EntityMappingType treatTargetType) {
|
||||
return mappingType.findSubPart( name, treatTargetType );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSubParts(
|
||||
Consumer<ModelPart> consumer, EntityMappingType treatTargetType) {
|
||||
mappingType.visitSubParts( consumer, treatTargetType );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFetchableName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FetchStrategy getMappedFetchStrategy() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fetch generateFetch(
|
||||
FetchParent fetchParent,
|
||||
NavigablePath fetchablePath,
|
||||
FetchTiming fetchTiming,
|
||||
boolean selected,
|
||||
LockMode lockMode,
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
return new EmbeddableFetchImpl(
|
||||
fetchablePath,
|
||||
this,
|
||||
fetchParent,
|
||||
fetchTiming,
|
||||
selected,
|
||||
attributeMetadataAccess.resolveAttributeMetadata( null ).isNullable(),
|
||||
creationState
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberOfFetchables() {
|
||||
return getEmbeddableTypeDescriptor().getNumberOfAttributeMappings();
|
||||
}
|
||||
}
|
|
@ -59,7 +59,7 @@ import org.hibernate.type.spi.TypeConfiguration;
|
|||
*
|
||||
* @author Andrea Boriero
|
||||
*/
|
||||
public class EmbeddedIdentifierMappingImpl implements CompositeIdentifierMapping, SingleAttributeIdentifierMapping, EmbeddableValuedFetchable {
|
||||
public class EmbeddedIdentifierMappingImpl implements CompositeIdentifierMapping, EmbeddableValuedFetchable {
|
||||
private final NavigableRole navigableRole;
|
||||
private final EntityMappingType entityMapping;
|
||||
private final String name;
|
||||
|
@ -161,12 +161,28 @@ public class EmbeddedIdentifierMappingImpl implements CompositeIdentifierMapping
|
|||
|
||||
@Override
|
||||
public void visitJdbcValues(
|
||||
Object value, Clause clause, JdbcValuesConsumer valuesConsumer, SharedSessionContractImplementor session) {
|
||||
getEmbeddableTypeDescriptor().visitJdbcValues( value, clause, valuesConsumer, session );
|
||||
Object value,
|
||||
Clause clause,
|
||||
JdbcValuesConsumer valuesConsumer,
|
||||
SharedSessionContractImplementor session) {
|
||||
getEmbeddableTypeDescriptor().getAttributeMappings().forEach(
|
||||
attributeMapping -> {
|
||||
final Object o = attributeMapping.getPropertyAccess().getGetter().get( value );
|
||||
if ( attributeMapping instanceof SingularAssociationAttributeMapping ) {
|
||||
final EntityMappingType associatedEntityMappingType =
|
||||
( (SingularAssociationAttributeMapping) attributeMapping ).getAssociatedEntityMappingType();
|
||||
final EntityIdentifierMapping identifierMapping =
|
||||
associatedEntityMappingType.getIdentifierMapping();
|
||||
final Object identifier = identifierMapping.getIdentifier( o, session );
|
||||
identifierMapping.visitJdbcValues( identifier, clause, valuesConsumer, session );
|
||||
}
|
||||
else {
|
||||
attributeMapping.visitJdbcValues( o, clause, valuesConsumer, session );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public <T> DomainResult<T> createDomainResult(
|
||||
NavigablePath navigablePath,
|
||||
|
@ -218,7 +234,6 @@ public class EmbeddedIdentifierMappingImpl implements CompositeIdentifierMapping
|
|||
);
|
||||
|
||||
return new SqlTuple( columnReferences, this );
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -237,13 +252,10 @@ public class EmbeddedIdentifierMappingImpl implements CompositeIdentifierMapping
|
|||
lhs
|
||||
);
|
||||
|
||||
lhs.addTableGroupJoin( new TableGroupJoin( navigablePath, SqlAstJoinType.INNER, compositeTableGroup, null ) );
|
||||
final TableGroupJoin join = new TableGroupJoin( navigablePath, SqlAstJoinType.LEFT, compositeTableGroup, null );
|
||||
lhs.addTableGroupJoin( join );
|
||||
|
||||
return new TableGroupJoin(
|
||||
navigablePath,
|
||||
sqlAstJoinType,
|
||||
compositeTableGroup
|
||||
);
|
||||
return join;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -258,7 +270,8 @@ public class EmbeddedIdentifierMappingImpl implements CompositeIdentifierMapping
|
|||
|
||||
@Override
|
||||
public void visitSubParts(
|
||||
Consumer<ModelPart> consumer, EntityMappingType treatTargetType) {
|
||||
Consumer<ModelPart> consumer,
|
||||
EntityMappingType treatTargetType) {
|
||||
getMappedTypeDescriptor().visitSubParts( consumer, treatTargetType );
|
||||
}
|
||||
|
||||
|
@ -297,8 +310,19 @@ public class EmbeddedIdentifierMappingImpl implements CompositeIdentifierMapping
|
|||
return getEmbeddableTypeDescriptor().getNumberOfAttributeMappings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitColumns(ColumnConsumer consumer) {
|
||||
getEmbeddableTypeDescriptor().visitColumns( consumer );
|
||||
getAttributes().forEach(
|
||||
attribute -> {
|
||||
if ( attribute instanceof SingularAssociationAttributeMapping ) {
|
||||
SingularAssociationAttributeMapping associationAttributeMapping = (SingularAssociationAttributeMapping) attribute;
|
||||
associationAttributeMapping.getForeignKeyDescriptor().visitReferringColumns( consumer );
|
||||
}
|
||||
else {
|
||||
attribute.visitColumns( consumer );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -317,8 +341,4 @@ public class EmbeddedIdentifierMappingImpl implements CompositeIdentifierMapping
|
|||
return (Collection) getEmbeddableTypeDescriptor().getAttributeMappings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PropertyAccess getPropertyAccess() {
|
||||
return propertyAccess;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.metamodel.mapping.internal;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.SortedMap;
|
||||
|
@ -49,6 +50,7 @@ import org.hibernate.metamodel.mapping.CollectionMappingType;
|
|||
import org.hibernate.metamodel.mapping.CollectionPart;
|
||||
import org.hibernate.metamodel.mapping.CompositeIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||
|
@ -229,7 +231,10 @@ public class MappingModelCreationHelper {
|
|||
.getDomainModel()
|
||||
.getTypeConfiguration()
|
||||
.getBasicTypeRegistry()
|
||||
.resolve( valueConverter.getRelationalJavaDescriptor(), resolution.getRelationalSqlTypeDescriptor() );
|
||||
.resolve(
|
||||
valueConverter.getRelationalJavaDescriptor(),
|
||||
resolution.getRelationalSqlTypeDescriptor()
|
||||
);
|
||||
|
||||
|
||||
return new BasicValuedSingularAttributeMapping(
|
||||
|
@ -474,15 +479,6 @@ public class MappingModelCreationHelper {
|
|||
final CollectionMappingType<?> collectionMappingType;
|
||||
final JavaTypeDescriptorRegistry jtdRegistry = creationContext.getJavaTypeDescriptorRegistry();
|
||||
|
||||
final ForeignKeyDescriptor keyDescriptor = interpretKeyDescriptor(
|
||||
bootProperty,
|
||||
bootValueMapping,
|
||||
collectionDescriptor,
|
||||
declaringType,
|
||||
dialect,
|
||||
creationProcess
|
||||
);
|
||||
|
||||
final CollectionPart elementDescriptor = interpretElement(
|
||||
bootValueMapping,
|
||||
tableExpression,
|
||||
|
@ -662,7 +658,6 @@ public class MappingModelCreationHelper {
|
|||
entityMappingType -> contributorMetadata,
|
||||
collectionMappingType,
|
||||
stateArrayPosition,
|
||||
keyDescriptor,
|
||||
elementDescriptor,
|
||||
indexDescriptor,
|
||||
identifierDescriptor,
|
||||
|
@ -678,6 +673,7 @@ public class MappingModelCreationHelper {
|
|||
declaringType,
|
||||
collectionDescriptor
|
||||
);
|
||||
|
||||
creationProcess.registerInitializationCallback(
|
||||
() -> {
|
||||
try {
|
||||
|
@ -693,11 +689,25 @@ public class MappingModelCreationHelper {
|
|||
}
|
||||
);
|
||||
|
||||
creationProcess.registerForeignKeyPostInitCallbacks(
|
||||
() -> {
|
||||
interpretKeyDescriptor(
|
||||
pluralAttributeMapping,
|
||||
bootValueMapping,
|
||||
collectionDescriptor,
|
||||
declaringType,
|
||||
dialect,
|
||||
creationProcess
|
||||
);
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
return pluralAttributeMapping;
|
||||
}
|
||||
|
||||
private static ForeignKeyDescriptor interpretKeyDescriptor(
|
||||
Property bootProperty,
|
||||
private static void interpretKeyDescriptor(
|
||||
PluralAttributeMappingImpl attributeMapping,
|
||||
Collection bootValueMapping,
|
||||
CollectionPersister collectionDescriptor,
|
||||
ManagedMappingType declaringType,
|
||||
|
@ -720,19 +730,53 @@ public class MappingModelCreationHelper {
|
|||
assert fkTarget instanceof BasicValuedModelPart;
|
||||
final BasicValuedModelPart simpleFkTarget = (BasicValuedModelPart) fkTarget;
|
||||
|
||||
return new SimpleForeignKeyDescriptor(
|
||||
( (AssociationType) bootValueMapping.getType() ).getForeignKeyDirection(),
|
||||
getTableIdentifierExpression( bootValueMappingKey.getTable(), creationProcess ),
|
||||
bootValueMappingKey.getColumnIterator().next().getText( dialect ),
|
||||
simpleFkTarget.getContainingTableExpression(),
|
||||
simpleFkTarget.getMappedColumnExpression(),
|
||||
(JdbcMapping) keyType
|
||||
attributeMapping.setForeignKeyDescriptor(
|
||||
new SimpleForeignKeyDescriptor(
|
||||
( (AssociationType) bootValueMapping.getType() ).getForeignKeyDirection(),
|
||||
getTableIdentifierExpression( bootValueMappingKey.getTable(), creationProcess ),
|
||||
bootValueMappingKey.getColumnIterator().next().getText( dialect ),
|
||||
simpleFkTarget.getContainingTableExpression(),
|
||||
simpleFkTarget.getMappedColumnExpression(),
|
||||
(JdbcMapping) keyType
|
||||
)
|
||||
);
|
||||
}
|
||||
else if ( fkTarget instanceof EmbeddableValuedModelPart ) {
|
||||
final EmbeddableValuedModelPart embeddedFkTarget = (EmbeddableValuedModelPart) fkTarget;
|
||||
List<JdbcMapping> jdbcMappings = new ArrayList<>();
|
||||
embeddedFkTarget.visitJdbcTypes(
|
||||
jdbcMapping -> {
|
||||
jdbcMappings.add( jdbcMapping );
|
||||
},
|
||||
null,
|
||||
creationProcess.getCreationContext().getTypeConfiguration()
|
||||
);
|
||||
List<String> keyColumnExpressions = new ArrayList<>();
|
||||
bootValueMapping.getColumnIterator().forEachRemaining( column -> keyColumnExpressions.add( column.getText(
|
||||
dialect ) ) );
|
||||
List<String> targetColumnExpressions = new ArrayList<>();
|
||||
fkTarget.visitColumns(
|
||||
(table, column, mapping) ->
|
||||
targetColumnExpressions.add( column ) );
|
||||
EmbeddedForeignKeyDescriptor embeddedForeignKeyDescriptor = new EmbeddedForeignKeyDescriptor(
|
||||
attributeMapping.getAttributeName(),
|
||||
(EmbeddedIdentifierMappingImpl) fkTarget,
|
||||
getStateArrayContributorMetadataAccess(attributeMapping.getPropertyAccess()),
|
||||
( (AssociationType) bootValueMapping.getType() ).getForeignKeyDirection(),
|
||||
getTableIdentifierExpression( bootValueMapping.getTable(), creationProcess ),
|
||||
keyColumnExpressions,
|
||||
embeddedFkTarget.getContainingTableExpression(),
|
||||
targetColumnExpressions,
|
||||
|
||||
throw new NotYetImplementedFor6Exception(
|
||||
"Support for composite foreign-keys not yet implemented: " + bootValueMapping.getRole()
|
||||
);
|
||||
creationProcess
|
||||
);
|
||||
attributeMapping.setForeignKeyDescriptor( embeddedForeignKeyDescriptor );
|
||||
}else {
|
||||
|
||||
throw new NotYetImplementedFor6Exception(
|
||||
"Support for composite foreign-keys not yet implemented: " + bootValueMapping.getRole()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static void interpretKeyDescriptor(
|
||||
|
@ -781,7 +825,6 @@ public class MappingModelCreationHelper {
|
|||
|
||||
);
|
||||
attributeMapping.setForeignKeyDescriptor( foreignKeyDescriptor );
|
||||
|
||||
}
|
||||
else {
|
||||
SingularAssociationAttributeMapping subPart = (SingularAssociationAttributeMapping) referencedEntityDescriptor
|
||||
|
@ -803,13 +846,45 @@ public class MappingModelCreationHelper {
|
|||
creationProcess
|
||||
);
|
||||
attributeMapping.setForeignKeyDescriptor( subPart.getForeignKeyDescriptor() );
|
||||
|
||||
}
|
||||
else {
|
||||
attributeMapping.setForeignKeyDescriptor( foreignKeyDescriptor );
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( fkTarget instanceof EmbeddableValuedModelPart ) {
|
||||
if ( bootValueMapping.isReferenceToPrimaryKey() ) {
|
||||
final EmbeddableValuedModelPart embeddedFkTarget = (EmbeddableValuedModelPart) fkTarget;
|
||||
final List<String> keyColumnExpressions = new ArrayList<>();
|
||||
bootValueMapping.getColumnIterator().forEachRemaining(
|
||||
column ->
|
||||
keyColumnExpressions.add( column.getText( dialect ) )
|
||||
);
|
||||
|
||||
final List<String> targetColumnExpressions = new ArrayList<>();
|
||||
embeddedFkTarget.getMappedColumnExpressions().forEach(
|
||||
column ->
|
||||
targetColumnExpressions.add( column )
|
||||
);
|
||||
|
||||
final EmbeddedForeignKeyDescriptor embeddedForeignKeyDescriptor = new EmbeddedForeignKeyDescriptor(
|
||||
attributeMapping.getAttributeName(),
|
||||
(EmbeddedIdentifierMappingImpl) fkTarget,
|
||||
getStateArrayContributorMetadataAccess(attributeMapping.getPropertyAccess()),
|
||||
( (AssociationType) bootValueMapping.getType() ).getForeignKeyDirection(),
|
||||
getTableIdentifierExpression( bootValueMapping.getTable(), creationProcess ),
|
||||
keyColumnExpressions,
|
||||
embeddedFkTarget.getContainingTableExpression(),
|
||||
targetColumnExpressions,
|
||||
|
||||
creationProcess
|
||||
);
|
||||
attributeMapping.setForeignKeyDescriptor( embeddedForeignKeyDescriptor );
|
||||
}
|
||||
else{
|
||||
throw new NotYetImplementedFor6Exception();
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new NotYetImplementedFor6Exception(
|
||||
"Support for composite foreign-keys not yet implemented: " +
|
||||
|
@ -1091,7 +1166,7 @@ public class MappingModelCreationHelper {
|
|||
propertyAccess
|
||||
);
|
||||
|
||||
creationProcess.registerInitializationCallback(
|
||||
creationProcess.registerForeignKeyPostInitCallbacks(
|
||||
() -> {
|
||||
final Dialect dialect = creationProcess.getCreationContext()
|
||||
.getSessionFactory()
|
||||
|
|
|
@ -37,6 +37,9 @@ public class MappingModelCreationProcess {
|
|||
|
||||
private String currentlyProcessingRole;
|
||||
|
||||
private List<PostInitCallback> postInitCallbacks;
|
||||
private List<PostInitCallback> foreignKeyPostInitCallbacks;
|
||||
|
||||
private MappingModelCreationProcess(
|
||||
Map<String,EntityPersister> entityPersisterMap,
|
||||
RuntimeModelCreationContext creationContext) {
|
||||
|
@ -66,7 +69,13 @@ public class MappingModelCreationProcess {
|
|||
entityPersister.prepareMappingModel( this );
|
||||
}
|
||||
|
||||
while ( postInitCallbacks != null && ! postInitCallbacks.isEmpty() ) {
|
||||
executePostInitCallbakcs( postInitCallbacks );
|
||||
|
||||
executePostInitCallbakcs( foreignKeyPostInitCallbacks );
|
||||
}
|
||||
|
||||
private void executePostInitCallbakcs(List<PostInitCallback> postInitCallbacks) {
|
||||
while ( postInitCallbacks != null && !postInitCallbacks.isEmpty() ) {
|
||||
// copy to avoid CCME
|
||||
final ArrayList<PostInitCallback> copy = new ArrayList<>( new ArrayList<>( postInitCallbacks ) );
|
||||
|
||||
|
@ -100,8 +109,6 @@ public class MappingModelCreationProcess {
|
|||
}
|
||||
}
|
||||
|
||||
private List<PostInitCallback> postInitCallbacks;
|
||||
|
||||
public void registerInitializationCallback(PostInitCallback callback) {
|
||||
if ( postInitCallbacks == null ) {
|
||||
postInitCallbacks = new ArrayList<>();
|
||||
|
@ -109,6 +116,13 @@ public class MappingModelCreationProcess {
|
|||
postInitCallbacks.add( callback );
|
||||
}
|
||||
|
||||
public void registerForeignKeyPostInitCallbacks(PostInitCallback callback) {
|
||||
if ( foreignKeyPostInitCallbacks == null ) {
|
||||
foreignKeyPostInitCallbacks = new ArrayList<>();
|
||||
}
|
||||
foreignKeyPostInitCallbacks.add( callback );
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface PostInitCallback {
|
||||
boolean process();
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
|||
import org.hibernate.metamodel.mapping.CollectionIdentifierDescriptor;
|
||||
import org.hibernate.metamodel.mapping.CollectionMappingType;
|
||||
import org.hibernate.metamodel.mapping.CollectionPart;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||
import org.hibernate.metamodel.mapping.ManagedMappingType;
|
||||
|
@ -61,18 +62,20 @@ import org.hibernate.sql.results.graph.collection.internal.CollectionDomainResul
|
|||
import org.hibernate.sql.results.graph.collection.internal.DelayedCollectionFetch;
|
||||
import org.hibernate.sql.results.graph.collection.internal.EagerCollectionFetch;
|
||||
import org.hibernate.sql.results.graph.collection.internal.SelectEagerCollectionFetch;
|
||||
import org.hibernate.type.AssociationType;
|
||||
import org.hibernate.type.EntityType;
|
||||
import org.hibernate.type.ForeignKeyDirection;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class PluralAttributeMappingImpl extends AbstractAttributeMapping implements PluralAttributeMapping {
|
||||
private static final Logger log = Logger.getLogger( PluralAttributeMappingImpl.class );
|
||||
|
||||
|
||||
public interface Aware {
|
||||
void injectAttributeMapping(PluralAttributeMapping attributeMapping);
|
||||
}
|
||||
|
@ -83,7 +86,6 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
|
|||
private final PropertyAccess propertyAccess;
|
||||
private final StateArrayContributorMetadataAccess stateArrayContributorMetadataAccess;
|
||||
|
||||
private final ForeignKeyDescriptor fkDescriptor;
|
||||
private final CollectionPart elementDescriptor;
|
||||
private final CollectionPart indexDescriptor;
|
||||
private final CollectionIdentifierDescriptor identifierDescriptor;
|
||||
|
@ -98,6 +100,7 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
|
|||
|
||||
private final IndexMetadata indexMetadata;
|
||||
|
||||
private ForeignKeyDescriptor fkDescriptor;
|
||||
private ForeignKeyDescriptor manyToManyFkDescriptor;
|
||||
|
||||
private OrderByFragment orderByFragment;
|
||||
|
@ -111,7 +114,6 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
|
|||
StateArrayContributorMetadataAccess stateArrayContributorMetadataAccess,
|
||||
CollectionMappingType collectionMappingType,
|
||||
int stateArrayPosition,
|
||||
ForeignKeyDescriptor fkDescriptor,
|
||||
CollectionPart elementDescriptor,
|
||||
CollectionPart indexDescriptor,
|
||||
CollectionIdentifierDescriptor identifierDescriptor,
|
||||
|
@ -124,7 +126,6 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
|
|||
this.stateArrayContributorMetadataAccess = stateArrayContributorMetadataAccess;
|
||||
this.collectionMappingType = collectionMappingType;
|
||||
this.stateArrayPosition = stateArrayPosition;
|
||||
this.fkDescriptor = fkDescriptor;
|
||||
this.elementDescriptor = elementDescriptor;
|
||||
this.indexDescriptor = indexDescriptor;
|
||||
this.identifierDescriptor = identifierDescriptor;
|
||||
|
@ -185,47 +186,84 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
|
|||
MappingModelCreationProcess creationProcess) {
|
||||
if ( collectionDescriptor.getElementType() instanceof EntityType
|
||||
|| collectionDescriptor.getIndexType() instanceof EntityType ) {
|
||||
creationProcess.registerForeignKeyPostInitCallbacks(
|
||||
() -> {
|
||||
final EntityPersister associatedEntityDescriptor;
|
||||
final ModelPart fkTargetPart;
|
||||
final Value fkBootDescriptorSource;
|
||||
if ( collectionDescriptor.getElementType() instanceof EntityType ) {
|
||||
final EntityType elementEntityType = (EntityType) collectionDescriptor.getElementType();
|
||||
associatedEntityDescriptor = creationProcess.getEntityPersister( elementEntityType.getAssociatedEntityName() );
|
||||
fkTargetPart = elementEntityType.isReferenceToPrimaryKey()
|
||||
? associatedEntityDescriptor.getIdentifierMapping()
|
||||
: associatedEntityDescriptor.findSubPart( elementEntityType.getRHSUniqueKeyPropertyName() );
|
||||
fkBootDescriptorSource = bootDescriptor.getElement();
|
||||
}
|
||||
else {
|
||||
assert collectionDescriptor.getIndexType() != null;
|
||||
assert bootDescriptor instanceof IndexedCollection;
|
||||
|
||||
final EntityPersister associatedEntityDescriptor;
|
||||
final ModelPart fkTargetPart;
|
||||
final Value fkBootDescriptorSource;
|
||||
if ( collectionDescriptor.getElementType() instanceof EntityType ) {
|
||||
final EntityType elementEntityType = (EntityType) collectionDescriptor.getElementType();
|
||||
associatedEntityDescriptor = creationProcess.getEntityPersister( elementEntityType.getAssociatedEntityName() );
|
||||
fkTargetPart = elementEntityType.isReferenceToPrimaryKey()
|
||||
? associatedEntityDescriptor.getIdentifierMapping()
|
||||
: associatedEntityDescriptor.findSubPart( elementEntityType.getRHSUniqueKeyPropertyName() );
|
||||
fkBootDescriptorSource = bootDescriptor.getElement();
|
||||
}
|
||||
else {
|
||||
assert collectionDescriptor.getIndexType() != null;
|
||||
assert bootDescriptor instanceof IndexedCollection;
|
||||
final EntityType indexEntityType = (EntityType) collectionDescriptor.getIndexType();
|
||||
associatedEntityDescriptor = creationProcess.getEntityPersister( indexEntityType.getAssociatedEntityName() );
|
||||
fkTargetPart = indexEntityType.isReferenceToPrimaryKey()
|
||||
? associatedEntityDescriptor.getIdentifierMapping()
|
||||
: associatedEntityDescriptor.findSubPart( indexEntityType.getRHSUniqueKeyPropertyName() );
|
||||
fkBootDescriptorSource = ( (IndexedCollection) bootDescriptor ).getIndex();
|
||||
}
|
||||
|
||||
final EntityType indexEntityType = (EntityType) collectionDescriptor.getIndexType();
|
||||
associatedEntityDescriptor = creationProcess.getEntityPersister( indexEntityType.getAssociatedEntityName() );
|
||||
fkTargetPart = indexEntityType.isReferenceToPrimaryKey()
|
||||
? associatedEntityDescriptor.getIdentifierMapping()
|
||||
: associatedEntityDescriptor.findSubPart( indexEntityType.getRHSUniqueKeyPropertyName() );
|
||||
fkBootDescriptorSource = ( (IndexedCollection) bootDescriptor ).getIndex();
|
||||
}
|
||||
if ( fkTargetPart instanceof BasicValuedModelPart ) {
|
||||
final BasicValuedModelPart basicFkTargetPart = (BasicValuedModelPart) fkTargetPart;
|
||||
final Joinable collectionDescriptorAsJoinable = (Joinable) collectionDescriptor;
|
||||
manyToManyFkDescriptor = new SimpleForeignKeyDescriptor(
|
||||
ForeignKeyDirection.TO_PARENT,
|
||||
collectionDescriptorAsJoinable.getTableName(),
|
||||
fkBootDescriptorSource.getColumnIterator()
|
||||
.next()
|
||||
.getText( creationProcess.getCreationContext()
|
||||
.getSessionFactory()
|
||||
.getJdbcServices()
|
||||
.getDialect() ),
|
||||
basicFkTargetPart.getContainingTableExpression(),
|
||||
basicFkTargetPart.getMappedColumnExpression(),
|
||||
basicFkTargetPart.getJdbcMapping()
|
||||
);
|
||||
}
|
||||
else if ( fkTargetPart instanceof EmbeddableValuedModelPart ) {
|
||||
final Joinable collectionDescriptorAsJoinable = (Joinable) collectionDescriptor;
|
||||
|
||||
java.util.List<String> keyColumnExpressions = new ArrayList<>();
|
||||
fkBootDescriptorSource.getColumnIterator()
|
||||
.forEachRemaining( column -> keyColumnExpressions.add(
|
||||
column.getText( creationProcess.getCreationContext()
|
||||
.getSessionFactory()
|
||||
.getJdbcServices()
|
||||
.getDialect() ) ) );
|
||||
java.util.List<String> targetColumnExpressions = new ArrayList<>();
|
||||
fkTargetPart.visitColumns(
|
||||
(table, column, mapping) ->
|
||||
targetColumnExpressions.add( column ) );
|
||||
|
||||
manyToManyFkDescriptor = new EmbeddedForeignKeyDescriptor(
|
||||
getAttributeName(),
|
||||
(EmbeddedIdentifierMappingImpl) fkTargetPart,
|
||||
stateArrayContributorMetadataAccess,
|
||||
( (AssociationType) bootDescriptor.getType() ).getForeignKeyDirection(),
|
||||
collectionDescriptorAsJoinable.getTableName(),
|
||||
keyColumnExpressions,
|
||||
( (EmbeddableValuedModelPart) fkTargetPart ).getContainingTableExpression(),
|
||||
targetColumnExpressions,
|
||||
creationProcess
|
||||
);
|
||||
}
|
||||
else {
|
||||
throw new NotYetImplementedFor6Exception(
|
||||
"Support for composite foreign keys not yet implemented : " + collectionDescriptor.getRole()
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
if ( fkTargetPart instanceof BasicValuedModelPart ) {
|
||||
final BasicValuedModelPart basicFkTargetPart = (BasicValuedModelPart) fkTargetPart;
|
||||
final Joinable collectionDescriptorAsJoinable = (Joinable) collectionDescriptor;
|
||||
manyToManyFkDescriptor = new SimpleForeignKeyDescriptor(
|
||||
ForeignKeyDirection.TO_PARENT,
|
||||
collectionDescriptorAsJoinable.getTableName(),
|
||||
fkBootDescriptorSource.getColumnIterator().next().getText(),
|
||||
basicFkTargetPart.getContainingTableExpression(),
|
||||
basicFkTargetPart.getMappedColumnExpression(),
|
||||
basicFkTargetPart.getJdbcMapping()
|
||||
);
|
||||
}
|
||||
else {
|
||||
throw new NotYetImplementedFor6Exception(
|
||||
"Support for composite foreign keys not yet implemented : " + collectionDescriptor.getRole()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
final boolean hasOrder = bootDescriptor.getOrderBy() != null;
|
||||
|
@ -457,6 +495,11 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
public void setForeignKeyDescriptor(ForeignKeyDescriptor fkDescriptor) {
|
||||
this.fkDescriptor = fkDescriptor;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private TableGroupJoin createOneToManyTableGroupJoin(
|
||||
NavigablePath navigablePath,
|
||||
|
@ -470,7 +513,7 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
|
|||
final TableGroup tableGroup = createOneToManyTableGroup(
|
||||
navigablePath,
|
||||
sqlAstJoinType == SqlAstJoinType.INNER
|
||||
&& ! getAttributeMetadataAccess().resolveAttributeMetadata( null ).isNullable(),
|
||||
&& !getAttributeMetadataAccess().resolveAttributeMetadata( null ).isNullable(),
|
||||
lockMode,
|
||||
aliasBaseGenerator,
|
||||
sqlExpressionResolver,
|
||||
|
@ -513,11 +556,12 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
|
|||
|
||||
final SqlAliasBase sqlAliasBase = aliasBaseGenerator.createSqlAliasBase( getSqlAliasStem() );
|
||||
|
||||
final TableReference primaryTableReference = entityPartDescriptor.getEntityMappingType().createPrimaryTableReference(
|
||||
sqlAliasBase,
|
||||
sqlExpressionResolver,
|
||||
creationContext
|
||||
);
|
||||
final TableReference primaryTableReference = entityPartDescriptor.getEntityMappingType()
|
||||
.createPrimaryTableReference(
|
||||
sqlAliasBase,
|
||||
sqlExpressionResolver,
|
||||
creationContext
|
||||
);
|
||||
|
||||
return new StandardTableGroup(
|
||||
navigablePath,
|
||||
|
@ -525,7 +569,8 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
|
|||
lockMode,
|
||||
primaryTableReference,
|
||||
sqlAliasBase,
|
||||
(tableExpression) -> entityPartDescriptor.getEntityMappingType().containsTableReference( tableExpression ),
|
||||
(tableExpression) -> entityPartDescriptor.getEntityMappingType()
|
||||
.containsTableReference( tableExpression ),
|
||||
(tableExpression, tg) -> entityPartDescriptor.getEntityMappingType().createTableReferenceJoin(
|
||||
tableExpression,
|
||||
sqlAliasBase,
|
||||
|
@ -585,7 +630,7 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
|
|||
SqlAstCreationContext creationContext) {
|
||||
final SqlAliasBase sqlAliasBase = aliasBaseGenerator.createSqlAliasBase( getSqlAliasStem() );
|
||||
|
||||
assert ! getCollectionDescriptor().isOneToMany();
|
||||
assert !getCollectionDescriptor().isOneToMany();
|
||||
|
||||
final String collectionTableName = ( (Joinable) collectionDescriptor ).getTableName();
|
||||
final TableReference collectionTableReference = new TableReference(
|
||||
|
@ -596,7 +641,7 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
|
|||
);
|
||||
|
||||
final Consumer<TableGroup> tableGroupFinalizer;
|
||||
final BiFunction<String,TableGroup,TableReferenceJoin> tableReferenceJoinCreator;
|
||||
final BiFunction<String, TableGroup, TableReferenceJoin> tableReferenceJoinCreator;
|
||||
final java.util.function.Predicate<String> tableReferenceJoinNameChecker;
|
||||
if ( elementDescriptor instanceof EntityCollectionPart || indexDescriptor instanceof EntityCollectionPart ) {
|
||||
final EntityCollectionPart entityPartDescriptor;
|
||||
|
@ -619,13 +664,14 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
|
|||
tableExpression,
|
||||
sqlAliasBase,
|
||||
associatedPrimaryTable,
|
||||
canUseInnerJoin && ! getAttributeMetadataAccess().resolveAttributeMetadata( null ).isNullable(),
|
||||
canUseInnerJoin && !getAttributeMetadataAccess().resolveAttributeMetadata( null ).isNullable(),
|
||||
sqlExpressionResolver,
|
||||
creationContext
|
||||
);
|
||||
|
||||
tableGroupFinalizer = tableGroup -> {
|
||||
final SqlAstJoinType joinType = canUseInnerJoin && ! getAttributeMetadataAccess().resolveAttributeMetadata( null ).isNullable()
|
||||
final SqlAstJoinType joinType = canUseInnerJoin && !getAttributeMetadataAccess().resolveAttributeMetadata(
|
||||
null ).isNullable()
|
||||
? SqlAstJoinType.INNER
|
||||
: SqlAstJoinType.LEFT;
|
||||
final TableReferenceJoin associationJoin = new TableReferenceJoin(
|
||||
|
@ -736,7 +782,7 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
|
|||
}
|
||||
|
||||
if ( elementDescriptor instanceof EntityCollectionPart ) {
|
||||
return ( (EntityCollectionPart) elementDescriptor ).findSubPart(name);
|
||||
return ( (EntityCollectionPart) elementDescriptor ).findSubPart( name );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -85,7 +85,7 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
|||
}
|
||||
|
||||
@Override
|
||||
public DomainResult createCollectionFecthDomainResult(
|
||||
public DomainResult createCollectionFetchDomainResult(
|
||||
NavigablePath collectionPath,
|
||||
TableGroup tableGroup,
|
||||
DomainResultCreationState creationState) {
|
||||
|
@ -140,14 +140,13 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
|||
tableReference,
|
||||
keyColumnExpression
|
||||
),
|
||||
s -> {
|
||||
return new ColumnReference(
|
||||
s ->
|
||||
new ColumnReference(
|
||||
identificationVariable,
|
||||
keyColumnExpression,
|
||||
jdbcMapping,
|
||||
creationState.getSqlAstCreationState().getCreationContext().getSessionFactory()
|
||||
);
|
||||
}
|
||||
)
|
||||
),
|
||||
jdbcMapping.getJavaTypeDescriptor(),
|
||||
sqlAstCreationState.getCreationContext().getDomainModel().getTypeConfiguration()
|
||||
|
@ -314,25 +313,11 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
|||
}
|
||||
|
||||
@Override
|
||||
public <T> T visitColumnMapping(FkColumnMappingFunction<T> function) {
|
||||
return function.apply(
|
||||
keyColumnContainingTable,
|
||||
keyColumnExpression ,
|
||||
targetColumnContainingTable,
|
||||
targetColumnExpression ,
|
||||
jdbcMapping
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitColumnMappings(FkColumnMappingConsumer consumer) {
|
||||
consumer.consume(
|
||||
keyColumnContainingTable,
|
||||
keyColumnExpression,
|
||||
targetColumnContainingTable,
|
||||
targetColumnExpression,
|
||||
jdbcMapping
|
||||
);
|
||||
public boolean areTargetColumnNamesEqualsTo(String[] columnNames) {
|
||||
if ( columnNames.length != 1 ) {
|
||||
return false;
|
||||
}
|
||||
return targetColumnExpression.equals( columnNames[0] );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -8,7 +8,6 @@ package org.hibernate.metamodel.mapping.internal;
|
|||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.engine.FetchStrategy;
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
import org.hibernate.mapping.ManyToOne;
|
||||
|
@ -181,7 +180,7 @@ public class SingularAssociationAttributeMapping extends AbstractSingularAttribu
|
|||
}
|
||||
|
||||
final FetchParent associationFetchParent = fetchParent.resolveContainingAssociationParent();
|
||||
if(associationFetchParent == null){
|
||||
if ( associationFetchParent == null ) {
|
||||
return null;
|
||||
}
|
||||
final ModelPart referencedModePart = associationFetchParent.getReferencedModePart();
|
||||
|
@ -189,7 +188,7 @@ public class SingularAssociationAttributeMapping extends AbstractSingularAttribu
|
|||
|
||||
final Association associationParent = (Association) referencedModePart;
|
||||
|
||||
if (foreignKeyDescriptor.equals( associationParent.getForeignKeyDescriptor() ) ) {
|
||||
if ( foreignKeyDescriptor.equals( associationParent.getForeignKeyDescriptor() ) ) {
|
||||
// we need to determine the NavigablePath referring to the entity that the bi-dir
|
||||
// fetch will "return" for its Assembler. so we walk "up" the FetchParent graph
|
||||
// to find the "referenced entity" reference
|
||||
|
@ -217,23 +216,10 @@ public class SingularAssociationAttributeMapping extends AbstractSingularAttribu
|
|||
if ( associationParentForeignKeyDescriptor.getTargetTableExpression()
|
||||
.equals( entityPersister.getTableName() ) ) {
|
||||
final String[] identifierColumnNames = entityPersister.getIdentifierColumnNames();
|
||||
return associationParentForeignKeyDescriptor.visitColumnMapping( (referringTable, referringColumns, targetTable, targetColumns, jdbcMapping) -> {
|
||||
// if ( identifierColumnNames.length == targetColumns.size() ) {
|
||||
// for ( int i = 0; i < identifierColumnNames.length; i++ ) {
|
||||
// if ( !targetColumns.contains( identifierColumnNames[i] ) ) {
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
if ( identifierColumnNames.length > 1 ) {
|
||||
throw new NotYetImplementedFor6Exception(
|
||||
"Support for composite foreign -keys not yet implemented" );
|
||||
}
|
||||
if ( targetColumns.equals( identifierColumnNames[0] ) ) {
|
||||
return createBiDirectionalFetch( fetchablePath, fetchParent );
|
||||
}
|
||||
// }
|
||||
return null;
|
||||
} );
|
||||
if ( associationParentForeignKeyDescriptor.areTargetColumnNamesEqualsTo( identifierColumnNames ) ) {
|
||||
return createBiDirectionalFetch( fetchablePath, fetchParent );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -217,6 +217,7 @@ import org.hibernate.type.Type;
|
|||
import org.hibernate.type.TypeHelper;
|
||||
import org.hibernate.type.VersionType;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* Basic functionality for persisting an entity via JDBC
|
||||
|
@ -1231,14 +1232,6 @@ public abstract class AbstractEntityPersister
|
|||
return new EntityResultImpl( navigablePath, this, resultVariable, creationState );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applySqlSelections(
|
||||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
DomainResultCreationState creationState) {
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public NaturalIdMapping getNaturalIdMapping() {
|
||||
return naturalIdMapping;
|
||||
|
@ -6450,7 +6443,27 @@ public abstract class AbstractEntityPersister
|
|||
collectAttributeDefinitions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJdbcTypes(
|
||||
Consumer<JdbcMapping> action,
|
||||
Clause clause,
|
||||
TypeConfiguration typeConfiguration) {
|
||||
getAttributeMappings().forEach(
|
||||
attributeMapping -> attributeMapping.visitJdbcTypes( action, clause, typeConfiguration )
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJdbcValues(
|
||||
Object value,
|
||||
Clause clause,
|
||||
JdbcValuesConsumer consumer,
|
||||
SharedSessionContractImplementor session) {
|
||||
getAttributeMappings().forEach(
|
||||
attributeMapping ->
|
||||
attributeMapping.visitJdbcValues( value, clause, consumer, session )
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityIdentifierDefinition getEntityKeyDefinition() {
|
||||
|
|
|
@ -19,7 +19,7 @@ public abstract class AbstractFetchParent implements FetchParent {
|
|||
private final FetchableContainer fetchContainer;
|
||||
private final NavigablePath navigablePath;
|
||||
|
||||
private List<Fetch> fetches;
|
||||
protected List<Fetch> fetches;
|
||||
|
||||
public AbstractFetchParent(FetchableContainer fetchContainer, NavigablePath navigablePath) {
|
||||
this.fetchContainer = fetchContainer;
|
||||
|
|
|
@ -60,13 +60,13 @@ public class EagerCollectionFetch extends CollectionFetch implements FetchParent
|
|||
final ForeignKeyDescriptor keyDescriptor = fetchedAttribute.getKeyDescriptor();
|
||||
if ( parentTableGroup != null ) {
|
||||
// join fetch
|
||||
keyContainerResult = keyDescriptor.createCollectionFecthDomainResult( fetchedPath, parentTableGroup, creationState );
|
||||
keyContainerResult = keyDescriptor.createCollectionFetchDomainResult( fetchedPath, parentTableGroup, creationState );
|
||||
keyCollectionResult = keyDescriptor.createDomainResult( fetchedPath, collectionTableGroup, creationState );
|
||||
}
|
||||
else {
|
||||
// select fetch
|
||||
// todo (6.0) : we could potentially leverage batch fetching for performance
|
||||
keyContainerResult = keyDescriptor.createCollectionFecthDomainResult( fetchedPath, collectionTableGroup, creationState );
|
||||
keyContainerResult = keyDescriptor.createCollectionFetchDomainResult( fetchedPath, collectionTableGroup, creationState );
|
||||
|
||||
// use null for `keyCollectionResult`... the initializer will see that as trigger to use
|
||||
// the assembled container-key value as the collection-key value.
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* 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.sql.results.graph.embeddable.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.internal.SingularAssociationAttributeMapping;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
import org.hibernate.sql.results.graph.AbstractFetchParent;
|
||||
import org.hibernate.sql.results.graph.AssemblerCreationState;
|
||||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
import org.hibernate.sql.results.graph.DomainResultAssembler;
|
||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||
import org.hibernate.sql.results.graph.Fetch;
|
||||
import org.hibernate.sql.results.graph.Fetchable;
|
||||
import org.hibernate.sql.results.graph.Initializer;
|
||||
import org.hibernate.sql.results.graph.basic.BasicFetch;
|
||||
import org.hibernate.sql.results.graph.basic.BasicResult;
|
||||
import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode;
|
||||
import org.hibernate.sql.results.graph.entity.internal.EntityFetchSelectImpl;
|
||||
|
||||
/**
|
||||
* @author Andrea Boriero
|
||||
*/
|
||||
public class EmbeddableForeignKeyResultImpl<T> extends AbstractFetchParent
|
||||
implements EmbeddableResultGraphNode, DomainResult<T> {
|
||||
|
||||
private final String resultVariable;
|
||||
|
||||
public EmbeddableForeignKeyResultImpl(
|
||||
List<SqlSelection> sqlSelections,
|
||||
NavigablePath navigablePath,
|
||||
EmbeddableValuedModelPart embeddableValuedModelPart,
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
super( embeddableValuedModelPart.getEmbeddableTypeDescriptor(), navigablePath );
|
||||
this.resultVariable = resultVariable;
|
||||
AtomicInteger atomicInteger = new AtomicInteger( 0 );
|
||||
fetches = new ArrayList<>();
|
||||
embeddableValuedModelPart.visitFetchables(
|
||||
fetchable -> {
|
||||
generateFetches( sqlSelections, navigablePath, creationState, atomicInteger, fetchable );
|
||||
},
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
private void generateFetches(
|
||||
List<SqlSelection> sqlSelections,
|
||||
NavigablePath navigablePath,
|
||||
DomainResultCreationState creationState,
|
||||
AtomicInteger atomicInteger,
|
||||
Fetchable fetchable) {
|
||||
if ( fetchable instanceof SingularAssociationAttributeMapping ) {
|
||||
final SingularAssociationAttributeMapping singularAssociationAttributeMapping = (SingularAssociationAttributeMapping) fetchable;
|
||||
EntityMappingType associatedEntityMappingType = singularAssociationAttributeMapping.getAssociatedEntityMappingType();
|
||||
BasicResult domainResult = new BasicResult(
|
||||
sqlSelections.get( atomicInteger.getAndIncrement() ).getValuesArrayPosition(),
|
||||
null,
|
||||
associatedEntityMappingType.getIdentifierMapping().getJavaTypeDescriptor()
|
||||
);
|
||||
Fetch fetch = new EntityFetchSelectImpl(
|
||||
this,
|
||||
singularAssociationAttributeMapping,
|
||||
null,
|
||||
false,
|
||||
navigablePath.append( fetchable.getFetchableName() ),
|
||||
domainResult,
|
||||
creationState
|
||||
);
|
||||
fetches.add( fetch );
|
||||
}
|
||||
else {
|
||||
final Fetch fetch = new BasicFetch(
|
||||
sqlSelections.get( atomicInteger.getAndIncrement() ).getValuesArrayPosition(),
|
||||
null,
|
||||
navigablePath.append( fetchable.getFetchableName() ),
|
||||
(BasicValuedModelPart) fetchable,
|
||||
true,
|
||||
null,
|
||||
FetchTiming.IMMEDIATE,
|
||||
creationState
|
||||
);
|
||||
fetches.add( fetch );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResultVariable() {
|
||||
return resultVariable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainResultAssembler<T> createResultAssembler(
|
||||
Consumer<Initializer> initializerCollector, AssemblerCreationState creationState) {
|
||||
final EmbeddableResultInitializer initializer = new EmbeddableResultInitializer(
|
||||
this,
|
||||
initializerCollector,
|
||||
creationState
|
||||
);
|
||||
|
||||
initializerCollector.accept( initializer );
|
||||
|
||||
//noinspection unchecked
|
||||
return new EmbeddableAssembler( initializer );
|
||||
}
|
||||
|
||||
@Override
|
||||
public EmbeddableMappingType getReferencedMappingType() {
|
||||
return (EmbeddableMappingType) getFetchContainer().getPartMappingType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fetch findFetch(String fetchableName) {
|
||||
return super.findFetch( fetchableName );
|
||||
}
|
||||
|
||||
@Override
|
||||
public EmbeddableMappingType getFetchContainer() {
|
||||
return (EmbeddableMappingType) super.getFetchContainer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EmbeddableValuedModelPart getReferencedMappingContainer() {
|
||||
return getFetchContainer().getEmbeddedValueMapping();
|
||||
}
|
||||
}
|
|
@ -51,7 +51,7 @@ public class EntityFetchJoinedImpl extends AbstractNonLazyEntityFetch {
|
|||
FetchParentAccess parentAccess,
|
||||
Consumer<Initializer> collector,
|
||||
AssemblerCreationState creationState) {
|
||||
return new EntityInitializerJoinedFetch(
|
||||
return new EntityJoinedFetchInitializer(
|
||||
entityResult,
|
||||
getNavigablePath(),
|
||||
lockMode,
|
||||
|
|
|
@ -57,7 +57,7 @@ public class EntityFetchSelectImpl extends AbstractNonJoinedEntityFetch {
|
|||
FetchParentAccess parentAccess,
|
||||
Consumer<Initializer> collector,
|
||||
AssemblerCreationState creationState) {
|
||||
final EntityInitializerSelectFetch initializer = new EntityInitializerSelectFetch(
|
||||
final EntitySelectFetchInitializer initializer = new EntitySelectFetchInitializer(
|
||||
getNavigablePath(),
|
||||
getReferencedMappingContainer().getEntityPersister(),
|
||||
result.createResultAssembler( collector, creationState ),
|
||||
|
|
|
@ -20,8 +20,9 @@ import org.hibernate.sql.results.graph.Initializer;
|
|||
/**
|
||||
* @author Andrea Boriero
|
||||
*/
|
||||
public class EntityInitializerJoinedFetch extends AbstractEntityInitializer {
|
||||
protected EntityInitializerJoinedFetch(
|
||||
public class EntityJoinedFetchInitializer extends AbstractEntityInitializer {
|
||||
|
||||
protected EntityJoinedFetchInitializer(
|
||||
EntityResultGraphNode resultDescriptor,
|
||||
NavigablePath navigablePath,
|
||||
LockMode lockMode,
|
|
@ -22,7 +22,7 @@ import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
|
|||
/**
|
||||
* @author Andrea Boriero
|
||||
*/
|
||||
public class EntityInitializerSelectFetch extends AbstractFetchParentAccess implements EntityInitializer {
|
||||
public class EntitySelectFetchInitializer extends AbstractFetchParentAccess implements EntityInitializer {
|
||||
private final NavigablePath navigablePath;
|
||||
private final EntityPersister concreteDescriptor;
|
||||
private final DomainResultAssembler identifierAssembler;
|
||||
|
@ -31,7 +31,7 @@ public class EntityInitializerSelectFetch extends AbstractFetchParentAccess impl
|
|||
|
||||
private Object entityInstance;
|
||||
|
||||
protected EntityInitializerSelectFetch(
|
||||
protected EntitySelectFetchInitializer(
|
||||
NavigablePath fetchedNavigable,
|
||||
EntityPersister concreteDescriptor,
|
||||
DomainResultAssembler identifierAssembler,
|
||||
|
@ -75,7 +75,7 @@ public class EntityInitializerSelectFetch extends AbstractFetchParentAccess impl
|
|||
entityInstance = session.internalLoad(
|
||||
entityName,
|
||||
id,
|
||||
false,
|
||||
true,
|
||||
nullable
|
||||
);
|
||||
|
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
* 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.orm.test.compositefk;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.EmbeddedId;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
|
||||
import org.hibernate.testing.jdbc.SQLStatementInspector;
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.FailureExpected;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.core.Is.is;
|
||||
import static org.hamcrest.core.IsNull.notNullValue;
|
||||
|
||||
/**
|
||||
* @author Andrea Boriero
|
||||
*/
|
||||
@DomainModel(
|
||||
annotatedClasses = {
|
||||
EagerManyToOneEmbeddedIdFKTest.System.class,
|
||||
EagerManyToOneEmbeddedIdFKTest.SystemUser.class
|
||||
}
|
||||
)
|
||||
@SessionFactory(statementInspectorClass = SQLStatementInspector.class)
|
||||
public class EagerManyToOneEmbeddedIdFKTest {
|
||||
|
||||
@BeforeEach
|
||||
public void setUp(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
PK userKey = new PK( 1, "Fab" );
|
||||
SystemUser user = new SystemUser( userKey, "Fab" );
|
||||
|
||||
System system = new System( 1, "sub1" );
|
||||
system.setUser( user );
|
||||
|
||||
session.save( user );
|
||||
session.save( system );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void tearDown(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "delete from System" ).executeUpdate();
|
||||
session.createQuery( "delete from SystemUser" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGet(SessionFactoryScope scope) {
|
||||
SQLStatementInspector statementInspector = (SQLStatementInspector) scope.getStatementInspector();
|
||||
statementInspector.clear();
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
System system = session.get( System.class, 1 );
|
||||
assertThat( system, is( notNullValue() ) );
|
||||
SystemUser user = system.getUser();
|
||||
assertThat( user, is( notNullValue() ) );
|
||||
statementInspector.assertExecutedCount( 1 );
|
||||
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 1 );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHql(SessionFactoryScope scope) {
|
||||
SQLStatementInspector statementInspector = (SQLStatementInspector) scope.getStatementInspector();
|
||||
statementInspector.clear();
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
System system = (System) session.createQuery( "from System e where e.id = :id" )
|
||||
.setParameter( "id", 1 ).uniqueResult();
|
||||
statementInspector.assertExecutedCount( 2 );
|
||||
|
||||
assertThat( system, is( notNullValue() ) );
|
||||
SystemUser user = system.getUser();
|
||||
assertThat( user, is( notNullValue() ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHqlJoin(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
System system = session.createQuery( "from System e join e.user where e.id = :id", System.class )
|
||||
.setParameter( "id", 1 ).uniqueResult();
|
||||
assertThat( system, is( notNullValue() ) );
|
||||
SystemUser user = system.getUser();
|
||||
assertThat( user, is( notNullValue() ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHqlJoinFetch(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
System system = session.createQuery(
|
||||
"from System e join fetch e.user where e.id = :id",
|
||||
System.class
|
||||
)
|
||||
.setParameter( "id", 1 ).uniqueResult();
|
||||
assertThat( system, is( notNullValue() ) );
|
||||
SystemUser user = system.getUser();
|
||||
assertThat( user, is( notNullValue() ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected(reason = "Embedded parameters has not yet been implemented ")
|
||||
public void testEmbeddedIdParameter(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
PK superUserKey = new PK( 1, "Fab" );
|
||||
|
||||
System system = session.createQuery(
|
||||
"from System e join fetch e.user u where u.id = :id",
|
||||
System.class
|
||||
).setParameter( "id", superUserKey ).uniqueResult();
|
||||
|
||||
assertThat( system, is( notNullValue() ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@Entity(name = "System")
|
||||
public static class System {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String name;
|
||||
|
||||
@ManyToOne
|
||||
SystemUser user;
|
||||
|
||||
public System() {
|
||||
}
|
||||
|
||||
public System(Integer id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public SystemUser getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public void setUser(SystemUser user) {
|
||||
this.user = user;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "SystemUser")
|
||||
public static class SystemUser {
|
||||
|
||||
@EmbeddedId
|
||||
private PK pk;
|
||||
|
||||
private String name;
|
||||
|
||||
public SystemUser() {
|
||||
}
|
||||
|
||||
public SystemUser(PK pk, String name) {
|
||||
this.pk = pk;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public PK getPk() {
|
||||
return pk;
|
||||
}
|
||||
|
||||
public void setPk(PK pk) {
|
||||
this.pk = pk;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
public static class PK implements Serializable {
|
||||
|
||||
private Integer subsystem;
|
||||
|
||||
private String username;
|
||||
|
||||
public PK(Integer subsystem, String username) {
|
||||
this.subsystem = subsystem;
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
private PK() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if ( this == o ) {
|
||||
return true;
|
||||
}
|
||||
if ( o == null || getClass() != o.getClass() ) {
|
||||
return false;
|
||||
}
|
||||
PK pk = (PK) o;
|
||||
return Objects.equals( subsystem, pk.subsystem ) &&
|
||||
Objects.equals( username, pk.username );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash( subsystem, username );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,389 @@
|
|||
/*
|
||||
* 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.orm.test.compositefk;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.EmbeddedId;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
|
||||
import org.hibernate.testing.jdbc.SQLStatementInspector;
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.FailureExpected;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.core.Is.is;
|
||||
import static org.hamcrest.core.IsNull.notNullValue;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Andrea Boriero
|
||||
*/
|
||||
@DomainModel(
|
||||
annotatedClasses = {
|
||||
ManyToOneEmbeddedIdWithToOneFKTest.System.class,
|
||||
ManyToOneEmbeddedIdWithToOneFKTest.SystemUser.class,
|
||||
ManyToOneEmbeddedIdWithToOneFKTest.Subsystem.class
|
||||
}
|
||||
)
|
||||
@SessionFactory(statementInspectorClass = SQLStatementInspector.class)
|
||||
public class ManyToOneEmbeddedIdWithToOneFKTest {
|
||||
|
||||
@BeforeEach
|
||||
public void setUp(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
Subsystem subsystem = new Subsystem( 2, "sub1" );
|
||||
PK userKey = new PK( subsystem, "Fab" );
|
||||
SystemUser user = new SystemUser( userKey, "Fab" );
|
||||
|
||||
System system = new System( 1, "sub1" );
|
||||
system.setUser( user );
|
||||
|
||||
session.save( subsystem );
|
||||
session.save( user );
|
||||
session.save( system );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void tearDown(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "delete from System" ).executeUpdate();
|
||||
session.createQuery( "delete from SystemUser" ).executeUpdate();
|
||||
session.createQuery( "delete from Subsystem" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGet(SessionFactoryScope scope) {
|
||||
SQLStatementInspector statementInspector = (SQLStatementInspector) scope.getStatementInspector();
|
||||
statementInspector.clear();
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
System system = session.get( System.class, 1 );
|
||||
assertThat( system, is( notNullValue() ) );
|
||||
|
||||
assertTrue( Hibernate.isInitialized( system.getUser() ) );
|
||||
assertTrue( Hibernate.isInitialized( system.getUser().getPk().subsystem ) );
|
||||
|
||||
SystemUser user = system.getUser();
|
||||
assertThat( user, is( notNullValue() ) );
|
||||
|
||||
statementInspector.assertExecutedCount( 1 );
|
||||
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 2 );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHql(SessionFactoryScope scope) {
|
||||
SQLStatementInspector statementInspector = (SQLStatementInspector) scope.getStatementInspector();
|
||||
statementInspector.clear();
|
||||
/*
|
||||
select
|
||||
s1_0.id_,
|
||||
s1_0.name as name2_1_,
|
||||
s1_0.user_subsystem_id ,
|
||||
s1_0.user_username_
|
||||
from
|
||||
System s1_0
|
||||
where
|
||||
s1_0.id=?
|
||||
|
||||
select
|
||||
s2_0.id,
|
||||
s2_0.description_
|
||||
from
|
||||
Subsystem s2_0
|
||||
where
|
||||
s2_0.id=?
|
||||
|
||||
select
|
||||
manytoonee0_.subsystem_id as subsyste3_2_0_,
|
||||
manytoonee0_.username as username1_2_0_,
|
||||
manytoonee0_.name as name2_2_0_
|
||||
from
|
||||
SystemUser manytoonee0_
|
||||
where
|
||||
manytoonee0_.subsystem_id=?
|
||||
and manytoonee0_.username=?
|
||||
*/
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
System system = (System) session.createQuery( "from System e where e.id = :id" )
|
||||
.setParameter( "id", 1 ).uniqueResult();
|
||||
|
||||
assertThat( system, is( notNullValue() ) );
|
||||
|
||||
statementInspector.assertExecutedCount( 3 );
|
||||
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 0 );
|
||||
statementInspector.assertNumberOfOccurrenceInQuery( 1, "join", 0 );
|
||||
statementInspector.assertNumberOfOccurrenceInQuery( 2, "join", 0 );
|
||||
|
||||
|
||||
assertTrue( Hibernate.isInitialized( system.getUser() ) );
|
||||
assertTrue( Hibernate.isInitialized( system.getUser().getPk().subsystem ) );
|
||||
|
||||
assertThat( system.getUser().getPk().subsystem.getDescription(),is("Fab"));
|
||||
|
||||
|
||||
SystemUser user = system.getUser();
|
||||
assertThat( user, is( notNullValue() ) );
|
||||
statementInspector.assertExecutedCount( 3 );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHqlJoin(SessionFactoryScope scope) {
|
||||
SQLStatementInspector statementInspector = (SQLStatementInspector) scope.getStatementInspector();
|
||||
statementInspector.clear();
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
System system = session.createQuery( "from System e join e.user where e.id = :id", System.class )
|
||||
.setParameter( "id", 1 ).uniqueResult();
|
||||
statementInspector.assertExecutedCount( 3 );
|
||||
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 1 );
|
||||
statementInspector.assertNumberOfOccurrenceInQuery( 1, "join", 0 );
|
||||
statementInspector.assertNumberOfOccurrenceInQuery( 2, "join", 0 );
|
||||
assertThat( system, is( notNullValue() ) );
|
||||
SystemUser user = system.getUser();
|
||||
assertThat( user, is( notNullValue() ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHqlJoinFetch(SessionFactoryScope scope) {
|
||||
SQLStatementInspector statementInspector = (SQLStatementInspector) scope.getStatementInspector();
|
||||
statementInspector.clear();
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
System system = session.createQuery(
|
||||
"from System e join fetch e.user where e.id = :id",
|
||||
System.class
|
||||
)
|
||||
.setParameter( "id", 1 ).uniqueResult();
|
||||
statementInspector.assertExecutedCount( 2 );
|
||||
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 1 );
|
||||
statementInspector.assertNumberOfOccurrenceInQuery( 1, "join", 0 );
|
||||
assertThat( system, is( notNullValue() ) );
|
||||
SystemUser user = system.getUser();
|
||||
assertThat( user, is( notNullValue() ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected(reason = "Embedded parameters has not yet been implemented ")
|
||||
public void testEmbeddedIdParameter(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
Subsystem subsystem = new Subsystem( 2, "sub1" );
|
||||
|
||||
PK superUserKey = new PK( subsystem, "Fab" );
|
||||
|
||||
System system = session.createQuery(
|
||||
"from System e join fetch e.user u where u.id = :id",
|
||||
System.class
|
||||
).setParameter( "id", superUserKey ).uniqueResult();
|
||||
|
||||
assertThat( system, is( notNullValue() ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHql2(SessionFactoryScope scope) {
|
||||
SQLStatementInspector statementInspector = (SQLStatementInspector) scope.getStatementInspector();
|
||||
statementInspector.clear();
|
||||
/*
|
||||
select
|
||||
s1_0.subsystem_id,
|
||||
s1_0.username,
|
||||
s1_0.name
|
||||
from
|
||||
SystemUser as s1_0
|
||||
|
||||
select
|
||||
s1_0.id,
|
||||
s1_0.description
|
||||
from
|
||||
Subsystem s1_0
|
||||
where
|
||||
s1_0.id=?
|
||||
*/
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
SystemUser system = (SystemUser) session.createQuery( "from SystemUser " )
|
||||
.uniqueResult();
|
||||
assertThat( system, is( notNullValue() ) );
|
||||
|
||||
statementInspector.assertExecutedCount( 2 );
|
||||
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 0 );
|
||||
statementInspector.assertNumberOfOccurrenceInQuery( 1, "join", 0 );
|
||||
|
||||
assertTrue( Hibernate.isInitialized( system.getPk().subsystem ) );
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@Entity(name = "System")
|
||||
public static class System {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String name;
|
||||
|
||||
@ManyToOne
|
||||
SystemUser user;
|
||||
|
||||
public System() {
|
||||
}
|
||||
|
||||
public System(Integer id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public SystemUser getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public void setUser(SystemUser user) {
|
||||
this.user = user;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "SystemUser")
|
||||
public static class SystemUser {
|
||||
|
||||
@EmbeddedId
|
||||
private PK pk;
|
||||
|
||||
private String name;
|
||||
|
||||
public SystemUser() {
|
||||
}
|
||||
|
||||
public SystemUser(PK pk, String name) {
|
||||
this.pk = pk;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public PK getPk() {
|
||||
return pk;
|
||||
}
|
||||
|
||||
public void setPk(PK pk) {
|
||||
this.pk = pk;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
public static class PK implements Serializable {
|
||||
|
||||
@ManyToOne
|
||||
private Subsystem subsystem;
|
||||
|
||||
private String username;
|
||||
|
||||
public PK(Subsystem subsystem, String username) {
|
||||
this.subsystem = subsystem;
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
private PK() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if ( this == o ) {
|
||||
return true;
|
||||
}
|
||||
if ( o == null || getClass() != o.getClass() ) {
|
||||
return false;
|
||||
}
|
||||
PK pk = (PK) o;
|
||||
return Objects.equals( subsystem, pk.subsystem ) &&
|
||||
Objects.equals( username, pk.username );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash( subsystem, username );
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Subsystem")
|
||||
public static class Subsystem {
|
||||
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
private String description;
|
||||
|
||||
public Subsystem() {
|
||||
}
|
||||
|
||||
public Subsystem(Integer id, String description) {
|
||||
this.id = id;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
// public Integer getId() {
|
||||
// return id;
|
||||
// }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
* 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.orm.test.compositefk;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.EmbeddedId;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToMany;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.FailureExpected;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.core.Is.is;
|
||||
import static org.hamcrest.core.IsNull.notNullValue;
|
||||
|
||||
/**
|
||||
* @author Andrea Boriero
|
||||
*/
|
||||
@DomainModel(
|
||||
annotatedClasses = {
|
||||
OneToManyEmbeddedIdFKTest.System.class,
|
||||
OneToManyEmbeddedIdFKTest.SystemUser.class
|
||||
}
|
||||
)
|
||||
@SessionFactory
|
||||
public class OneToManyEmbeddedIdFKTest {
|
||||
|
||||
@BeforeEach
|
||||
public void setUp(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
|
||||
PK superUserKey = new PK( 1, "Fab" );
|
||||
SystemUser superUser = new SystemUser( superUserKey, "Fab" );
|
||||
|
||||
PK userKey = new PK( 2, "Andrea" );
|
||||
SystemUser user = new SystemUser( userKey, "Andrea" );
|
||||
|
||||
System system = new System( 1, "sub1" );
|
||||
system.addUser( superUser );
|
||||
system.addUser( user );
|
||||
|
||||
session.save( superUser );
|
||||
session.save( user );
|
||||
session.save( system );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void tearDown(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "delete from System" ).executeUpdate();
|
||||
session.createQuery( "delete from SystemUser" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGet(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
System system = session.get( System.class, 1 );
|
||||
assertThat( system, is( notNullValue() ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHqlQuery(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
System system = (System) session.createQuery( "from System e where e.id = :id" )
|
||||
.setParameter( "id", 1 ).uniqueResult();
|
||||
assertThat( system, is( notNullValue() ) );
|
||||
assertThat( system.getUsers().size(), is( 2 ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHqlJoin(SessionFactoryScope scope) {
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
System system = session.createQuery( "from System e join e.users where e.id = :id", System.class )
|
||||
.setParameter( "id", 1 ).uniqueResult();
|
||||
assertThat( system, is( notNullValue() ) );
|
||||
assertThat( system.getUsers().size(), is( 2 ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHqlJoinFetch(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
System system = session.createQuery(
|
||||
"from System e join fetch e.users where e.id = :id",
|
||||
System.class
|
||||
)
|
||||
.setParameter( "id", 1 ).uniqueResult();
|
||||
assertThat( system, is( notNullValue() ) );
|
||||
assertThat( system.getUsers().size(), is( 2 ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected(reason = "Embedded parameters has not yet been implemented ")
|
||||
public void testEmbeddedIdParameter(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
PK superUserKey = new PK( 1, "Fab" );
|
||||
|
||||
System system = session.createQuery(
|
||||
"from System e join fetch e.users u where u.id = :id",
|
||||
System.class
|
||||
).setParameter( "id", superUserKey ).uniqueResult();
|
||||
|
||||
assertThat( system, is( notNullValue() ) );
|
||||
assertThat( system.getUsers().size(), is( 2 ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Entity(name = "System")
|
||||
public static class System {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String name;
|
||||
|
||||
@OneToMany
|
||||
List<SystemUser> users = new ArrayList<>();
|
||||
|
||||
public System() {
|
||||
}
|
||||
|
||||
public System(Integer id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<SystemUser> getUsers() {
|
||||
return users;
|
||||
}
|
||||
|
||||
public void setUsers(List<SystemUser> users) {
|
||||
this.users = users;
|
||||
}
|
||||
|
||||
public void addUser(SystemUser user) {
|
||||
this.users.add( user );
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "SystemUser")
|
||||
public static class SystemUser {
|
||||
|
||||
@EmbeddedId
|
||||
private PK pk;
|
||||
|
||||
private String name;
|
||||
|
||||
public SystemUser() {
|
||||
}
|
||||
|
||||
public SystemUser(PK pk, String name) {
|
||||
this.pk = pk;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public PK getPk() {
|
||||
return pk;
|
||||
}
|
||||
|
||||
public void setPk(PK pk) {
|
||||
this.pk = pk;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
public static class PK implements Serializable {
|
||||
|
||||
private Integer subsystem;
|
||||
|
||||
private String username;
|
||||
|
||||
public PK(Integer subsystem, String username) {
|
||||
this.subsystem = subsystem;
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
private PK() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if ( this == o ) {
|
||||
return true;
|
||||
}
|
||||
if ( o == null || getClass() != o.getClass() ) {
|
||||
return false;
|
||||
}
|
||||
PK pk = (PK) o;
|
||||
return Objects.equals( subsystem, pk.subsystem ) &&
|
||||
Objects.equals( username, pk.username );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash( subsystem, username );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,7 +8,6 @@ package org.hibernate.orm.test.onetoone;
|
|||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.MapsId;
|
||||
|
|
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* 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>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.orm.test.sql.exec;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
|
||||
import org.hibernate.testing.jdbc.SQLStatementInspector;
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Andrea Boriero
|
||||
*/
|
||||
@DomainModel(
|
||||
annotatedClasses = {
|
||||
EmbeddedWithManyToOneTest.SystemUser.class,
|
||||
EmbeddedWithManyToOneTest.Subsystem.class
|
||||
}
|
||||
)
|
||||
@SessionFactory(
|
||||
generateStatistics = true,
|
||||
statementInspectorClass = SQLStatementInspector.class)
|
||||
public class EmbeddedWithManyToOneTest {
|
||||
|
||||
@BeforeEach
|
||||
public void setUp(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
Subsystem subsystem = new Subsystem( 2, "sub1" );
|
||||
PK userKey = new PK( subsystem, "Fab" );
|
||||
SystemUser user = new SystemUser( 1, userKey, "Fab" );
|
||||
|
||||
session.save( subsystem );
|
||||
session.save( user );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void tearDown(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "delete from SystemUser" ).executeUpdate();
|
||||
session.createQuery( "delete from Subsystem" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGet(SessionFactoryScope scope) {
|
||||
SQLStatementInspector statementInspector = (SQLStatementInspector) scope.getStatementInspector();
|
||||
statementInspector.clear();
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
SystemUser systemUser = session.get( SystemUser.class, 1 );
|
||||
assertTrue( Hibernate.isInitialized( systemUser.getPk() ) );
|
||||
statementInspector.assertExecutedCount( 1 );
|
||||
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 1 );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHqlSelect(SessionFactoryScope scope) {
|
||||
SQLStatementInspector statementInspector = (SQLStatementInspector) scope.getStatementInspector();
|
||||
statementInspector.clear();
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
SystemUser systemUser = session.createQuery( "from SystemUser", SystemUser.class )
|
||||
.uniqueResult();
|
||||
assertTrue( Hibernate.isInitialized( systemUser.getPk() ) );
|
||||
statementInspector.assertExecutedCount( 2 );
|
||||
statementInspector.assertNumberOfOccurrenceInQuery( 1, "join", 0 );
|
||||
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 0 );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Entity(name = "SystemUser")
|
||||
public static class SystemUser {
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
@Embedded
|
||||
private PK pk;
|
||||
|
||||
private String name;
|
||||
|
||||
public SystemUser() {
|
||||
}
|
||||
|
||||
public SystemUser(Integer id, PK pk, String name) {
|
||||
this.id = id;
|
||||
this.pk = pk;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public PK getPk() {
|
||||
return pk;
|
||||
}
|
||||
|
||||
public void setPk(PK pk) {
|
||||
this.pk = pk;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
public static class PK implements Serializable {
|
||||
|
||||
@ManyToOne
|
||||
private Subsystem subsystem;
|
||||
|
||||
private String username;
|
||||
|
||||
public PK(Subsystem subsystem, String username) {
|
||||
this.subsystem = subsystem;
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
private PK() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if ( this == o ) {
|
||||
return true;
|
||||
}
|
||||
if ( o == null || getClass() != o.getClass() ) {
|
||||
return false;
|
||||
}
|
||||
PK pk = (PK) o;
|
||||
return Objects.equals( subsystem, pk.subsystem ) &&
|
||||
Objects.equals( username, pk.username );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash( subsystem, username );
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Subsystem")
|
||||
public static class Subsystem {
|
||||
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
private String description;
|
||||
|
||||
public Subsystem() {
|
||||
}
|
||||
|
||||
public Subsystem(Integer id, String description) {
|
||||
this.id = id;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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.testing.jdbc;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
import org.hibernate.resource.jdbc.spi.StatementInspector;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Andrea Boriero
|
||||
*/
|
||||
public class SQLStatementInspector implements StatementInspector {
|
||||
private final LinkedList<String> sqlQueries = new LinkedList<>();
|
||||
|
||||
public SQLStatementInspector() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String inspect(String sql) {
|
||||
sqlQueries.add( sql );
|
||||
return sql;
|
||||
}
|
||||
|
||||
public LinkedList<String> getSqlQueries() {
|
||||
return sqlQueries;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
sqlQueries.clear();
|
||||
}
|
||||
|
||||
public void assertExecuted(String expected) {
|
||||
assertTrue( sqlQueries.contains( expected ) );
|
||||
}
|
||||
|
||||
public void assertExecutedCount(int expected) {
|
||||
assertEquals( expected, sqlQueries.size() );
|
||||
}
|
||||
|
||||
public void assertNumberOfOccurrenceInQuery(int queryNumber, String toCheck, int expectedNumberOfOccurrences) {
|
||||
String query = sqlQueries.get( queryNumber );
|
||||
int actual = query.split( toCheck, -1 ).length - 1;
|
||||
assertThat( actual, is( expectedNumberOfOccurrences ) );
|
||||
}
|
||||
}
|
|
@ -406,5 +406,10 @@ public class SessionFactoryExtension
|
|||
public MetadataImplementor getMetadataImplementor() {
|
||||
return modelScope.getDomainModel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatementInspector getStatementInspector() {
|
||||
return getSessionFactory().getSessionFactoryOptions().getStatementInspector();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import java.util.function.Function;
|
|||
import org.hibernate.boot.spi.MetadataImplementor;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.resource.jdbc.spi.StatementInspector;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
|
@ -30,4 +31,6 @@ public interface SessionFactoryScope {
|
|||
<T> T fromTransaction(SessionImplementor session, Function<SessionImplementor, T> action);
|
||||
|
||||
MetadataImplementor getMetadataImplementor();
|
||||
|
||||
StatementInspector getStatementInspector();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue