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 List<DomainResult> domainResults = new ArrayList<>();
|
||||||
|
|
||||||
final NavigablePath idPath = rootPath.append( EntityIdentifierMapping.ROLE_LOCAL_NAME );
|
|
||||||
entityDescriptor.getIdentifierMapping().visitColumns(
|
entityDescriptor.getIdentifierMapping().visitColumns(
|
||||||
(tab, col, jdbcMapping) -> {
|
(tab, col, jdbcMapping) -> {
|
||||||
final TableReference tableReference = rootTableGroup.resolveTableReference( tab );
|
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.Loadable;
|
||||||
import org.hibernate.loader.ast.spi.Loader;
|
import org.hibernate.loader.ast.spi.Loader;
|
||||||
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
||||||
|
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
|
@ -477,8 +478,11 @@ public class LoaderSelectBuilder {
|
||||||
LoaderSqlAstCreationState creationState,
|
LoaderSqlAstCreationState creationState,
|
||||||
List<Fetch> fetches) {
|
List<Fetch> fetches) {
|
||||||
return (fetchable, isKeyFetchable) -> {
|
return (fetchable, isKeyFetchable) -> {
|
||||||
|
NavigablePath navigablePath = fetchParent.getNavigablePath();
|
||||||
final NavigablePath fetchablePath = fetchParent.getNavigablePath().append( fetchable.getFetchableName() );
|
if ( isKeyFetchable ) {
|
||||||
|
navigablePath = navigablePath.append( EntityIdentifierMapping.ROLE_LOCAL_NAME );
|
||||||
|
}
|
||||||
|
final NavigablePath fetchablePath = navigablePath.append( fetchable.getFetchableName() );
|
||||||
|
|
||||||
final Fetch biDirectionalFetch = fetchable.resolveCircularFetch(
|
final Fetch biDirectionalFetch = fetchable.resolveCircularFetch(
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
|
|
|
@ -155,7 +155,9 @@ public class LoaderSqlAstCreationState
|
||||||
if ( tableGroup.getNavigablePath().equals( navigablePath ) ) {
|
if ( tableGroup.getNavigablePath().equals( navigablePath ) ) {
|
||||||
return tableGroup;
|
return tableGroup;
|
||||||
}
|
}
|
||||||
if(tableGroup.getNavigablePath().getIdentifierForTableGroup().equals( navigablePath.getIdentifierForTableGroup() )){
|
if ( tableGroup.getNavigablePath()
|
||||||
|
.getIdentifierForTableGroup()
|
||||||
|
.equals( navigablePath.getIdentifierForTableGroup() ) ) {
|
||||||
return tableGroup;
|
return tableGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ import org.hibernate.loader.internal.AliasConstantsHelper;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
|
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
|
||||||
import org.hibernate.sql.Template;
|
import org.hibernate.sql.Template;
|
||||||
|
import org.hibernate.type.ComponentType;
|
||||||
import org.hibernate.type.EntityType;
|
import org.hibernate.type.EntityType;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
|
@ -245,7 +246,10 @@ public class Column implements Selectable, Serializable, Cloneable {
|
||||||
&& size.getScale() == null && size.getPrecision() == null ) {
|
&& size.getScale() == null && size.getPrecision() == null ) {
|
||||||
if ( type instanceof EntityType ) {
|
if ( type instanceof EntityType ) {
|
||||||
//ManyToOneType doesn't implement JdbcMapping
|
//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 ) {
|
if ( type instanceof JdbcMapping ) {
|
||||||
size = dialect.getDefaultSizeStrategy().resolveDefaultSize(
|
size = dialect.getDefaultSizeStrategy().resolveDefaultSize(
|
||||||
|
|
|
@ -318,16 +318,18 @@ public class EmbeddableMappingType implements ManagedMappingType {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object disassemble(Object value, SharedSessionContractImplementor session) {
|
public Object disassemble(Object value, SharedSessionContractImplementor session) {
|
||||||
throw new NotYetImplementedFor6Exception( getClass() );
|
final Collection<AttributeMapping> attributeMappings = getAttributeMappings();
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
Object[] result = new Object[attributeMappings.size()];
|
||||||
public void visitDisassembledJdbcValues(
|
int i = 0;
|
||||||
Object value,
|
final Iterator<AttributeMapping> iterator = attributeMappings.iterator();
|
||||||
Clause clause,
|
while ( iterator.hasNext() ) {
|
||||||
JdbcValuesConsumer valuesConsumer,
|
AttributeMapping mapping = iterator.next();
|
||||||
SharedSessionContractImplementor session) {
|
Object o = mapping.getPropertyAccess().getGetter().get( value );
|
||||||
throw new NotYetImplementedFor6Exception( getClass() );
|
result[i] = mapping.disassemble( o, session );
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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) {
|
public void visitColumns(ColumnConsumer consumer) {
|
||||||
attributeMappings.values().forEach(
|
attributeMappings.values().forEach(
|
||||||
attributeMapping -> attributeMapping.visitColumns( consumer )
|
attributeMapping -> attributeMapping.visitColumns( consumer )
|
||||||
|
|
|
@ -68,7 +68,7 @@ public interface EntityValuedModelPart extends FetchableContainer {
|
||||||
Consumer<JdbcMapping> action,
|
Consumer<JdbcMapping> action,
|
||||||
Clause clause,
|
Clause clause,
|
||||||
TypeConfiguration typeConfiguration) {
|
TypeConfiguration typeConfiguration) {
|
||||||
getEntityMappingType().getJdbcTypeCount( typeConfiguration );
|
getEntityMappingType().visitJdbcTypes( action, clause, typeConfiguration );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -25,7 +25,7 @@ public interface ForeignKeyDescriptor extends VirtualModelPart {
|
||||||
|
|
||||||
ForeignKeyDirection getDirection();
|
ForeignKeyDirection getDirection();
|
||||||
|
|
||||||
DomainResult createCollectionFecthDomainResult(
|
DomainResult createCollectionFetchDomainResult(
|
||||||
NavigablePath collectionPath,
|
NavigablePath collectionPath,
|
||||||
TableGroup tableGroup,
|
TableGroup tableGroup,
|
||||||
DomainResultCreationState creationState);
|
DomainResultCreationState creationState);
|
||||||
|
@ -54,6 +54,10 @@ public interface ForeignKeyDescriptor extends VirtualModelPart {
|
||||||
return PART_NAME;
|
return PART_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String getReferringTableExpression();
|
||||||
|
|
||||||
|
String getTargetTableExpression();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visits the FK "referring" columns
|
* Visits the FK "referring" columns
|
||||||
*/
|
*/
|
||||||
|
@ -62,36 +66,10 @@ public interface ForeignKeyDescriptor extends VirtualModelPart {
|
||||||
visitReferringColumns( consumer );
|
visitReferringColumns( consumer );
|
||||||
}
|
}
|
||||||
|
|
||||||
String getReferringTableExpression();
|
|
||||||
|
|
||||||
void visitReferringColumns(ColumnConsumer consumer);
|
void visitReferringColumns(ColumnConsumer consumer);
|
||||||
|
|
||||||
String getTargetTableExpression();
|
|
||||||
|
|
||||||
void visitTargetColumns(ColumnConsumer consumer);
|
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
|
* @author Andrea Boriero
|
||||||
*/
|
*/
|
||||||
public class EmbeddedIdentifierMappingImpl implements CompositeIdentifierMapping, SingleAttributeIdentifierMapping, EmbeddableValuedFetchable {
|
public class EmbeddedIdentifierMappingImpl implements CompositeIdentifierMapping, EmbeddableValuedFetchable {
|
||||||
private final NavigableRole navigableRole;
|
private final NavigableRole navigableRole;
|
||||||
private final EntityMappingType entityMapping;
|
private final EntityMappingType entityMapping;
|
||||||
private final String name;
|
private final String name;
|
||||||
|
@ -161,12 +161,28 @@ public class EmbeddedIdentifierMappingImpl implements CompositeIdentifierMapping
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitJdbcValues(
|
public void visitJdbcValues(
|
||||||
Object value, Clause clause, JdbcValuesConsumer valuesConsumer, SharedSessionContractImplementor session) {
|
Object value,
|
||||||
getEmbeddableTypeDescriptor().visitJdbcValues( value, clause, valuesConsumer, session );
|
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
|
@Override
|
||||||
public <T> DomainResult<T> createDomainResult(
|
public <T> DomainResult<T> createDomainResult(
|
||||||
NavigablePath navigablePath,
|
NavigablePath navigablePath,
|
||||||
|
@ -218,7 +234,6 @@ public class EmbeddedIdentifierMappingImpl implements CompositeIdentifierMapping
|
||||||
);
|
);
|
||||||
|
|
||||||
return new SqlTuple( columnReferences, this );
|
return new SqlTuple( columnReferences, this );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -237,13 +252,10 @@ public class EmbeddedIdentifierMappingImpl implements CompositeIdentifierMapping
|
||||||
lhs
|
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(
|
return join;
|
||||||
navigablePath,
|
|
||||||
sqlAstJoinType,
|
|
||||||
compositeTableGroup
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -258,7 +270,8 @@ public class EmbeddedIdentifierMappingImpl implements CompositeIdentifierMapping
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitSubParts(
|
public void visitSubParts(
|
||||||
Consumer<ModelPart> consumer, EntityMappingType treatTargetType) {
|
Consumer<ModelPart> consumer,
|
||||||
|
EntityMappingType treatTargetType) {
|
||||||
getMappedTypeDescriptor().visitSubParts( consumer, treatTargetType );
|
getMappedTypeDescriptor().visitSubParts( consumer, treatTargetType );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,8 +310,19 @@ public class EmbeddedIdentifierMappingImpl implements CompositeIdentifierMapping
|
||||||
return getEmbeddableTypeDescriptor().getNumberOfAttributeMappings();
|
return getEmbeddableTypeDescriptor().getNumberOfAttributeMappings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void visitColumns(ColumnConsumer consumer) {
|
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
|
@Override
|
||||||
|
@ -317,8 +341,4 @@ public class EmbeddedIdentifierMappingImpl implements CompositeIdentifierMapping
|
||||||
return (Collection) getEmbeddableTypeDescriptor().getAttributeMappings();
|
return (Collection) getEmbeddableTypeDescriptor().getAttributeMappings();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public PropertyAccess getPropertyAccess() {
|
|
||||||
return propertyAccess;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
package org.hibernate.metamodel.mapping.internal;
|
package org.hibernate.metamodel.mapping.internal;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.SortedMap;
|
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.CollectionPart;
|
||||||
import org.hibernate.metamodel.mapping.CompositeIdentifierMapping;
|
import org.hibernate.metamodel.mapping.CompositeIdentifierMapping;
|
||||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||||
|
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||||
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||||
|
@ -229,7 +231,10 @@ public class MappingModelCreationHelper {
|
||||||
.getDomainModel()
|
.getDomainModel()
|
||||||
.getTypeConfiguration()
|
.getTypeConfiguration()
|
||||||
.getBasicTypeRegistry()
|
.getBasicTypeRegistry()
|
||||||
.resolve( valueConverter.getRelationalJavaDescriptor(), resolution.getRelationalSqlTypeDescriptor() );
|
.resolve(
|
||||||
|
valueConverter.getRelationalJavaDescriptor(),
|
||||||
|
resolution.getRelationalSqlTypeDescriptor()
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
return new BasicValuedSingularAttributeMapping(
|
return new BasicValuedSingularAttributeMapping(
|
||||||
|
@ -474,15 +479,6 @@ public class MappingModelCreationHelper {
|
||||||
final CollectionMappingType<?> collectionMappingType;
|
final CollectionMappingType<?> collectionMappingType;
|
||||||
final JavaTypeDescriptorRegistry jtdRegistry = creationContext.getJavaTypeDescriptorRegistry();
|
final JavaTypeDescriptorRegistry jtdRegistry = creationContext.getJavaTypeDescriptorRegistry();
|
||||||
|
|
||||||
final ForeignKeyDescriptor keyDescriptor = interpretKeyDescriptor(
|
|
||||||
bootProperty,
|
|
||||||
bootValueMapping,
|
|
||||||
collectionDescriptor,
|
|
||||||
declaringType,
|
|
||||||
dialect,
|
|
||||||
creationProcess
|
|
||||||
);
|
|
||||||
|
|
||||||
final CollectionPart elementDescriptor = interpretElement(
|
final CollectionPart elementDescriptor = interpretElement(
|
||||||
bootValueMapping,
|
bootValueMapping,
|
||||||
tableExpression,
|
tableExpression,
|
||||||
|
@ -662,7 +658,6 @@ public class MappingModelCreationHelper {
|
||||||
entityMappingType -> contributorMetadata,
|
entityMappingType -> contributorMetadata,
|
||||||
collectionMappingType,
|
collectionMappingType,
|
||||||
stateArrayPosition,
|
stateArrayPosition,
|
||||||
keyDescriptor,
|
|
||||||
elementDescriptor,
|
elementDescriptor,
|
||||||
indexDescriptor,
|
indexDescriptor,
|
||||||
identifierDescriptor,
|
identifierDescriptor,
|
||||||
|
@ -678,6 +673,7 @@ public class MappingModelCreationHelper {
|
||||||
declaringType,
|
declaringType,
|
||||||
collectionDescriptor
|
collectionDescriptor
|
||||||
);
|
);
|
||||||
|
|
||||||
creationProcess.registerInitializationCallback(
|
creationProcess.registerInitializationCallback(
|
||||||
() -> {
|
() -> {
|
||||||
try {
|
try {
|
||||||
|
@ -693,11 +689,25 @@ public class MappingModelCreationHelper {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
creationProcess.registerForeignKeyPostInitCallbacks(
|
||||||
|
() -> {
|
||||||
|
interpretKeyDescriptor(
|
||||||
|
pluralAttributeMapping,
|
||||||
|
bootValueMapping,
|
||||||
|
collectionDescriptor,
|
||||||
|
declaringType,
|
||||||
|
dialect,
|
||||||
|
creationProcess
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
return pluralAttributeMapping;
|
return pluralAttributeMapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ForeignKeyDescriptor interpretKeyDescriptor(
|
private static void interpretKeyDescriptor(
|
||||||
Property bootProperty,
|
PluralAttributeMappingImpl attributeMapping,
|
||||||
Collection bootValueMapping,
|
Collection bootValueMapping,
|
||||||
CollectionPersister collectionDescriptor,
|
CollectionPersister collectionDescriptor,
|
||||||
ManagedMappingType declaringType,
|
ManagedMappingType declaringType,
|
||||||
|
@ -720,19 +730,53 @@ public class MappingModelCreationHelper {
|
||||||
assert fkTarget instanceof BasicValuedModelPart;
|
assert fkTarget instanceof BasicValuedModelPart;
|
||||||
final BasicValuedModelPart simpleFkTarget = (BasicValuedModelPart) fkTarget;
|
final BasicValuedModelPart simpleFkTarget = (BasicValuedModelPart) fkTarget;
|
||||||
|
|
||||||
return new SimpleForeignKeyDescriptor(
|
attributeMapping.setForeignKeyDescriptor(
|
||||||
( (AssociationType) bootValueMapping.getType() ).getForeignKeyDirection(),
|
new SimpleForeignKeyDescriptor(
|
||||||
getTableIdentifierExpression( bootValueMappingKey.getTable(), creationProcess ),
|
( (AssociationType) bootValueMapping.getType() ).getForeignKeyDirection(),
|
||||||
bootValueMappingKey.getColumnIterator().next().getText( dialect ),
|
getTableIdentifierExpression( bootValueMappingKey.getTable(), creationProcess ),
|
||||||
simpleFkTarget.getContainingTableExpression(),
|
bootValueMappingKey.getColumnIterator().next().getText( dialect ),
|
||||||
simpleFkTarget.getMappedColumnExpression(),
|
simpleFkTarget.getContainingTableExpression(),
|
||||||
(JdbcMapping) keyType
|
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(
|
creationProcess
|
||||||
"Support for composite foreign-keys not yet implemented: " + bootValueMapping.getRole()
|
);
|
||||||
);
|
attributeMapping.setForeignKeyDescriptor( embeddedForeignKeyDescriptor );
|
||||||
|
}else {
|
||||||
|
|
||||||
|
throw new NotYetImplementedFor6Exception(
|
||||||
|
"Support for composite foreign-keys not yet implemented: " + bootValueMapping.getRole()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void interpretKeyDescriptor(
|
public static void interpretKeyDescriptor(
|
||||||
|
@ -781,7 +825,6 @@ public class MappingModelCreationHelper {
|
||||||
|
|
||||||
);
|
);
|
||||||
attributeMapping.setForeignKeyDescriptor( foreignKeyDescriptor );
|
attributeMapping.setForeignKeyDescriptor( foreignKeyDescriptor );
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
SingularAssociationAttributeMapping subPart = (SingularAssociationAttributeMapping) referencedEntityDescriptor
|
SingularAssociationAttributeMapping subPart = (SingularAssociationAttributeMapping) referencedEntityDescriptor
|
||||||
|
@ -803,13 +846,45 @@ public class MappingModelCreationHelper {
|
||||||
creationProcess
|
creationProcess
|
||||||
);
|
);
|
||||||
attributeMapping.setForeignKeyDescriptor( subPart.getForeignKeyDescriptor() );
|
attributeMapping.setForeignKeyDescriptor( subPart.getForeignKeyDescriptor() );
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
attributeMapping.setForeignKeyDescriptor( foreignKeyDescriptor );
|
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 {
|
else {
|
||||||
throw new NotYetImplementedFor6Exception(
|
throw new NotYetImplementedFor6Exception(
|
||||||
"Support for composite foreign-keys not yet implemented: " +
|
"Support for composite foreign-keys not yet implemented: " +
|
||||||
|
@ -1091,7 +1166,7 @@ public class MappingModelCreationHelper {
|
||||||
propertyAccess
|
propertyAccess
|
||||||
);
|
);
|
||||||
|
|
||||||
creationProcess.registerInitializationCallback(
|
creationProcess.registerForeignKeyPostInitCallbacks(
|
||||||
() -> {
|
() -> {
|
||||||
final Dialect dialect = creationProcess.getCreationContext()
|
final Dialect dialect = creationProcess.getCreationContext()
|
||||||
.getSessionFactory()
|
.getSessionFactory()
|
||||||
|
|
|
@ -37,6 +37,9 @@ public class MappingModelCreationProcess {
|
||||||
|
|
||||||
private String currentlyProcessingRole;
|
private String currentlyProcessingRole;
|
||||||
|
|
||||||
|
private List<PostInitCallback> postInitCallbacks;
|
||||||
|
private List<PostInitCallback> foreignKeyPostInitCallbacks;
|
||||||
|
|
||||||
private MappingModelCreationProcess(
|
private MappingModelCreationProcess(
|
||||||
Map<String,EntityPersister> entityPersisterMap,
|
Map<String,EntityPersister> entityPersisterMap,
|
||||||
RuntimeModelCreationContext creationContext) {
|
RuntimeModelCreationContext creationContext) {
|
||||||
|
@ -66,7 +69,13 @@ public class MappingModelCreationProcess {
|
||||||
entityPersister.prepareMappingModel( this );
|
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
|
// copy to avoid CCME
|
||||||
final ArrayList<PostInitCallback> copy = new ArrayList<>( new ArrayList<>( postInitCallbacks ) );
|
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) {
|
public void registerInitializationCallback(PostInitCallback callback) {
|
||||||
if ( postInitCallbacks == null ) {
|
if ( postInitCallbacks == null ) {
|
||||||
postInitCallbacks = new ArrayList<>();
|
postInitCallbacks = new ArrayList<>();
|
||||||
|
@ -109,6 +116,13 @@ public class MappingModelCreationProcess {
|
||||||
postInitCallbacks.add( callback );
|
postInitCallbacks.add( callback );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void registerForeignKeyPostInitCallbacks(PostInitCallback callback) {
|
||||||
|
if ( foreignKeyPostInitCallbacks == null ) {
|
||||||
|
foreignKeyPostInitCallbacks = new ArrayList<>();
|
||||||
|
}
|
||||||
|
foreignKeyPostInitCallbacks.add( callback );
|
||||||
|
}
|
||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface PostInitCallback {
|
public interface PostInitCallback {
|
||||||
boolean process();
|
boolean process();
|
||||||
|
|
|
@ -25,6 +25,7 @@ import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
||||||
import org.hibernate.metamodel.mapping.CollectionIdentifierDescriptor;
|
import org.hibernate.metamodel.mapping.CollectionIdentifierDescriptor;
|
||||||
import org.hibernate.metamodel.mapping.CollectionMappingType;
|
import org.hibernate.metamodel.mapping.CollectionMappingType;
|
||||||
import org.hibernate.metamodel.mapping.CollectionPart;
|
import org.hibernate.metamodel.mapping.CollectionPart;
|
||||||
|
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||||
import org.hibernate.metamodel.mapping.ManagedMappingType;
|
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.DelayedCollectionFetch;
|
||||||
import org.hibernate.sql.results.graph.collection.internal.EagerCollectionFetch;
|
import org.hibernate.sql.results.graph.collection.internal.EagerCollectionFetch;
|
||||||
import org.hibernate.sql.results.graph.collection.internal.SelectEagerCollectionFetch;
|
import org.hibernate.sql.results.graph.collection.internal.SelectEagerCollectionFetch;
|
||||||
|
import org.hibernate.type.AssociationType;
|
||||||
import org.hibernate.type.EntityType;
|
import org.hibernate.type.EntityType;
|
||||||
import org.hibernate.type.ForeignKeyDirection;
|
import org.hibernate.type.ForeignKeyDirection;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class PluralAttributeMappingImpl extends AbstractAttributeMapping implements PluralAttributeMapping {
|
public class PluralAttributeMappingImpl extends AbstractAttributeMapping implements PluralAttributeMapping {
|
||||||
private static final Logger log = Logger.getLogger( PluralAttributeMappingImpl.class );
|
private static final Logger log = Logger.getLogger( PluralAttributeMappingImpl.class );
|
||||||
|
|
||||||
|
|
||||||
public interface Aware {
|
public interface Aware {
|
||||||
void injectAttributeMapping(PluralAttributeMapping attributeMapping);
|
void injectAttributeMapping(PluralAttributeMapping attributeMapping);
|
||||||
}
|
}
|
||||||
|
@ -83,7 +86,6 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
|
||||||
private final PropertyAccess propertyAccess;
|
private final PropertyAccess propertyAccess;
|
||||||
private final StateArrayContributorMetadataAccess stateArrayContributorMetadataAccess;
|
private final StateArrayContributorMetadataAccess stateArrayContributorMetadataAccess;
|
||||||
|
|
||||||
private final ForeignKeyDescriptor fkDescriptor;
|
|
||||||
private final CollectionPart elementDescriptor;
|
private final CollectionPart elementDescriptor;
|
||||||
private final CollectionPart indexDescriptor;
|
private final CollectionPart indexDescriptor;
|
||||||
private final CollectionIdentifierDescriptor identifierDescriptor;
|
private final CollectionIdentifierDescriptor identifierDescriptor;
|
||||||
|
@ -98,6 +100,7 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
|
||||||
|
|
||||||
private final IndexMetadata indexMetadata;
|
private final IndexMetadata indexMetadata;
|
||||||
|
|
||||||
|
private ForeignKeyDescriptor fkDescriptor;
|
||||||
private ForeignKeyDescriptor manyToManyFkDescriptor;
|
private ForeignKeyDescriptor manyToManyFkDescriptor;
|
||||||
|
|
||||||
private OrderByFragment orderByFragment;
|
private OrderByFragment orderByFragment;
|
||||||
|
@ -111,7 +114,6 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
|
||||||
StateArrayContributorMetadataAccess stateArrayContributorMetadataAccess,
|
StateArrayContributorMetadataAccess stateArrayContributorMetadataAccess,
|
||||||
CollectionMappingType collectionMappingType,
|
CollectionMappingType collectionMappingType,
|
||||||
int stateArrayPosition,
|
int stateArrayPosition,
|
||||||
ForeignKeyDescriptor fkDescriptor,
|
|
||||||
CollectionPart elementDescriptor,
|
CollectionPart elementDescriptor,
|
||||||
CollectionPart indexDescriptor,
|
CollectionPart indexDescriptor,
|
||||||
CollectionIdentifierDescriptor identifierDescriptor,
|
CollectionIdentifierDescriptor identifierDescriptor,
|
||||||
|
@ -124,7 +126,6 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
|
||||||
this.stateArrayContributorMetadataAccess = stateArrayContributorMetadataAccess;
|
this.stateArrayContributorMetadataAccess = stateArrayContributorMetadataAccess;
|
||||||
this.collectionMappingType = collectionMappingType;
|
this.collectionMappingType = collectionMappingType;
|
||||||
this.stateArrayPosition = stateArrayPosition;
|
this.stateArrayPosition = stateArrayPosition;
|
||||||
this.fkDescriptor = fkDescriptor;
|
|
||||||
this.elementDescriptor = elementDescriptor;
|
this.elementDescriptor = elementDescriptor;
|
||||||
this.indexDescriptor = indexDescriptor;
|
this.indexDescriptor = indexDescriptor;
|
||||||
this.identifierDescriptor = identifierDescriptor;
|
this.identifierDescriptor = identifierDescriptor;
|
||||||
|
@ -185,47 +186,84 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
|
||||||
MappingModelCreationProcess creationProcess) {
|
MappingModelCreationProcess creationProcess) {
|
||||||
if ( collectionDescriptor.getElementType() instanceof EntityType
|
if ( collectionDescriptor.getElementType() instanceof EntityType
|
||||||
|| collectionDescriptor.getIndexType() 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 EntityType indexEntityType = (EntityType) collectionDescriptor.getIndexType();
|
||||||
final ModelPart fkTargetPart;
|
associatedEntityDescriptor = creationProcess.getEntityPersister( indexEntityType.getAssociatedEntityName() );
|
||||||
final Value fkBootDescriptorSource;
|
fkTargetPart = indexEntityType.isReferenceToPrimaryKey()
|
||||||
if ( collectionDescriptor.getElementType() instanceof EntityType ) {
|
? associatedEntityDescriptor.getIdentifierMapping()
|
||||||
final EntityType elementEntityType = (EntityType) collectionDescriptor.getElementType();
|
: associatedEntityDescriptor.findSubPart( indexEntityType.getRHSUniqueKeyPropertyName() );
|
||||||
associatedEntityDescriptor = creationProcess.getEntityPersister( elementEntityType.getAssociatedEntityName() );
|
fkBootDescriptorSource = ( (IndexedCollection) bootDescriptor ).getIndex();
|
||||||
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();
|
if ( fkTargetPart instanceof BasicValuedModelPart ) {
|
||||||
associatedEntityDescriptor = creationProcess.getEntityPersister( indexEntityType.getAssociatedEntityName() );
|
final BasicValuedModelPart basicFkTargetPart = (BasicValuedModelPart) fkTargetPart;
|
||||||
fkTargetPart = indexEntityType.isReferenceToPrimaryKey()
|
final Joinable collectionDescriptorAsJoinable = (Joinable) collectionDescriptor;
|
||||||
? associatedEntityDescriptor.getIdentifierMapping()
|
manyToManyFkDescriptor = new SimpleForeignKeyDescriptor(
|
||||||
: associatedEntityDescriptor.findSubPart( indexEntityType.getRHSUniqueKeyPropertyName() );
|
ForeignKeyDirection.TO_PARENT,
|
||||||
fkBootDescriptorSource = ( (IndexedCollection) bootDescriptor ).getIndex();
|
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;
|
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")
|
@SuppressWarnings("unused")
|
||||||
private TableGroupJoin createOneToManyTableGroupJoin(
|
private TableGroupJoin createOneToManyTableGroupJoin(
|
||||||
NavigablePath navigablePath,
|
NavigablePath navigablePath,
|
||||||
|
@ -470,7 +513,7 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
|
||||||
final TableGroup tableGroup = createOneToManyTableGroup(
|
final TableGroup tableGroup = createOneToManyTableGroup(
|
||||||
navigablePath,
|
navigablePath,
|
||||||
sqlAstJoinType == SqlAstJoinType.INNER
|
sqlAstJoinType == SqlAstJoinType.INNER
|
||||||
&& ! getAttributeMetadataAccess().resolveAttributeMetadata( null ).isNullable(),
|
&& !getAttributeMetadataAccess().resolveAttributeMetadata( null ).isNullable(),
|
||||||
lockMode,
|
lockMode,
|
||||||
aliasBaseGenerator,
|
aliasBaseGenerator,
|
||||||
sqlExpressionResolver,
|
sqlExpressionResolver,
|
||||||
|
@ -513,11 +556,12 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
|
||||||
|
|
||||||
final SqlAliasBase sqlAliasBase = aliasBaseGenerator.createSqlAliasBase( getSqlAliasStem() );
|
final SqlAliasBase sqlAliasBase = aliasBaseGenerator.createSqlAliasBase( getSqlAliasStem() );
|
||||||
|
|
||||||
final TableReference primaryTableReference = entityPartDescriptor.getEntityMappingType().createPrimaryTableReference(
|
final TableReference primaryTableReference = entityPartDescriptor.getEntityMappingType()
|
||||||
sqlAliasBase,
|
.createPrimaryTableReference(
|
||||||
sqlExpressionResolver,
|
sqlAliasBase,
|
||||||
creationContext
|
sqlExpressionResolver,
|
||||||
);
|
creationContext
|
||||||
|
);
|
||||||
|
|
||||||
return new StandardTableGroup(
|
return new StandardTableGroup(
|
||||||
navigablePath,
|
navigablePath,
|
||||||
|
@ -525,7 +569,8 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
|
||||||
lockMode,
|
lockMode,
|
||||||
primaryTableReference,
|
primaryTableReference,
|
||||||
sqlAliasBase,
|
sqlAliasBase,
|
||||||
(tableExpression) -> entityPartDescriptor.getEntityMappingType().containsTableReference( tableExpression ),
|
(tableExpression) -> entityPartDescriptor.getEntityMappingType()
|
||||||
|
.containsTableReference( tableExpression ),
|
||||||
(tableExpression, tg) -> entityPartDescriptor.getEntityMappingType().createTableReferenceJoin(
|
(tableExpression, tg) -> entityPartDescriptor.getEntityMappingType().createTableReferenceJoin(
|
||||||
tableExpression,
|
tableExpression,
|
||||||
sqlAliasBase,
|
sqlAliasBase,
|
||||||
|
@ -585,7 +630,7 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
|
||||||
SqlAstCreationContext creationContext) {
|
SqlAstCreationContext creationContext) {
|
||||||
final SqlAliasBase sqlAliasBase = aliasBaseGenerator.createSqlAliasBase( getSqlAliasStem() );
|
final SqlAliasBase sqlAliasBase = aliasBaseGenerator.createSqlAliasBase( getSqlAliasStem() );
|
||||||
|
|
||||||
assert ! getCollectionDescriptor().isOneToMany();
|
assert !getCollectionDescriptor().isOneToMany();
|
||||||
|
|
||||||
final String collectionTableName = ( (Joinable) collectionDescriptor ).getTableName();
|
final String collectionTableName = ( (Joinable) collectionDescriptor ).getTableName();
|
||||||
final TableReference collectionTableReference = new TableReference(
|
final TableReference collectionTableReference = new TableReference(
|
||||||
|
@ -596,7 +641,7 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
|
||||||
);
|
);
|
||||||
|
|
||||||
final Consumer<TableGroup> tableGroupFinalizer;
|
final Consumer<TableGroup> tableGroupFinalizer;
|
||||||
final BiFunction<String,TableGroup,TableReferenceJoin> tableReferenceJoinCreator;
|
final BiFunction<String, TableGroup, TableReferenceJoin> tableReferenceJoinCreator;
|
||||||
final java.util.function.Predicate<String> tableReferenceJoinNameChecker;
|
final java.util.function.Predicate<String> tableReferenceJoinNameChecker;
|
||||||
if ( elementDescriptor instanceof EntityCollectionPart || indexDescriptor instanceof EntityCollectionPart ) {
|
if ( elementDescriptor instanceof EntityCollectionPart || indexDescriptor instanceof EntityCollectionPart ) {
|
||||||
final EntityCollectionPart entityPartDescriptor;
|
final EntityCollectionPart entityPartDescriptor;
|
||||||
|
@ -619,13 +664,14 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
|
||||||
tableExpression,
|
tableExpression,
|
||||||
sqlAliasBase,
|
sqlAliasBase,
|
||||||
associatedPrimaryTable,
|
associatedPrimaryTable,
|
||||||
canUseInnerJoin && ! getAttributeMetadataAccess().resolveAttributeMetadata( null ).isNullable(),
|
canUseInnerJoin && !getAttributeMetadataAccess().resolveAttributeMetadata( null ).isNullable(),
|
||||||
sqlExpressionResolver,
|
sqlExpressionResolver,
|
||||||
creationContext
|
creationContext
|
||||||
);
|
);
|
||||||
|
|
||||||
tableGroupFinalizer = tableGroup -> {
|
tableGroupFinalizer = tableGroup -> {
|
||||||
final SqlAstJoinType joinType = canUseInnerJoin && ! getAttributeMetadataAccess().resolveAttributeMetadata( null ).isNullable()
|
final SqlAstJoinType joinType = canUseInnerJoin && !getAttributeMetadataAccess().resolveAttributeMetadata(
|
||||||
|
null ).isNullable()
|
||||||
? SqlAstJoinType.INNER
|
? SqlAstJoinType.INNER
|
||||||
: SqlAstJoinType.LEFT;
|
: SqlAstJoinType.LEFT;
|
||||||
final TableReferenceJoin associationJoin = new TableReferenceJoin(
|
final TableReferenceJoin associationJoin = new TableReferenceJoin(
|
||||||
|
@ -736,7 +782,7 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( elementDescriptor instanceof EntityCollectionPart ) {
|
if ( elementDescriptor instanceof EntityCollectionPart ) {
|
||||||
return ( (EntityCollectionPart) elementDescriptor ).findSubPart(name);
|
return ( (EntityCollectionPart) elementDescriptor ).findSubPart( name );
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,7 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DomainResult createCollectionFecthDomainResult(
|
public DomainResult createCollectionFetchDomainResult(
|
||||||
NavigablePath collectionPath,
|
NavigablePath collectionPath,
|
||||||
TableGroup tableGroup,
|
TableGroup tableGroup,
|
||||||
DomainResultCreationState creationState) {
|
DomainResultCreationState creationState) {
|
||||||
|
@ -140,14 +140,13 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
||||||
tableReference,
|
tableReference,
|
||||||
keyColumnExpression
|
keyColumnExpression
|
||||||
),
|
),
|
||||||
s -> {
|
s ->
|
||||||
return new ColumnReference(
|
new ColumnReference(
|
||||||
identificationVariable,
|
identificationVariable,
|
||||||
keyColumnExpression,
|
keyColumnExpression,
|
||||||
jdbcMapping,
|
jdbcMapping,
|
||||||
creationState.getSqlAstCreationState().getCreationContext().getSessionFactory()
|
creationState.getSqlAstCreationState().getCreationContext().getSessionFactory()
|
||||||
);
|
)
|
||||||
}
|
|
||||||
),
|
),
|
||||||
jdbcMapping.getJavaTypeDescriptor(),
|
jdbcMapping.getJavaTypeDescriptor(),
|
||||||
sqlAstCreationState.getCreationContext().getDomainModel().getTypeConfiguration()
|
sqlAstCreationState.getCreationContext().getDomainModel().getTypeConfiguration()
|
||||||
|
@ -314,25 +313,11 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T visitColumnMapping(FkColumnMappingFunction<T> function) {
|
public boolean areTargetColumnNamesEqualsTo(String[] columnNames) {
|
||||||
return function.apply(
|
if ( columnNames.length != 1 ) {
|
||||||
keyColumnContainingTable,
|
return false;
|
||||||
keyColumnExpression ,
|
}
|
||||||
targetColumnContainingTable,
|
return targetColumnExpression.equals( columnNames[0] );
|
||||||
targetColumnExpression ,
|
|
||||||
jdbcMapping
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visitColumnMappings(FkColumnMappingConsumer consumer) {
|
|
||||||
consumer.consume(
|
|
||||||
keyColumnContainingTable,
|
|
||||||
keyColumnExpression,
|
|
||||||
targetColumnContainingTable,
|
|
||||||
targetColumnExpression,
|
|
||||||
jdbcMapping
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -8,7 +8,6 @@ package org.hibernate.metamodel.mapping.internal;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.NotYetImplementedFor6Exception;
|
|
||||||
import org.hibernate.engine.FetchStrategy;
|
import org.hibernate.engine.FetchStrategy;
|
||||||
import org.hibernate.engine.FetchTiming;
|
import org.hibernate.engine.FetchTiming;
|
||||||
import org.hibernate.mapping.ManyToOne;
|
import org.hibernate.mapping.ManyToOne;
|
||||||
|
@ -181,7 +180,7 @@ public class SingularAssociationAttributeMapping extends AbstractSingularAttribu
|
||||||
}
|
}
|
||||||
|
|
||||||
final FetchParent associationFetchParent = fetchParent.resolveContainingAssociationParent();
|
final FetchParent associationFetchParent = fetchParent.resolveContainingAssociationParent();
|
||||||
if(associationFetchParent == null){
|
if ( associationFetchParent == null ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final ModelPart referencedModePart = associationFetchParent.getReferencedModePart();
|
final ModelPart referencedModePart = associationFetchParent.getReferencedModePart();
|
||||||
|
@ -189,7 +188,7 @@ public class SingularAssociationAttributeMapping extends AbstractSingularAttribu
|
||||||
|
|
||||||
final Association associationParent = (Association) referencedModePart;
|
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
|
// 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
|
// fetch will "return" for its Assembler. so we walk "up" the FetchParent graph
|
||||||
// to find the "referenced entity" reference
|
// to find the "referenced entity" reference
|
||||||
|
@ -217,23 +216,10 @@ public class SingularAssociationAttributeMapping extends AbstractSingularAttribu
|
||||||
if ( associationParentForeignKeyDescriptor.getTargetTableExpression()
|
if ( associationParentForeignKeyDescriptor.getTargetTableExpression()
|
||||||
.equals( entityPersister.getTableName() ) ) {
|
.equals( entityPersister.getTableName() ) ) {
|
||||||
final String[] identifierColumnNames = entityPersister.getIdentifierColumnNames();
|
final String[] identifierColumnNames = entityPersister.getIdentifierColumnNames();
|
||||||
return associationParentForeignKeyDescriptor.visitColumnMapping( (referringTable, referringColumns, targetTable, targetColumns, jdbcMapping) -> {
|
if ( associationParentForeignKeyDescriptor.areTargetColumnNamesEqualsTo( identifierColumnNames ) ) {
|
||||||
// if ( identifierColumnNames.length == targetColumns.size() ) {
|
return createBiDirectionalFetch( fetchablePath, fetchParent );
|
||||||
// for ( int i = 0; i < identifierColumnNames.length; i++ ) {
|
}
|
||||||
// if ( !targetColumns.contains( identifierColumnNames[i] ) ) {
|
return null;
|
||||||
// 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;
|
|
||||||
} );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -217,6 +217,7 @@ import org.hibernate.type.Type;
|
||||||
import org.hibernate.type.TypeHelper;
|
import org.hibernate.type.TypeHelper;
|
||||||
import org.hibernate.type.VersionType;
|
import org.hibernate.type.VersionType;
|
||||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||||
|
import org.hibernate.type.spi.TypeConfiguration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Basic functionality for persisting an entity via JDBC
|
* Basic functionality for persisting an entity via JDBC
|
||||||
|
@ -1231,14 +1232,6 @@ public abstract class AbstractEntityPersister
|
||||||
return new EntityResultImpl( navigablePath, this, resultVariable, creationState );
|
return new EntityResultImpl( navigablePath, this, resultVariable, creationState );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void applySqlSelections(
|
|
||||||
NavigablePath navigablePath,
|
|
||||||
TableGroup tableGroup,
|
|
||||||
DomainResultCreationState creationState) {
|
|
||||||
throw new NotYetImplementedFor6Exception( getClass() );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NaturalIdMapping getNaturalIdMapping() {
|
public NaturalIdMapping getNaturalIdMapping() {
|
||||||
return naturalIdMapping;
|
return naturalIdMapping;
|
||||||
|
@ -6450,7 +6443,27 @@ public abstract class AbstractEntityPersister
|
||||||
collectAttributeDefinitions();
|
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
|
@Override
|
||||||
public EntityIdentifierDefinition getEntityKeyDefinition() {
|
public EntityIdentifierDefinition getEntityKeyDefinition() {
|
||||||
|
|
|
@ -19,7 +19,7 @@ public abstract class AbstractFetchParent implements FetchParent {
|
||||||
private final FetchableContainer fetchContainer;
|
private final FetchableContainer fetchContainer;
|
||||||
private final NavigablePath navigablePath;
|
private final NavigablePath navigablePath;
|
||||||
|
|
||||||
private List<Fetch> fetches;
|
protected List<Fetch> fetches;
|
||||||
|
|
||||||
public AbstractFetchParent(FetchableContainer fetchContainer, NavigablePath navigablePath) {
|
public AbstractFetchParent(FetchableContainer fetchContainer, NavigablePath navigablePath) {
|
||||||
this.fetchContainer = fetchContainer;
|
this.fetchContainer = fetchContainer;
|
||||||
|
|
|
@ -60,13 +60,13 @@ public class EagerCollectionFetch extends CollectionFetch implements FetchParent
|
||||||
final ForeignKeyDescriptor keyDescriptor = fetchedAttribute.getKeyDescriptor();
|
final ForeignKeyDescriptor keyDescriptor = fetchedAttribute.getKeyDescriptor();
|
||||||
if ( parentTableGroup != null ) {
|
if ( parentTableGroup != null ) {
|
||||||
// join fetch
|
// join fetch
|
||||||
keyContainerResult = keyDescriptor.createCollectionFecthDomainResult( fetchedPath, parentTableGroup, creationState );
|
keyContainerResult = keyDescriptor.createCollectionFetchDomainResult( fetchedPath, parentTableGroup, creationState );
|
||||||
keyCollectionResult = keyDescriptor.createDomainResult( fetchedPath, collectionTableGroup, creationState );
|
keyCollectionResult = keyDescriptor.createDomainResult( fetchedPath, collectionTableGroup, creationState );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// select fetch
|
// select fetch
|
||||||
// todo (6.0) : we could potentially leverage batch fetching for performance
|
// 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
|
// use null for `keyCollectionResult`... the initializer will see that as trigger to use
|
||||||
// the assembled container-key value as the collection-key value.
|
// 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,
|
FetchParentAccess parentAccess,
|
||||||
Consumer<Initializer> collector,
|
Consumer<Initializer> collector,
|
||||||
AssemblerCreationState creationState) {
|
AssemblerCreationState creationState) {
|
||||||
return new EntityInitializerJoinedFetch(
|
return new EntityJoinedFetchInitializer(
|
||||||
entityResult,
|
entityResult,
|
||||||
getNavigablePath(),
|
getNavigablePath(),
|
||||||
lockMode,
|
lockMode,
|
||||||
|
|
|
@ -57,7 +57,7 @@ public class EntityFetchSelectImpl extends AbstractNonJoinedEntityFetch {
|
||||||
FetchParentAccess parentAccess,
|
FetchParentAccess parentAccess,
|
||||||
Consumer<Initializer> collector,
|
Consumer<Initializer> collector,
|
||||||
AssemblerCreationState creationState) {
|
AssemblerCreationState creationState) {
|
||||||
final EntityInitializerSelectFetch initializer = new EntityInitializerSelectFetch(
|
final EntitySelectFetchInitializer initializer = new EntitySelectFetchInitializer(
|
||||||
getNavigablePath(),
|
getNavigablePath(),
|
||||||
getReferencedMappingContainer().getEntityPersister(),
|
getReferencedMappingContainer().getEntityPersister(),
|
||||||
result.createResultAssembler( collector, creationState ),
|
result.createResultAssembler( collector, creationState ),
|
||||||
|
|
|
@ -20,8 +20,9 @@ import org.hibernate.sql.results.graph.Initializer;
|
||||||
/**
|
/**
|
||||||
* @author Andrea Boriero
|
* @author Andrea Boriero
|
||||||
*/
|
*/
|
||||||
public class EntityInitializerJoinedFetch extends AbstractEntityInitializer {
|
public class EntityJoinedFetchInitializer extends AbstractEntityInitializer {
|
||||||
protected EntityInitializerJoinedFetch(
|
|
||||||
|
protected EntityJoinedFetchInitializer(
|
||||||
EntityResultGraphNode resultDescriptor,
|
EntityResultGraphNode resultDescriptor,
|
||||||
NavigablePath navigablePath,
|
NavigablePath navigablePath,
|
||||||
LockMode lockMode,
|
LockMode lockMode,
|
|
@ -22,7 +22,7 @@ import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
|
||||||
/**
|
/**
|
||||||
* @author Andrea Boriero
|
* @author Andrea Boriero
|
||||||
*/
|
*/
|
||||||
public class EntityInitializerSelectFetch extends AbstractFetchParentAccess implements EntityInitializer {
|
public class EntitySelectFetchInitializer extends AbstractFetchParentAccess implements EntityInitializer {
|
||||||
private final NavigablePath navigablePath;
|
private final NavigablePath navigablePath;
|
||||||
private final EntityPersister concreteDescriptor;
|
private final EntityPersister concreteDescriptor;
|
||||||
private final DomainResultAssembler identifierAssembler;
|
private final DomainResultAssembler identifierAssembler;
|
||||||
|
@ -31,7 +31,7 @@ public class EntityInitializerSelectFetch extends AbstractFetchParentAccess impl
|
||||||
|
|
||||||
private Object entityInstance;
|
private Object entityInstance;
|
||||||
|
|
||||||
protected EntityInitializerSelectFetch(
|
protected EntitySelectFetchInitializer(
|
||||||
NavigablePath fetchedNavigable,
|
NavigablePath fetchedNavigable,
|
||||||
EntityPersister concreteDescriptor,
|
EntityPersister concreteDescriptor,
|
||||||
DomainResultAssembler identifierAssembler,
|
DomainResultAssembler identifierAssembler,
|
||||||
|
@ -75,7 +75,7 @@ public class EntityInitializerSelectFetch extends AbstractFetchParentAccess impl
|
||||||
entityInstance = session.internalLoad(
|
entityInstance = session.internalLoad(
|
||||||
entityName,
|
entityName,
|
||||||
id,
|
id,
|
||||||
false,
|
true,
|
||||||
nullable
|
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.CascadeType;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
import javax.persistence.GeneratedValue;
|
|
||||||
import javax.persistence.Id;
|
import javax.persistence.Id;
|
||||||
import javax.persistence.JoinColumn;
|
import javax.persistence.JoinColumn;
|
||||||
import javax.persistence.MapsId;
|
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() {
|
public MetadataImplementor getMetadataImplementor() {
|
||||||
return modelScope.getDomainModel();
|
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.boot.spi.MetadataImplementor;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
|
import org.hibernate.resource.jdbc.spi.StatementInspector;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
|
@ -30,4 +31,6 @@ public interface SessionFactoryScope {
|
||||||
<T> T fromTransaction(SessionImplementor session, Function<SessionImplementor, T> action);
|
<T> T fromTransaction(SessionImplementor session, Function<SessionImplementor, T> action);
|
||||||
|
|
||||||
MetadataImplementor getMetadataImplementor();
|
MetadataImplementor getMetadataImplementor();
|
||||||
|
|
||||||
|
StatementInspector getStatementInspector();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue