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();
final Property attribute;
if ( embeddedSource.isVirtualAttribute() ) {
attribute = new SyntheticProperty() {
@Override
public String getPropertyAccessorName() {
return "embedded";
}
};
}
else {
attribute = new Property();
}
final Property attribute = new Property();
attribute.setValue( componentBinding );
bindProperty(
sourceDocument,
embeddedSource,
attribute
);
if ( embeddedSource.isVirtualAttribute() ) {
attribute.setPropertyAccessorName( "embedded" );
}
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.spi.RuntimeModelCreationContext;
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.spi.TypeConfiguration;
@ -78,6 +79,7 @@ public class MetadataContext {
private final Set<MappedSuperclass> knownMappedSuperclasses;
private final TypeConfiguration typeConfiguration;
private final JpaStaticMetaModelPopulationSetting jpaStaticMetaModelPopulationSetting;
private final JpaMetaModelPopulationSetting jpaMetaModelPopulationSetting;
private final AttributeFactory attributeFactory = new AttributeFactory( this );
private final Map<Class<?>, EntityDomainType<?>> entityTypes = new HashMap<>();
@ -105,12 +107,14 @@ public class MetadataContext {
MappingMetamodel mappingMetamodel,
MetadataImplementor bootMetamodel,
JpaStaticMetaModelPopulationSetting jpaStaticMetaModelPopulationSetting,
JpaMetaModelPopulationSetting jpaMetaModelPopulationSetting,
RuntimeModelCreationContext runtimeModelCreationContext) {
this.jpaMetamodel = jpaMetamodel;
this.metamodel = mappingMetamodel;
this.knownMappedSuperclasses = bootMetamodel.getMappedSuperclassMappingsCopy();
this.typeConfiguration = runtimeModelCreationContext.getTypeConfiguration();
this.jpaStaticMetaModelPopulationSetting = jpaStaticMetaModelPopulationSetting;
this.jpaMetaModelPopulationSetting = jpaMetaModelPopulationSetting;
this.runtimeModelCreationContext = runtimeModelCreationContext;
}
@ -287,13 +291,12 @@ public class MetadataContext {
property
);
if ( attribute != null ) {
( (AttributeContainer<Object>) jpaMapping ).getInFlightAccess().addAttribute( attribute );
addAttribute( jpaMapping, attribute );
if ( property.isNaturalIdentifier() ) {
( ( AttributeContainer<Object>) jpaMapping ).getInFlightAccess()
.applyNaturalIdAttribute( attribute );
}
}
}
( (AttributeContainer<?>) jpaMapping ).getInFlightAccess().finishUp();
@ -329,7 +332,7 @@ public class MetadataContext {
}
final PersistentAttribute<Object, ?> attribute = attributeFactory.buildAttribute( jpaType, property );
if ( attribute != null ) {
( (AttributeContainer<Object>) jpaType ).getInFlightAccess().addAttribute( attribute );
addAttribute( jpaType, attribute );
if ( property.isNaturalIdentifier() ) {
( ( AttributeContainer<Object>) jpaType ).getInFlightAccess()
.applyNaturalIdAttribute( attribute );
@ -370,7 +373,7 @@ public class MetadataContext {
final Property property = propertyItr.next();
final PersistentAttribute<Object, ?> attribute = attributeFactory.buildAttribute( (ManagedDomainType<Object>) embeddable, property );
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
// 2) register the part (mapping role)

View File

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

View File

@ -158,6 +158,7 @@ import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.AttributeMetadata;
import org.hibernate.metamodel.mapping.AttributeMetadataAccess;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
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.StateArrayContributorMapping;
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.CompoundNaturalIdMapping;
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

View File

@ -6,7 +6,7 @@
*/
//$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;
/**

View File

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

View File

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