Add support for non-synthetic virtual model parts

This commit is contained in:
Christian Beikov 2022-01-06 19:47:13 +01:00
parent fb882f56f3
commit 4e5a28deaa
8 changed files with 77 additions and 23 deletions

View File

@ -1870,24 +1870,16 @@ public class ModelBinder {
componentBinding.createForeignKey(); componentBinding.createForeignKey();
final Property attribute; final Property attribute = new Property();
if ( embeddedSource.isVirtualAttribute() ) {
attribute = new SyntheticProperty() {
@Override
public String getPropertyAccessorName() {
return "embedded";
}
};
}
else {
attribute = new Property();
}
attribute.setValue( componentBinding ); attribute.setValue( componentBinding );
bindProperty( bindProperty(
sourceDocument, sourceDocument,
embeddedSource, embeddedSource,
attribute attribute
); );
if ( embeddedSource.isVirtualAttribute() ) {
attribute.setPropertyAccessorName( "embedded" );
}
return attribute; return attribute;
} }

View File

@ -47,6 +47,7 @@ import org.hibernate.metamodel.model.domain.internal.MappedSuperclassTypeImpl;
import org.hibernate.metamodel.model.domain.internal.MappingMetamodelImpl; import org.hibernate.metamodel.model.domain.internal.MappingMetamodelImpl;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext; import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.java.spi.EntityJavaTypeDescriptor;
import org.hibernate.type.descriptor.java.spi.JavaTypeRegistry; import org.hibernate.type.descriptor.java.spi.JavaTypeRegistry;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
@ -78,6 +79,7 @@ public class MetadataContext {
private final Set<MappedSuperclass> knownMappedSuperclasses; private final Set<MappedSuperclass> knownMappedSuperclasses;
private final TypeConfiguration typeConfiguration; private final TypeConfiguration typeConfiguration;
private final JpaStaticMetaModelPopulationSetting jpaStaticMetaModelPopulationSetting; private final JpaStaticMetaModelPopulationSetting jpaStaticMetaModelPopulationSetting;
private final JpaMetaModelPopulationSetting jpaMetaModelPopulationSetting;
private final AttributeFactory attributeFactory = new AttributeFactory( this ); private final AttributeFactory attributeFactory = new AttributeFactory( this );
private final Map<Class<?>, EntityDomainType<?>> entityTypes = new HashMap<>(); private final Map<Class<?>, EntityDomainType<?>> entityTypes = new HashMap<>();
@ -105,12 +107,14 @@ public class MetadataContext {
MappingMetamodel mappingMetamodel, MappingMetamodel mappingMetamodel,
MetadataImplementor bootMetamodel, MetadataImplementor bootMetamodel,
JpaStaticMetaModelPopulationSetting jpaStaticMetaModelPopulationSetting, JpaStaticMetaModelPopulationSetting jpaStaticMetaModelPopulationSetting,
JpaMetaModelPopulationSetting jpaMetaModelPopulationSetting,
RuntimeModelCreationContext runtimeModelCreationContext) { RuntimeModelCreationContext runtimeModelCreationContext) {
this.jpaMetamodel = jpaMetamodel; this.jpaMetamodel = jpaMetamodel;
this.metamodel = mappingMetamodel; this.metamodel = mappingMetamodel;
this.knownMappedSuperclasses = bootMetamodel.getMappedSuperclassMappingsCopy(); this.knownMappedSuperclasses = bootMetamodel.getMappedSuperclassMappingsCopy();
this.typeConfiguration = runtimeModelCreationContext.getTypeConfiguration(); this.typeConfiguration = runtimeModelCreationContext.getTypeConfiguration();
this.jpaStaticMetaModelPopulationSetting = jpaStaticMetaModelPopulationSetting; this.jpaStaticMetaModelPopulationSetting = jpaStaticMetaModelPopulationSetting;
this.jpaMetaModelPopulationSetting = jpaMetaModelPopulationSetting;
this.runtimeModelCreationContext = runtimeModelCreationContext; this.runtimeModelCreationContext = runtimeModelCreationContext;
} }
@ -287,13 +291,12 @@ public class MetadataContext {
property property
); );
if ( attribute != null ) { if ( attribute != null ) {
( (AttributeContainer<Object>) jpaMapping ).getInFlightAccess().addAttribute( attribute ); addAttribute( jpaMapping, attribute );
if ( property.isNaturalIdentifier() ) { if ( property.isNaturalIdentifier() ) {
( ( AttributeContainer<Object>) jpaMapping ).getInFlightAccess() ( ( AttributeContainer<Object>) jpaMapping ).getInFlightAccess()
.applyNaturalIdAttribute( attribute ); .applyNaturalIdAttribute( attribute );
} }
} }
} }
( (AttributeContainer<?>) jpaMapping ).getInFlightAccess().finishUp(); ( (AttributeContainer<?>) jpaMapping ).getInFlightAccess().finishUp();
@ -329,7 +332,7 @@ public class MetadataContext {
} }
final PersistentAttribute<Object, ?> attribute = attributeFactory.buildAttribute( jpaType, property ); final PersistentAttribute<Object, ?> attribute = attributeFactory.buildAttribute( jpaType, property );
if ( attribute != null ) { if ( attribute != null ) {
( (AttributeContainer<Object>) jpaType ).getInFlightAccess().addAttribute( attribute ); addAttribute( jpaType, attribute );
if ( property.isNaturalIdentifier() ) { if ( property.isNaturalIdentifier() ) {
( ( AttributeContainer<Object>) jpaType ).getInFlightAccess() ( ( AttributeContainer<Object>) jpaType ).getInFlightAccess()
.applyNaturalIdAttribute( attribute ); .applyNaturalIdAttribute( attribute );
@ -370,7 +373,7 @@ public class MetadataContext {
final Property property = propertyItr.next(); final Property property = propertyItr.next();
final PersistentAttribute<Object, ?> attribute = attributeFactory.buildAttribute( (ManagedDomainType<Object>) embeddable, property ); final PersistentAttribute<Object, ?> attribute = attributeFactory.buildAttribute( (ManagedDomainType<Object>) embeddable, property );
if ( attribute != null ) { if ( attribute != null ) {
( ( AttributeContainer<Object>) embeddable ).getInFlightAccess().addAttribute( attribute ); addAttribute( embeddable, attribute );
} }
} }
@ -384,6 +387,27 @@ public class MetadataContext {
} }
} }
private void addAttribute(ManagedDomainType<?> type, PersistentAttribute<Object, ?> attribute) {
final AttributeContainer.InFlightAccess<Object> inFlightAccess = ( (AttributeContainer<Object>) type ).getInFlightAccess();
final boolean virtual = attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.EMBEDDED
&& attribute.getAttributeJavaTypeDescriptor() instanceof EntityJavaTypeDescriptor<?>;
if ( virtual ) {
final EmbeddableDomainType<?> embeddableDomainType = (EmbeddableDomainType<?>) attribute.getValueGraphType();
final Component component = componentByEmbeddable.get( embeddableDomainType );
final Iterator<Property> propertyItr = component.getPropertyIterator();
while ( propertyItr.hasNext() ) {
final Property property = propertyItr.next();
final PersistentAttribute<Object, ?> subAttribute = attributeFactory.buildAttribute( (ManagedDomainType<Object>) embeddableDomainType, property );
if ( subAttribute != null ) {
inFlightAccess.addAttribute( subAttribute );
}
}
if ( jpaMetaModelPopulationSetting != JpaMetaModelPopulationSetting.ENABLED ) {
return;
}
}
inFlightAccess.addAttribute( attribute );
}
// 1) create the part // 1) create the part
// 2) register the part (mapping role) // 2) register the part (mapping role)

View File

@ -474,6 +474,7 @@ public class JpaMetamodelImpl implements JpaMetamodel, Serializable {
mappingMetamodel, mappingMetamodel,
bootMetamodel, bootMetamodel,
jpaStaticMetaModelPopulationSetting, jpaStaticMetaModelPopulationSetting,
jpaMetaModelPopulationSetting,
runtimeModelCreationContext runtimeModelCreationContext
); );

View File

@ -158,6 +158,7 @@ import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.AttributeMetadata; import org.hibernate.metamodel.mapping.AttributeMetadata;
import org.hibernate.metamodel.mapping.AttributeMetadataAccess; import org.hibernate.metamodel.mapping.AttributeMetadataAccess;
import org.hibernate.metamodel.mapping.BasicValuedModelPart; import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping; import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping; import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityMappingType;
@ -175,6 +176,7 @@ import org.hibernate.metamodel.mapping.SelectableConsumer;
import org.hibernate.metamodel.mapping.SingularAttributeMapping; import org.hibernate.metamodel.mapping.SingularAttributeMapping;
import org.hibernate.metamodel.mapping.StateArrayContributorMapping; import org.hibernate.metamodel.mapping.StateArrayContributorMapping;
import org.hibernate.metamodel.mapping.StateArrayContributorMetadata; import org.hibernate.metamodel.mapping.StateArrayContributorMetadata;
import org.hibernate.metamodel.mapping.VirtualModelPart;
import org.hibernate.metamodel.mapping.internal.BasicEntityIdentifierMappingImpl; import org.hibernate.metamodel.mapping.internal.BasicEntityIdentifierMappingImpl;
import org.hibernate.metamodel.mapping.internal.CompoundNaturalIdMapping; import org.hibernate.metamodel.mapping.internal.CompoundNaturalIdMapping;
import org.hibernate.metamodel.mapping.internal.DiscriminatedAssociationAttributeMapping; import org.hibernate.metamodel.mapping.internal.DiscriminatedAssociationAttributeMapping;
@ -6362,7 +6364,21 @@ public abstract class AbstractEntityPersister
} }
} }
return getIdentifierModelPart( name, treatTargetType ); final ModelPart identifierModelPart = getIdentifierModelPart( name, treatTargetType );
if ( identifierModelPart != null ) {
return identifierModelPart;
}
for ( AttributeMapping attribute : declaredAttributeMappings.values() ) {
if ( attribute instanceof EmbeddableValuedModelPart && attribute instanceof VirtualModelPart ) {
final ModelPart subPart = ( (EmbeddableValuedModelPart) attribute ).findSubPart( name, null );
if ( subPart != null ) {
return subPart;
}
}
}
return null;
} }
@Override @Override

View File

@ -6,7 +6,7 @@
*/ */
//$Id: Detail.java 4602 2004-09-26 11:42:47Z oneovthafew $ //$Id: Detail.java 4602 2004-09-26 11:42:47Z oneovthafew $
package org.hibernate.test.formulajoin; package org.hibernate.orm.test.formulajoin;
import java.io.Serializable; import java.io.Serializable;
/** /**

View File

@ -4,13 +4,14 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later. * 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>. * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/ */
package org.hibernate.test.formulajoin; package org.hibernate.orm.test.formulajoin;
import java.util.List; import java.util.List;
import org.hibernate.Session; import org.hibernate.Session;
import org.hibernate.Transaction; import org.hibernate.Transaction;
import org.hibernate.dialect.PostgreSQL81Dialect; import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Configuration;
import org.hibernate.dialect.PostgreSQLDialect; import org.hibernate.dialect.PostgreSQLDialect;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
@ -23,10 +24,18 @@ import static org.junit.Assert.assertTrue;
* @author Gavin King * @author Gavin King
*/ */
public class FormulaJoinTest extends BaseCoreFunctionalTestCase { public class FormulaJoinTest extends BaseCoreFunctionalTestCase {
@Override
public String[] getMappings() { public String[] getMappings() {
return new String[] { "formulajoin/Root.hbm.xml" }; return new String[] { "formulajoin/Root.hbm.xml" };
} }
@Override
protected void configure(Configuration configuration) {
super.configure( configuration );
configuration.setProperty( AvailableSettings.JPA_METAMODEL_POPULATION, "enabled" );
}
@Test @Test
public void testFormulaJoin() { public void testFormulaJoin() {
Session s = openSession(); Session s = openSession();
@ -50,7 +59,7 @@ public class FormulaJoinTest extends BaseCoreFunctionalTestCase {
tx.commit(); tx.commit();
s.close(); s.close();
if ( getDialect() instanceof PostgreSQLDialect || getDialect() instanceof PostgreSQL81Dialect ) return; if ( getDialect() instanceof PostgreSQLDialect ) return;
s = openSession(); s = openSession();
tx = s.beginTransaction(); tx = s.beginTransaction();
@ -83,10 +92,22 @@ public class FormulaJoinTest extends BaseCoreFunctionalTestCase {
tx.commit(); tx.commit();
s.close(); s.close();
s = openSession();
tx = s.beginTransaction();
l = s.createQuery("from Detail d join fetch d.root").list();
assertEquals( l.size(), 2 );
tx.commit();
s.close();
s = openSession(); s = openSession();
tx = s.beginTransaction(); tx = s.beginTransaction();
l = s.createQuery("from Detail d join fetch d.currentRoot.root m join fetch m.detail").list(); l = s.createQuery("from Detail d join fetch d.currentRoot.root m join fetch m.detail").list();
assertEquals( l.size(), 2 ); assertEquals( l.size(), 2 );
s = openSession();
tx = s.beginTransaction();
l = s.createQuery("from Detail d join fetch d.root m join fetch m.detail").list();
assertEquals( l.size(), 2 );
s.createQuery("delete from Detail").executeUpdate(); s.createQuery("delete from Detail").executeUpdate();
s.createQuery("delete from Root").executeUpdate(); s.createQuery("delete from Root").executeUpdate();

View File

@ -16,7 +16,7 @@
--> -->
<hibernate-mapping package="org.hibernate.test.formulajoin"> <hibernate-mapping package="org.hibernate.orm.test.formulajoin">
<class name="Root" table="t_roots"> <class name="Root" table="t_roots">

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later. * 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>. * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/ */
package org.hibernate.test.formulajoin; package org.hibernate.orm.test.formulajoin;
import java.io.Serializable; import java.io.Serializable;