Implemented @Parent

This commit is contained in:
Andrea Boriero 2020-07-24 15:37:42 +01:00
parent d3978a0871
commit b26b397d59
6 changed files with 93 additions and 37 deletions

View File

@ -8,6 +8,7 @@ package org.hibernate.metamodel.mapping;
import java.util.List;
import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
@ -46,7 +47,9 @@ public interface EmbeddableValuedModelPart extends ModelPart, Fetchable, Fetchab
/**
* @see org.hibernate.annotations.Parent
*/
SingularAttributeMapping getParentInjectionAttributeMapping();
default PropertyAccess getParentInjectionAttributePropertyAccess() {
return null;
}
Expression toSqlExpression(
TableGroup tableGroup,

View File

@ -22,9 +22,9 @@ import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.ManagedMappingType;
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.property.access.internal.PropertyAccessStrategyBasicImpl;
import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
@ -62,6 +62,7 @@ public class EmbeddedAttributeMapping
private final String tableExpression;
private final String[] attrColumnNames;
private final EmbeddableMappingType embeddableMappingType;
private final PropertyAccess parentInjectionAttributeProperyAccess;
@SuppressWarnings("WeakerAccess")
public EmbeddedAttributeMapping(
@ -71,6 +72,7 @@ public class EmbeddedAttributeMapping
String tableExpression,
String[] attrColumnNames,
StateArrayContributorMetadataAccess attributeMetadataAccess,
String parentInjectionAttributeName,
FetchStrategy mappedFetchStrategy,
EmbeddableMappingType embeddableMappingType,
ManagedMappingType declaringType,
@ -83,6 +85,15 @@ public class EmbeddedAttributeMapping
declaringType,
propertyAccess
);
if ( parentInjectionAttributeName != null ) {
parentInjectionAttributeProperyAccess = PropertyAccessStrategyBasicImpl.INSTANCE.buildPropertyAccess(
embeddableMappingType.getMappedJavaTypeDescriptor().getJavaType(),
parentInjectionAttributeName
);
}
else {
parentInjectionAttributeProperyAccess = null;
}
this.navigableRole = navigableRole;
this.tableExpression = tableExpression;
this.attrColumnNames = attrColumnNames;
@ -99,12 +110,6 @@ public class EmbeddedAttributeMapping
return embeddableMappingType;
}
@Override
public SingularAttributeMapping getParentInjectionAttributeMapping() {
// todo (6.0) : implement
return null;
}
@Override
public String getContainingTableExpression() {
return tableExpression;
@ -115,6 +120,11 @@ public class EmbeddedAttributeMapping
return Arrays.asList( attrColumnNames );
}
@Override
public PropertyAccess getParentInjectionAttributePropertyAccess() {
return parentInjectionAttributeProperyAccess;
}
@Override
public void visitJdbcTypes(
Consumer<JdbcMapping> action,

View File

@ -22,9 +22,10 @@ import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.property.access.internal.PropertyAccessStrategyBasicImpl;
import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.sql.ast.Clause;
@ -59,7 +60,7 @@ public class EmbeddedCollectionPart implements CollectionPart, EmbeddableValuedF
private final String containingTableExpression;
private final SingularAttributeMapping parentInjectionAttribute;
private final PropertyAccess parentInjectionAttributeProperyAccess;
private final List<String> columnExpressions;
private final String sqlAliasStem;
@ -68,15 +69,24 @@ public class EmbeddedCollectionPart implements CollectionPart, EmbeddableValuedF
CollectionPersister collectionDescriptor,
Nature nature,
EmbeddableMappingType embeddableMappingType,
SingularAttributeMapping parentInjectionAttribute,
String parentInjectionAttributeName,
String containingTableExpression,
List<String> columnExpressions,
String sqlAliasStem) {
this.navigableRole = collectionDescriptor.getNavigableRole().appendContainer( nature.getName() );
this.collectionDescriptor = collectionDescriptor;
this.nature = nature;
if ( parentInjectionAttributeName != null ) {
parentInjectionAttributeProperyAccess = PropertyAccessStrategyBasicImpl.INSTANCE.buildPropertyAccess(
embeddableMappingType.getMappedJavaTypeDescriptor().getJavaType(),
parentInjectionAttributeName
);
}
else {
parentInjectionAttributeProperyAccess = null;
}
this.embeddableMappingType = embeddableMappingType;
this.parentInjectionAttribute = parentInjectionAttribute;
this.containingTableExpression = containingTableExpression;
this.columnExpressions = columnExpressions;
this.sqlAliasStem = sqlAliasStem;
@ -108,8 +118,8 @@ public class EmbeddedCollectionPart implements CollectionPart, EmbeddableValuedF
}
@Override
public SingularAttributeMapping getParentInjectionAttributeMapping() {
return parentInjectionAttribute;
public PropertyAccess getParentInjectionAttributePropertyAccess() {
return parentInjectionAttributeProperyAccess;
}
@Override

View File

@ -413,8 +413,9 @@ public class MappingModelCreationHelper {
creationProcess
);
final Component component = (Component) bootProperty.getValue();
final EmbeddableMappingType embeddableMappingType = EmbeddableMappingType.from(
(Component) bootProperty.getValue(),
component,
attrType,
attributeMappingType -> new EmbeddedAttributeMapping(
attrName,
@ -423,6 +424,7 @@ public class MappingModelCreationHelper {
tableExpression,
attrColumnNames,
attributeMetadataAccess,
component.getParentProperty(),
FetchStrategy.IMMEDIATE_JOIN,
attributeMappingType,
declaringType,
@ -1115,7 +1117,7 @@ public class MappingModelCreationHelper {
CollectionPart.Nature.INDEX,
inflightDescriptor,
// parent-injection
null,
component.getParentProperty(),
tableExpression,
columnExpressions,
sqlAliasStem
@ -1206,7 +1208,7 @@ public class MappingModelCreationHelper {
CollectionPart.Nature.ELEMENT,
embeddableMappingType,
// parent-injection
null,
component.getParentProperty(),
tableExpression,
columnExpressions,
sqlAliasStem

View File

@ -9,16 +9,20 @@ package org.hibernate.sql.results.graph.embeddable;
import java.util.IdentityHashMap;
import java.util.Map;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
import org.hibernate.metamodel.mapping.StateArrayContributorMapping;
import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.graph.AbstractFetchParentAccess;
import org.hibernate.sql.results.graph.AssemblerCreationState;
import org.hibernate.sql.results.graph.DomainResultAssembler;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParentAccess;
import org.hibernate.sql.results.graph.Initializer;
import org.hibernate.sql.results.graph.collection.CollectionInitializer;
import org.hibernate.sql.results.graph.entity.EntityInitializer;
import org.hibernate.sql.results.internal.NullValueAssembler;
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
@ -28,7 +32,7 @@ import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentAccess implements EmbeddableInitializer {
private final NavigablePath navigablePath;
private final EmbeddableValuedModelPart embeddedModelPartDescriptor;
private final FetchParentAccess fetchParentAccess;
private FetchParentAccess fetchParentAccess;
private final Map<StateArrayContributorMapping, DomainResultAssembler> assemblerMap;
@ -92,9 +96,10 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA
// todo (6.0) : register "parent resolution listener" if the composite is defined for `@Parent`
// something like:
final SingularAttributeMapping parentInjectionTarget = embeddedModelPartDescriptor.getParentInjectionAttributeMapping();
final PropertyAccess parentInjectionPropertyAccess = embeddedModelPartDescriptor.getParentInjectionAttributePropertyAccess();
if ( parentInjectionTarget != null ) {
if ( parentInjectionPropertyAccess != null ) {
if ( getFetchParentAccess() != null ) {
getFetchParentAccess().findFirstEntityDescriptorAccess().registerResolutionListener(
// todo (6.0) : this is the legacy behavior
// - the first entity is injected as the parent, even if the composite
@ -103,7 +108,7 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA
if ( compositeInstance == null ) {
return;
}
parentInjectionTarget.getPropertyAccess().getSetter().set(
parentInjectionPropertyAccess.getSetter().set(
compositeInstance,
owner,
rowProcessingState.getSession().getFactory()
@ -111,7 +116,7 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA
}
);
}
}
}
@Override
@ -130,6 +135,33 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA
@Override
public void initializeInstance(RowProcessingState rowProcessingState) {
final PropertyAccess parentInjectionPropertyAccess = embeddedModelPartDescriptor.getParentInjectionAttributePropertyAccess();
if ( parentInjectionPropertyAccess != null && getFetchParentAccess() == null ) {
Initializer initializer = rowProcessingState.resolveInitializer( navigablePath.getParent() );
final Object owner;
if ( initializer instanceof CollectionInitializer ) {
owner = ( (CollectionInitializer) initializer ).getCollectionInstance().getOwner();
}
else if ( initializer instanceof EntityInitializer ) {
owner = ( (EntityInitializer) initializer ).getEntityInstance();
parentInjectionPropertyAccess.getSetter().set(
compositeInstance,
owner,
rowProcessingState.getSession().getFactory()
);
}
else {
throw new NotYetImplementedFor6Exception( getClass() );
}
parentInjectionPropertyAccess.getSetter().set(
compositeInstance,
owner,
rowProcessingState.getSession().getFactory()
);
}
EmbeddableLoadingLogger.INSTANCE.debugf(
"Initializing composite instance [%s] : %s",
navigablePath,

View File

@ -484,7 +484,6 @@ public class EmbeddedTest {
}
@Test
@FailureExpected(reason = "@Parent annotation mapping has not yet been implemented")
public void testParent(SessionFactoryScope scope) {
Book book = new Book();
scope.inTransaction(