HHH-14191 - ANY mapping support
- `@ManyToAny` - embeddable sub-attribute
This commit is contained in:
parent
97a88ebbcf
commit
3d46fabeb5
|
@ -6,12 +6,14 @@
|
|||
*/
|
||||
package org.hibernate;
|
||||
|
||||
import org.hibernate.metamodel.mapping.NonTransientException;
|
||||
|
||||
/**
|
||||
* Thrown from methods added for 6.0 that are not yet implemented.
|
||||
*
|
||||
* todo (6.0) : prior going final, we need to find all usages of this and implement all methods (or throw a different exception)
|
||||
*/
|
||||
public class NotYetImplementedFor6Exception extends RuntimeException {
|
||||
public class NotYetImplementedFor6Exception extends RuntimeException implements NonTransientException {
|
||||
public NotYetImplementedFor6Exception(String message) {
|
||||
super( message );
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@ import org.hibernate.mapping.SyntheticProperty;
|
|||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.mapping.ToOne;
|
||||
import org.hibernate.mapping.Value;
|
||||
import org.hibernate.type.DiscriminatorType;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
|
@ -953,46 +954,53 @@ public class BinderHelper {
|
|||
EntityBinder entityBinder,
|
||||
boolean optional,
|
||||
MetadataBuildingContext context) {
|
||||
final XProperty xProperty = inferredData.getProperty();
|
||||
|
||||
//All FK columns should be in the same table
|
||||
Any value = new Any( context, columns[0].getTable() );
|
||||
AnyMetaDef metaAnnDef = inferredData.getProperty().getAnnotation( AnyMetaDef.class );
|
||||
final Any value = new Any( context, columns[0].getTable() );
|
||||
|
||||
value.setLazy( lazy );
|
||||
if ( metaAnnDef != null ) {
|
||||
//local has precedence over general and can be mapped for future reference if named
|
||||
bindAnyMetaDefs( inferredData.getProperty(), context );
|
||||
}
|
||||
else {
|
||||
metaAnnDef = context.getMetadataCollector().getAnyMetaDef( anyMetaDefName );
|
||||
}
|
||||
if ( metaAnnDef != null ) {
|
||||
value.setIdentifierType( metaAnnDef.idType() );
|
||||
value.setMetaType( metaAnnDef.metaType() );
|
||||
|
||||
HashMap values = new HashMap();
|
||||
org.hibernate.type.Type metaType = context.getMetadataCollector().getTypeConfiguration().getBasicTypeRegistry().getRegisteredType( value.getMetaType() );
|
||||
for (MetaValue metaValue : metaAnnDef.metaValues()) {
|
||||
try {
|
||||
Object discrim = ( (org.hibernate.type.DiscriminatorType) metaType ).stringToObject( metaValue
|
||||
.value() );
|
||||
String entityName = metaValue.targetEntity().getName();
|
||||
values.put( discrim, entityName );
|
||||
}
|
||||
catch (ClassCastException cce) {
|
||||
throw new MappingException( "metaType was not a DiscriminatorType: "
|
||||
+ metaType.getName() );
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new MappingException( "could not interpret metaValue", e );
|
||||
}
|
||||
}
|
||||
if ( !values.isEmpty() ) {
|
||||
value.setMetaValues( values );
|
||||
}
|
||||
final AnyMetaDef metaDefToUse;
|
||||
final AnyMetaDef localMetaDefAnn = xProperty.getAnnotation( AnyMetaDef.class );
|
||||
if ( localMetaDefAnn != null ) {
|
||||
//local has precedence over general and can be mapped for future reference if named
|
||||
bindAnyMetaDefs(xProperty, context );
|
||||
metaDefToUse = localMetaDefAnn;
|
||||
}
|
||||
else {
|
||||
throw new AnnotationException( "Unable to find @AnyMetaDef for an @(ManyTo)Any mapping: "
|
||||
+ StringHelper.qualify( propertyHolder.getPath(), inferredData.getPropertyName() ) );
|
||||
metaDefToUse = context.getMetadataCollector().getAnyMetaDef( anyMetaDefName );
|
||||
if ( metaDefToUse == null ) {
|
||||
throw new AnnotationException(
|
||||
"Unable to find @AnyMetaDef for an @(ManyTo)Any mapping: "
|
||||
+ StringHelper.qualify( propertyHolder.getPath(), inferredData.getPropertyName() )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
value.setIdentifierType( metaDefToUse.idType() );
|
||||
value.setMetaType( metaDefToUse.metaType() );
|
||||
|
||||
final HashMap<Object,String> values = new HashMap<>();
|
||||
final DiscriminatorType<?> metaType = (DiscriminatorType<?>) context.getMetadataCollector()
|
||||
.getTypeConfiguration()
|
||||
.getBasicTypeRegistry()
|
||||
.getRegisteredType( value.getMetaType() );
|
||||
|
||||
for (int i = 0; i < metaDefToUse.metaValues().length; i++) {
|
||||
final MetaValue metaValue = metaDefToUse.metaValues()[ i ];
|
||||
try {
|
||||
final Object discriminator = metaType.stringToObject( metaValue.value() );
|
||||
final String entityName = metaValue.targetEntity().getName();
|
||||
values.put( discriminator, entityName );
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new MappingException( "Could not interpret @MetaValue", e );
|
||||
}
|
||||
}
|
||||
|
||||
if ( !values.isEmpty() ) {
|
||||
value.setMetaValues( values );
|
||||
}
|
||||
|
||||
value.setCascadeDeleteEnabled( cascadeOnDelete );
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* 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.internal.util;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class JavaHelper {
|
||||
public static Package getPackageFor(String name) {
|
||||
return getPackageFor( name, JavaHelper.class.getClassLoader() );
|
||||
}
|
||||
|
||||
public static Package getPackageFor(String name, ClassLoader classLoader) {
|
||||
// after Java 9 we can do -
|
||||
//return classLoader.getDefinedPackage( name );
|
||||
|
||||
return Package.getPackage( name );
|
||||
}
|
||||
|
||||
private JavaHelper() {
|
||||
// disallow direct instantiation
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.metamodel.mapping;
|
||||
|
||||
import org.hibernate.sql.results.graph.Fetchable;
|
||||
import org.hibernate.sql.results.graph.FetchableContainer;
|
||||
|
||||
/**
|
||||
* A discriminated association. This is similar to an association to
|
||||
|
@ -20,9 +21,9 @@ import org.hibernate.sql.results.graph.Fetchable;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface DiscriminatedAssociationModelPart extends Fetchable {
|
||||
public interface DiscriminatedAssociationModelPart extends Fetchable, FetchableContainer {
|
||||
BasicValuedModelPart getDiscriminatorPart();
|
||||
ModelPart getKeyPart();
|
||||
BasicValuedModelPart getKeyPart();
|
||||
|
||||
EntityMappingType resolveDiscriminatorValue(Object discriminatorValue);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
package org.hibernate.metamodel.mapping;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
@ -18,15 +19,19 @@ import java.util.function.Function;
|
|||
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
import org.hibernate.engine.config.spi.ConfigurationService;
|
||||
import org.hibernate.engine.spi.CascadeStyle;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
import org.hibernate.mapping.Any;
|
||||
import org.hibernate.mapping.BasicValue;
|
||||
import org.hibernate.mapping.Component;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.Selectable;
|
||||
import org.hibernate.metamodel.mapping.internal.DiscriminatedAssociationAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.internal.MappingModelCreationHelper;
|
||||
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
|
||||
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||
|
@ -34,6 +39,7 @@ import org.hibernate.metamodel.model.domain.NavigableRole;
|
|||
import org.hibernate.metamodel.spi.EmbeddableRepresentationStrategy;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.property.access.spi.PropertyAccess;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.sql.ast.Clause;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
|
@ -41,12 +47,15 @@ import org.hibernate.sql.results.graph.DomainResult;
|
|||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||
import org.hibernate.sql.results.graph.Fetchable;
|
||||
import org.hibernate.sql.results.graph.embeddable.internal.EmbeddableResultImpl;
|
||||
import org.hibernate.type.AnyType;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.CollectionType;
|
||||
import org.hibernate.type.CompositeType;
|
||||
import org.hibernate.type.EntityType;
|
||||
import org.hibernate.type.Type;
|
||||
import org.hibernate.type.descriptor.java.ImmutableMutabilityPlan;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.java.MutabilityPlan;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
|
@ -154,8 +163,10 @@ public class EmbeddableMappingType implements ManagedMappingType {
|
|||
Component bootDescriptor,
|
||||
CompositeType compositeType,
|
||||
MappingModelCreationProcess creationProcess) {
|
||||
final String containingTableExpression = valueMapping.getContainingTableExpression();
|
||||
final SessionFactoryImplementor sessionFactory = creationProcess.getCreationContext().getSessionFactory();
|
||||
final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration();
|
||||
|
||||
final String containingTableExpression = valueMapping.getContainingTableExpression();
|
||||
final List<String> mappedColumnExpressions = valueMapping.getMappedColumnExpressions();
|
||||
|
||||
final Type[] subtypes = compositeType.getSubtypes();
|
||||
|
@ -174,7 +185,7 @@ public class EmbeddableMappingType implements ManagedMappingType {
|
|||
final Selectable selectable = basicValue.getColumn();
|
||||
|
||||
final String mappedColumnExpression = mappedColumnExpressions.get( columnPosition++ );
|
||||
assert mappedColumnExpression.equals( selectable.getText( creationProcess.getCreationContext().getSessionFactory().getDialect() ) );
|
||||
assert mappedColumnExpression.equals( selectable.getText( sessionFactory.getDialect() ) );
|
||||
|
||||
attributeMappings.put(
|
||||
bootPropertyDescriptor.getName(),
|
||||
|
@ -196,9 +207,112 @@ public class EmbeddableMappingType implements ManagedMappingType {
|
|||
)
|
||||
);
|
||||
}
|
||||
else if ( subtype instanceof AnyType ) {
|
||||
final Any bootValueMapping = (Any) bootPropertyDescriptor.getValue();
|
||||
final AnyType anyType = (AnyType) subtype;
|
||||
|
||||
final PropertyAccess propertyAccess = representationStrategy.resolvePropertyAccess( bootPropertyDescriptor );
|
||||
final boolean nullable = bootValueMapping.isNullable();
|
||||
final boolean insertable = bootPropertyDescriptor.isInsertable();
|
||||
final boolean updateable = bootPropertyDescriptor.isUpdateable();
|
||||
final boolean includeInOptimisticLocking = bootPropertyDescriptor.isOptimisticLocked();
|
||||
final CascadeStyle cascadeStyle = compositeType.getCascadeStyle( attributeIndex );
|
||||
final MutabilityPlan mutabilityPlan;
|
||||
|
||||
if ( updateable ) {
|
||||
mutabilityPlan = new MutabilityPlan() {
|
||||
@Override
|
||||
public boolean isMutable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object deepCopy(Object value) {
|
||||
if ( value == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return anyType.deepCopy( value, creationProcess.getCreationContext().getSessionFactory() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Serializable disassemble(Object value) {
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object assemble(Serializable cached) {
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
}
|
||||
};
|
||||
}
|
||||
else {
|
||||
mutabilityPlan = ImmutableMutabilityPlan.INSTANCE;
|
||||
}
|
||||
|
||||
final StateArrayContributorMetadataAccess attributeMetadataAccess = entityMappingType -> new StateArrayContributorMetadata() {
|
||||
@Override
|
||||
public PropertyAccess getPropertyAccess() {
|
||||
return propertyAccess;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MutabilityPlan getMutabilityPlan() {
|
||||
return mutabilityPlan;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNullable() {
|
||||
return nullable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInsertable() {
|
||||
return insertable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUpdatable() {
|
||||
return updateable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIncludedInDirtyChecking() {
|
||||
// todo (6.0) : do not believe this is correct
|
||||
return updateable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIncludedInOptimisticLocking() {
|
||||
return includeInOptimisticLocking;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CascadeStyle getCascadeStyle() {
|
||||
return cascadeStyle;
|
||||
}
|
||||
};
|
||||
|
||||
attributeMappings.put(
|
||||
bootPropertyDescriptor.getName(),
|
||||
new DiscriminatedAssociationAttributeMapping(
|
||||
valueMapping.getNavigableRole().append( bootPropertyDescriptor.getName() ),
|
||||
typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Object.class ),
|
||||
this,
|
||||
attributeIndex,
|
||||
attributeMetadataAccess,
|
||||
bootPropertyDescriptor.isLazy() ? FetchTiming.DELAYED : FetchTiming.IMMEDIATE,
|
||||
propertyAccess,
|
||||
bootPropertyDescriptor,
|
||||
anyType,
|
||||
bootValueMapping,
|
||||
creationProcess
|
||||
)
|
||||
);
|
||||
}
|
||||
else if ( subtype instanceof CompositeType ) {
|
||||
final CompositeType subCompositeType = (CompositeType) subtype;
|
||||
final int columnSpan = subCompositeType.getColumnSpan( creationProcess.getCreationContext().getSessionFactory() );
|
||||
final int columnSpan = subCompositeType.getColumnSpan( sessionFactory );
|
||||
|
||||
final List<String> customReadExpressions = new ArrayList<>( columnSpan );
|
||||
final List<String> customWriteExpressions = new ArrayList<>( columnSpan );
|
||||
|
|
|
@ -11,6 +11,7 @@ import org.hibernate.metamodel.mapping.ManagedMappingType;
|
|||
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
|
||||
import org.hibernate.property.access.spi.PropertyAccess;
|
||||
import org.hibernate.sql.results.graph.FetchOptions;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
|
@ -25,7 +26,7 @@ public abstract class AbstractSingularAttributeMapping
|
|||
String name,
|
||||
int stateArrayPosition,
|
||||
StateArrayContributorMetadataAccess attributeMetadataAccess,
|
||||
FetchStrategy mappedFetchStrategy,
|
||||
FetchOptions mappedFetchStrategy,
|
||||
ManagedMappingType declaringType,
|
||||
PropertyAccess propertyAccess) {
|
||||
super( name, attributeMetadataAccess, mappedFetchStrategy, stateArrayPosition, declaringType );
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
package org.hibernate.metamodel.mapping.internal;
|
||||
|
||||
import org.hibernate.engine.FetchStrategy;
|
||||
import org.hibernate.engine.FetchStyle;
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
import org.hibernate.metamodel.mapping.ManagedMappingType;
|
||||
|
@ -44,7 +43,7 @@ public abstract class AbstractStateArrayContributorMapping
|
|||
public AbstractStateArrayContributorMapping(
|
||||
String name,
|
||||
StateArrayContributorMetadataAccess attributeMetadataAccess,
|
||||
FetchStrategy mappedFetchStrategy,
|
||||
FetchOptions mappedFetchStrategy,
|
||||
int stateArrayPosition,
|
||||
ManagedMappingType declaringType) {
|
||||
this(
|
||||
|
|
|
@ -42,25 +42,29 @@ import static org.hibernate.sql.ast.spi.SqlExpressionResolver.createColumnRefere
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public class AnyDiscriminatorPart implements BasicValuedModelPart, FetchOptions {
|
||||
public static final String PART_NAME = EntityDiscriminatorMapping.ROLE_NAME;
|
||||
public static final String ROLE_NAME = EntityDiscriminatorMapping.ROLE_NAME;
|
||||
|
||||
private final NavigableRole navigableRole;
|
||||
private final DiscriminatedAssociationModelPart declaringType;
|
||||
|
||||
private final String table;
|
||||
private final String column;
|
||||
private final boolean nullable;
|
||||
|
||||
private final MetaType metaType;
|
||||
|
||||
public AnyDiscriminatorPart(
|
||||
NavigableRole attributeRole,
|
||||
NavigableRole partRole,
|
||||
DiscriminatedAssociationModelPart declaringType,
|
||||
String table,
|
||||
String column,
|
||||
boolean nullable,
|
||||
MetaType metaType) {
|
||||
this.navigableRole = attributeRole.append( PART_NAME );
|
||||
this.navigableRole = partRole;
|
||||
this.declaringType = declaringType;
|
||||
this.table = table;
|
||||
this.column = column;
|
||||
this.nullable = nullable;
|
||||
this.metaType = metaType;
|
||||
}
|
||||
|
||||
|
@ -104,7 +108,7 @@ public class AnyDiscriminatorPart implements BasicValuedModelPart, FetchOptions
|
|||
|
||||
@Override
|
||||
public String getPartName() {
|
||||
return PART_NAME;
|
||||
return ROLE_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -171,7 +175,7 @@ public class AnyDiscriminatorPart implements BasicValuedModelPart, FetchOptions
|
|||
fetchParent,
|
||||
fetchablePath,
|
||||
this,
|
||||
false,
|
||||
nullable,
|
||||
null,
|
||||
fetchTiming,
|
||||
creationState
|
||||
|
|
|
@ -39,14 +39,14 @@ import org.hibernate.sql.results.graph.basic.BasicFetch;
|
|||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import static org.hibernate.metamodel.mapping.internal.DiscriminatedAssociationMapping.KEY_ROLE_NAME;
|
||||
|
||||
/**
|
||||
* Acts as a ModelPart for the key portion of an any-valued mapping
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
|
||||
public static final String ROLE_NAME = "{key}";
|
||||
|
||||
private final NavigableRole navigableRole;
|
||||
private final String table;
|
||||
private final String column;
|
||||
|
@ -56,9 +56,8 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
|
|||
|
||||
public AnyKeyPart(
|
||||
NavigableRole navigableRole,
|
||||
String table,
|
||||
DiscriminatedAssociationModelPart anyPart, String table,
|
||||
String column,
|
||||
DiscriminatedAssociationModelPart anyPart,
|
||||
boolean nullable,
|
||||
JdbcMapping jdbcMapping) {
|
||||
this.navigableRole = navigableRole;
|
||||
|
@ -101,7 +100,7 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
|
|||
|
||||
@Override
|
||||
public String getPartName() {
|
||||
return KEY_ROLE_NAME;
|
||||
return ROLE_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -126,7 +125,7 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
|
|||
|
||||
@Override
|
||||
public FetchOptions getMappedFetchOptions() {
|
||||
return null;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -149,7 +148,7 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
|
|||
.getCreationContext()
|
||||
.getSessionFactory();
|
||||
|
||||
final TableGroup tableGroup = fromClauseAccess.getTableGroup( fetchParent.getNavigablePath() );
|
||||
final TableGroup tableGroup = fromClauseAccess.getTableGroup( fetchParent.getNavigablePath().getParent() );
|
||||
final TableReference tableReference = tableGroup.getTableReference( table );
|
||||
|
||||
final Expression columnReference = sqlExpressionResolver.resolveSqlExpression(
|
||||
|
|
|
@ -6,17 +6,14 @@
|
|||
*/
|
||||
package org.hibernate.metamodel.mapping.internal;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.engine.FetchStrategy;
|
||||
import org.hibernate.engine.FetchStyle;
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.mapping.Any;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.Selectable;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.DiscriminatedAssociationModelPart;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
|
@ -32,14 +29,8 @@ import org.hibernate.sql.results.graph.Fetch;
|
|||
import org.hibernate.sql.results.graph.FetchParent;
|
||||
import org.hibernate.sql.results.graph.Fetchable;
|
||||
import org.hibernate.type.AnyType;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.CompositeType;
|
||||
import org.hibernate.type.MetaType;
|
||||
import org.hibernate.type.Type;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
|
||||
import static org.hibernate.metamodel.mapping.internal.DiscriminatedAssociationMapping.KEY_ROLE_NAME;
|
||||
|
||||
/**
|
||||
* Singular, any-valued attribute
|
||||
*
|
||||
|
@ -55,71 +46,35 @@ public class DiscriminatedAssociationAttributeMapping
|
|||
|
||||
public DiscriminatedAssociationAttributeMapping(
|
||||
NavigableRole attributeRole,
|
||||
JavaTypeDescriptor<Object> baseAssociationJtd,
|
||||
JavaTypeDescriptor<?> baseAssociationJtd,
|
||||
ManagedMappingType declaringType,
|
||||
int stateArrayPosition,
|
||||
StateArrayContributorMetadataAccess attributeMetadataAccess,
|
||||
FetchStrategy mappedFetchStrategy,
|
||||
FetchTiming fetchTiming,
|
||||
PropertyAccess propertyAccess,
|
||||
Property bootProperty,
|
||||
AnyType anyType,
|
||||
Any bootValueMapping,
|
||||
MappingModelCreationProcess creationProcess) {
|
||||
super( bootProperty.getName(), stateArrayPosition, attributeMetadataAccess, mappedFetchStrategy, declaringType, propertyAccess );
|
||||
super(
|
||||
bootProperty.getName(),
|
||||
stateArrayPosition,
|
||||
attributeMetadataAccess,
|
||||
fetchTiming == FetchTiming.IMMEDIATE
|
||||
? new FetchStrategy( FetchTiming.IMMEDIATE, FetchStyle.SELECT )
|
||||
: new FetchStrategy( FetchTiming.DELAYED, FetchStyle.SELECT ),
|
||||
declaringType,
|
||||
propertyAccess
|
||||
);
|
||||
this.navigableRole = attributeRole;
|
||||
|
||||
final SessionFactoryImplementor sessionFactory = creationProcess.getCreationContext().getSessionFactory();
|
||||
|
||||
final JdbcEnvironment jdbcEnvironment = sessionFactory.getJdbcServices().getJdbcEnvironment();
|
||||
final String tableName = jdbcEnvironment.getQualifiedObjectNameFormatter().format(
|
||||
bootValueMapping.getTable().getQualifiedTableName(),
|
||||
jdbcEnvironment.getDialect()
|
||||
);
|
||||
|
||||
assert bootValueMapping.getColumnSpan() > 1;
|
||||
final Iterator<Selectable> columnIterator = bootValueMapping.getColumnIterator();
|
||||
|
||||
assert columnIterator.hasNext();
|
||||
|
||||
final AnyDiscriminatorPart discriminatorPart = new AnyDiscriminatorPart(
|
||||
this.discriminatorMapping = DiscriminatedAssociationMapping.from(
|
||||
attributeRole,
|
||||
this,
|
||||
tableName,
|
||||
columnIterator.next().getText( jdbcEnvironment.getDialect() ),
|
||||
(MetaType) anyType.getDiscriminatorType()
|
||||
);
|
||||
|
||||
|
||||
final Fetchable keyPart;
|
||||
final Type keyType = anyType.getIdentifierType();
|
||||
if ( keyType instanceof BasicType ) {
|
||||
assert columnIterator.hasNext();
|
||||
|
||||
keyPart = new AnyKeyPart(
|
||||
attributeRole.append( KEY_ROLE_NAME ),
|
||||
tableName,
|
||||
columnIterator.next().getText( jdbcEnvironment.getDialect() ),
|
||||
this,
|
||||
attributeMetadataAccess.resolveAttributeMetadata( null ).isNullable(),
|
||||
(BasicType<?>) keyType
|
||||
);
|
||||
|
||||
assert ! columnIterator.hasNext();
|
||||
}
|
||||
else {
|
||||
assert keyType instanceof CompositeType;
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
}
|
||||
|
||||
this.discriminatorMapping = new DiscriminatedAssociationMapping(
|
||||
this,
|
||||
discriminatorPart,
|
||||
keyPart,
|
||||
baseAssociationJtd,
|
||||
bootProperty.isLazy()
|
||||
? FetchTiming.DELAYED
|
||||
: FetchTiming.IMMEDIATE,
|
||||
sessionFactory
|
||||
this,
|
||||
anyType,
|
||||
bootValueMapping,
|
||||
creationProcess
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -129,7 +84,7 @@ public class DiscriminatedAssociationAttributeMapping
|
|||
}
|
||||
|
||||
@Override
|
||||
public ModelPart getKeyPart() {
|
||||
public BasicValuedModelPart getKeyPart() {
|
||||
return discriminatorMapping.getKeyPart();
|
||||
}
|
||||
|
||||
|
@ -167,4 +122,34 @@ public class DiscriminatedAssociationAttributeMapping
|
|||
public MappingType getMappedType() {
|
||||
return discriminatorMapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberOfFetchables() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFetchables(Consumer<Fetchable> fetchableConsumer, EntityMappingType treatTargetType) {
|
||||
fetchableConsumer.accept( getDiscriminatorPart() );
|
||||
fetchableConsumer.accept( getKeyPart() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelPart findSubPart(String name, EntityMappingType treatTargetType) {
|
||||
if ( AnyDiscriminatorPart.ROLE_NAME.equals( name ) ) {
|
||||
return getDiscriminatorPart();
|
||||
}
|
||||
|
||||
if ( AnyKeyPart.ROLE_NAME.equals( name ) ) {
|
||||
return getKeyPart();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSubParts(Consumer<ModelPart> consumer, EntityMappingType treatTargetType) {
|
||||
consumer.accept( getDiscriminatorPart() );
|
||||
consumer.accept( getKeyPart() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,24 +6,33 @@
|
|||
*/
|
||||
package org.hibernate.metamodel.mapping.internal;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.engine.FetchStyle;
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.mapping.Any;
|
||||
import org.hibernate.mapping.Selectable;
|
||||
import org.hibernate.metamodel.RuntimeMetamodels;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.DiscriminatedAssociationModelPart;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||
import org.hibernate.metamodel.mapping.MappingType;
|
||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
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.DomainResultGraphNode;
|
||||
import org.hibernate.sql.results.graph.Fetch;
|
||||
import org.hibernate.sql.results.graph.FetchOptions;
|
||||
import org.hibernate.sql.results.graph.FetchParent;
|
||||
|
@ -31,6 +40,9 @@ import org.hibernate.sql.results.graph.FetchParentAccess;
|
|||
import org.hibernate.sql.results.graph.Fetchable;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions;
|
||||
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
|
||||
import org.hibernate.type.AnyType;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.MetaType;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
|
||||
/**
|
||||
|
@ -39,11 +51,67 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public class DiscriminatedAssociationMapping implements MappingType, FetchOptions {
|
||||
public static final String KEY_ROLE_NAME = "{key}";
|
||||
|
||||
public static DiscriminatedAssociationMapping from(
|
||||
NavigableRole containerRole,
|
||||
JavaTypeDescriptor<?> baseAssociationJtd,
|
||||
DiscriminatedAssociationModelPart declaringModelPart,
|
||||
AnyType anyType,
|
||||
Any bootValueMapping,
|
||||
MappingModelCreationProcess creationProcess) {
|
||||
final SessionFactoryImplementor sessionFactory = creationProcess.getCreationContext().getSessionFactory();
|
||||
|
||||
final JdbcEnvironment jdbcEnvironment = sessionFactory.getJdbcServices().getJdbcEnvironment();
|
||||
final String tableName = jdbcEnvironment.getQualifiedObjectNameFormatter().format(
|
||||
bootValueMapping.getTable().getQualifiedTableName(),
|
||||
jdbcEnvironment.getDialect()
|
||||
);
|
||||
|
||||
assert bootValueMapping.getColumnSpan() == 2;
|
||||
final Iterator<Selectable> columnIterator = bootValueMapping.getColumnIterator();
|
||||
|
||||
assert columnIterator.hasNext();
|
||||
final Selectable metaColumn = columnIterator.next();
|
||||
assert columnIterator.hasNext();
|
||||
final Selectable keyColumn = columnIterator.next();
|
||||
assert ! columnIterator.hasNext();
|
||||
|
||||
final AnyDiscriminatorPart discriminatorPart = new AnyDiscriminatorPart(
|
||||
containerRole.append( AnyDiscriminatorPart.ROLE_NAME),
|
||||
declaringModelPart,
|
||||
tableName,
|
||||
metaColumn.getText( jdbcEnvironment.getDialect() ),
|
||||
bootValueMapping.isNullable(),
|
||||
(MetaType) anyType.getDiscriminatorType()
|
||||
);
|
||||
|
||||
|
||||
final BasicType<?> keyType = (BasicType<?>) anyType.getIdentifierType();
|
||||
final BasicValuedModelPart keyPart = new AnyKeyPart(
|
||||
containerRole.append( AnyKeyPart.ROLE_NAME),
|
||||
declaringModelPart,
|
||||
tableName,
|
||||
keyColumn.getText( jdbcEnvironment.getDialect() ),
|
||||
bootValueMapping.isNullable(),
|
||||
keyType
|
||||
);
|
||||
|
||||
return new DiscriminatedAssociationMapping(
|
||||
declaringModelPart,
|
||||
discriminatorPart,
|
||||
keyPart,
|
||||
baseAssociationJtd,
|
||||
bootValueMapping.isLazy()
|
||||
? FetchTiming.DELAYED
|
||||
: FetchTiming.IMMEDIATE,
|
||||
bootValueMapping.getMetaValues(),
|
||||
sessionFactory
|
||||
);
|
||||
}
|
||||
|
||||
private final DiscriminatedAssociationModelPart modelPart;
|
||||
private final AnyDiscriminatorPart discriminatorPart;
|
||||
private final Fetchable keyPart;
|
||||
private final BasicValuedModelPart keyPart;
|
||||
|
||||
private final JavaTypeDescriptor<?> baseAssociationJtd;
|
||||
|
||||
|
@ -64,9 +132,10 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
|
|||
public DiscriminatedAssociationMapping(
|
||||
DiscriminatedAssociationModelPart modelPart,
|
||||
AnyDiscriminatorPart discriminatorPart,
|
||||
Fetchable keyPart,
|
||||
BasicValuedModelPart keyPart,
|
||||
JavaTypeDescriptor<?> baseAssociationJtd,
|
||||
FetchTiming fetchTiming,
|
||||
Map<Object,String> discriminatorValueMappings,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
this.modelPart = modelPart;
|
||||
this.discriminatorPart = discriminatorPart;
|
||||
|
@ -75,8 +144,8 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
|
|||
this.fetchTiming = fetchTiming;
|
||||
|
||||
final RuntimeMetamodels runtimeMetamodels = sessionFactory.getRuntimeMetamodels();
|
||||
discriminatorPart.getMetaType().getDiscriminatorValuesToEntityNameMap().forEach(
|
||||
(value, entityName) -> discriminatorValueMappings.add(
|
||||
discriminatorValueMappings.forEach(
|
||||
(value, entityName) -> this.discriminatorValueMappings.add(
|
||||
new ValueMapping( value, runtimeMetamodels.getEntityMappingType( entityName ) )
|
||||
)
|
||||
);
|
||||
|
@ -90,7 +159,7 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
|
|||
return discriminatorPart;
|
||||
}
|
||||
|
||||
public Fetchable getKeyPart() {
|
||||
public BasicValuedModelPart getKeyPart() {
|
||||
return keyPart;
|
||||
}
|
||||
|
||||
|
@ -137,64 +206,65 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
|
|||
LockMode lockMode,
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
final Fetch discriminatorValueFetch = getDiscriminatorPart().generateFetch(
|
||||
fetchParent,
|
||||
fetchablePath.append( AnyDiscriminatorPart.PART_NAME ),
|
||||
FetchTiming.IMMEDIATE,
|
||||
selected,
|
||||
lockMode,
|
||||
resultVariable,
|
||||
creationState
|
||||
);
|
||||
|
||||
final Fetch keyValueFetch = getKeyPart().generateFetch(
|
||||
fetchParent,
|
||||
fetchablePath.append( ForeignKeyDescriptor.PART_NAME ),
|
||||
FetchTiming.IMMEDIATE,
|
||||
selected,
|
||||
lockMode,
|
||||
resultVariable,
|
||||
creationState
|
||||
);
|
||||
|
||||
return new AnyValuedFetch(
|
||||
fetchablePath,
|
||||
baseAssociationJtd,
|
||||
modelPart,
|
||||
discriminatorValueFetch,
|
||||
keyValueFetch,
|
||||
fetchTiming,
|
||||
fetchParent
|
||||
fetchParent,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
|
||||
private static class AnyValuedFetch implements Fetch {
|
||||
public <T> DomainResult<T> createDomainResult(
|
||||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
return new AnyValuedResult<>(
|
||||
navigablePath,
|
||||
baseAssociationJtd,
|
||||
modelPart,
|
||||
resultVariable
|
||||
);
|
||||
}
|
||||
|
||||
private static abstract class AnyValuedResultGraphNode implements DomainResultGraphNode, FetchParent {
|
||||
private final NavigablePath navigablePath;
|
||||
|
||||
private final DiscriminatedAssociationModelPart fetchedPart;
|
||||
private final DiscriminatedAssociationModelPart graphedPart;
|
||||
private final JavaTypeDescriptor<?> baseAssociationJtd;
|
||||
|
||||
private final Fetch discriminatorValueFetch;
|
||||
private final Fetch keyValueFetch;
|
||||
private final FetchTiming fetchTiming;
|
||||
private final FetchParent fetchParent;
|
||||
private Fetch discriminatorValueFetch;
|
||||
private Fetch keyValueFetch;
|
||||
|
||||
public AnyValuedFetch(
|
||||
public AnyValuedResultGraphNode(
|
||||
NavigablePath navigablePath,
|
||||
DiscriminatedAssociationModelPart fetchedPart,
|
||||
Fetch discriminatorValueFetch,
|
||||
Fetch keyValueFetch,
|
||||
FetchTiming fetchTiming,
|
||||
FetchParent fetchParent) {
|
||||
DiscriminatedAssociationModelPart graphedPart,
|
||||
JavaTypeDescriptor<?> baseAssociationJtd) {
|
||||
this.navigablePath = navigablePath;
|
||||
this.fetchedPart = fetchedPart;
|
||||
this.discriminatorValueFetch = discriminatorValueFetch;
|
||||
this.keyValueFetch = keyValueFetch;
|
||||
this.fetchTiming = fetchTiming;
|
||||
this.fetchParent = fetchParent;
|
||||
this.graphedPart = graphedPart;
|
||||
this.baseAssociationJtd = baseAssociationJtd;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaTypeDescriptor<?> getResultJavaTypeDescriptor() {
|
||||
return fetchedPart.getJavaTypeDescriptor();
|
||||
protected void afterInitialize(DomainResultCreationState creationState) {
|
||||
final List<Fetch> fetches = creationState.visitFetches( this );
|
||||
assert fetches.size() == 2;
|
||||
|
||||
discriminatorValueFetch = fetches.get( 0 );
|
||||
keyValueFetch = fetches.get( 1 );
|
||||
}
|
||||
|
||||
public Fetch getDiscriminatorValueFetch() {
|
||||
return discriminatorValueFetch;
|
||||
}
|
||||
|
||||
public Fetch getKeyValueFetch() {
|
||||
return keyValueFetch;
|
||||
}
|
||||
|
||||
public JavaTypeDescriptor<?> getBaseAssociationJtd() {
|
||||
return baseAssociationJtd;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -202,6 +272,95 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
|
|||
return navigablePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaTypeDescriptor<?> getResultJavaTypeDescriptor() {
|
||||
return baseAssociationJtd;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAnyNonScalarResults() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DiscriminatedAssociationModelPart getReferencedMappingContainer() {
|
||||
return graphedPart;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DiscriminatedAssociationModelPart getReferencedMappingType() {
|
||||
return graphedPart;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Fetch> getFetches() {
|
||||
return Arrays.asList( discriminatorValueFetch, keyValueFetch );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fetch findFetch(Fetchable fetchable) {
|
||||
assert graphedPart.getDiscriminatorPart() == fetchable
|
||||
|| graphedPart.getKeyPart() == fetchable;
|
||||
|
||||
if ( graphedPart.getDiscriminatorPart() == fetchable ) {
|
||||
return discriminatorValueFetch;
|
||||
}
|
||||
|
||||
if ( graphedPart.getKeyPart() == fetchable ) {
|
||||
return keyValueFetch;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException( "Given Fetchable [" + fetchable + "] did not match either discriminator nor key mapping" );
|
||||
}
|
||||
}
|
||||
|
||||
private static class AnyValuedResult<T> extends AnyValuedResultGraphNode implements DomainResult<T> {
|
||||
private final String resultVariable;
|
||||
|
||||
public AnyValuedResult(
|
||||
NavigablePath navigablePath,
|
||||
JavaTypeDescriptor<?> baseAssociationJtd,
|
||||
DiscriminatedAssociationModelPart fetchedPart,
|
||||
String resultVariable) {
|
||||
super( navigablePath, fetchedPart, baseAssociationJtd );
|
||||
this.resultVariable = resultVariable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResultVariable() {
|
||||
return resultVariable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainResultAssembler<T> createResultAssembler(AssemblerCreationState creationState) {
|
||||
return new AnyResultAssembler<>(
|
||||
getNavigablePath(),
|
||||
getReferencedMappingContainer(),
|
||||
true,
|
||||
getDiscriminatorValueFetch().createAssembler( null, creationState ),
|
||||
getKeyValueFetch().createAssembler( null, creationState )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static class AnyValuedFetch extends AnyValuedResultGraphNode implements Fetch {
|
||||
private final FetchTiming fetchTiming;
|
||||
private final FetchParent fetchParent;
|
||||
|
||||
public AnyValuedFetch(
|
||||
NavigablePath navigablePath,
|
||||
JavaTypeDescriptor<?> baseAssociationJtd,
|
||||
DiscriminatedAssociationModelPart fetchedPart,
|
||||
FetchTiming fetchTiming,
|
||||
FetchParent fetchParent,
|
||||
DomainResultCreationState creationState) {
|
||||
super( navigablePath, fetchedPart, baseAssociationJtd );
|
||||
this.fetchTiming = fetchTiming;
|
||||
this.fetchParent = fetchParent;
|
||||
|
||||
afterInitialize( creationState );
|
||||
}
|
||||
|
||||
@Override
|
||||
public FetchParent getFetchParent() {
|
||||
return fetchParent;
|
||||
|
@ -209,7 +368,7 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
|
|||
|
||||
@Override
|
||||
public DiscriminatedAssociationModelPart getFetchedMapping() {
|
||||
return fetchedPart;
|
||||
return getReferencedMappingContainer();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -231,21 +390,22 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
|
|||
public DomainResultAssembler<?> createAssembler(
|
||||
FetchParentAccess parentAccess,
|
||||
AssemblerCreationState creationState) {
|
||||
return new AnyResultAssembler(
|
||||
navigablePath,
|
||||
fetchedPart,
|
||||
fetchTiming,
|
||||
discriminatorValueFetch.createAssembler( parentAccess, creationState ),
|
||||
keyValueFetch.createAssembler( parentAccess, creationState )
|
||||
return new AnyResultAssembler<>(
|
||||
getNavigablePath(),
|
||||
getFetchedMapping(),
|
||||
fetchTiming == FetchTiming.IMMEDIATE,
|
||||
getDiscriminatorValueFetch().createAssembler( parentAccess, creationState ),
|
||||
getKeyValueFetch().createAssembler( parentAccess, creationState )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static class AnyResultAssembler implements DomainResultAssembler<Object> {
|
||||
private static class AnyResultAssembler<T> implements DomainResultAssembler<T> {
|
||||
private final NavigablePath fetchedPath;
|
||||
|
||||
private final DiscriminatedAssociationModelPart fetchedPart;
|
||||
private final FetchTiming fetchTiming;
|
||||
|
||||
private final boolean eager;
|
||||
|
||||
private final DomainResultAssembler<?> discriminatorValueAssembler;
|
||||
private final DomainResultAssembler<?> keyValueAssembler;
|
||||
|
@ -253,18 +413,18 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
|
|||
public AnyResultAssembler(
|
||||
NavigablePath fetchedPath,
|
||||
DiscriminatedAssociationModelPart fetchedPart,
|
||||
FetchTiming fetchTiming,
|
||||
boolean eager,
|
||||
DomainResultAssembler<?> discriminatorValueAssembler,
|
||||
DomainResultAssembler<?> keyValueAssembler) {
|
||||
this.fetchedPath = fetchedPath;
|
||||
this.fetchedPart = fetchedPart;
|
||||
this.fetchTiming = fetchTiming;
|
||||
this.eager = eager;
|
||||
this.discriminatorValueAssembler = discriminatorValueAssembler;
|
||||
this.keyValueAssembler = keyValueAssembler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object assemble(
|
||||
public T assemble(
|
||||
RowProcessingState rowProcessingState,
|
||||
JdbcValuesSourceProcessingOptions options) {
|
||||
final Object discriminatorValue = discriminatorValueAssembler.assemble( rowProcessingState, options );
|
||||
|
@ -283,17 +443,18 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
|
|||
.getJdbcValuesSourceProcessingState()
|
||||
.getSession();
|
||||
|
||||
return session.internalLoad(
|
||||
//noinspection unchecked
|
||||
return (T) session.internalLoad(
|
||||
entityMapping.getEntityName(),
|
||||
keyValue,
|
||||
fetchTiming != FetchTiming.DELAYED,
|
||||
eager,
|
||||
// should not be null since we checked already. null would indicate bad data (ala, not-found handling)
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaTypeDescriptor<Object> getAssembledJavaTypeDescriptor() {
|
||||
public JavaTypeDescriptor<T> getAssembledJavaTypeDescriptor() {
|
||||
//noinspection unchecked
|
||||
return fetchedPart.getJavaTypeDescriptor();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* 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.function.Consumer;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
import org.hibernate.mapping.Any;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.CollectionPart;
|
||||
import org.hibernate.metamodel.mapping.DiscriminatedAssociationModelPart;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.MappingType;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
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.FetchOptions;
|
||||
import org.hibernate.sql.results.graph.FetchParent;
|
||||
import org.hibernate.type.AnyType;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class DiscriminatedCollectionPart implements DiscriminatedAssociationModelPart, CollectionPart {
|
||||
private final Nature nature;
|
||||
|
||||
private final NavigableRole partRole;
|
||||
private final DiscriminatedAssociationMapping discriminatorMapping;
|
||||
|
||||
public DiscriminatedCollectionPart(
|
||||
Nature nature,
|
||||
NavigableRole collectionRole,
|
||||
JavaTypeDescriptor<Object> baseAssociationJtd,
|
||||
Any bootValueMapping,
|
||||
AnyType anyType,
|
||||
MappingModelCreationProcess creationProcess) {
|
||||
this.nature = nature;
|
||||
this.partRole = collectionRole.append( nature.getName() );
|
||||
|
||||
this.discriminatorMapping = DiscriminatedAssociationMapping.from(
|
||||
partRole,
|
||||
baseAssociationJtd,
|
||||
this,
|
||||
anyType,
|
||||
bootValueMapping,
|
||||
creationProcess
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Nature getNature() {
|
||||
return nature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValuedModelPart getDiscriminatorPart() {
|
||||
return discriminatorMapping.getDiscriminatorPart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValuedModelPart getKeyPart() {
|
||||
return discriminatorMapping.getKeyPart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityMappingType resolveDiscriminatorValue(Object discriminatorValue) {
|
||||
return discriminatorMapping.resolveDiscriminatorValueToEntityName( discriminatorValue );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFetchableName() {
|
||||
return nature.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FetchOptions getMappedFetchOptions() {
|
||||
return discriminatorMapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fetch generateFetch(
|
||||
FetchParent fetchParent,
|
||||
NavigablePath fetchablePath,
|
||||
FetchTiming fetchTiming,
|
||||
boolean selected,
|
||||
LockMode lockMode,
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
return discriminatorMapping.generateFetch(
|
||||
fetchParent,
|
||||
fetchablePath,
|
||||
fetchTiming,
|
||||
selected,
|
||||
lockMode,
|
||||
resultVariable,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> DomainResult<T> createDomainResult(
|
||||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
return discriminatorMapping.createDomainResult(
|
||||
navigablePath,
|
||||
tableGroup,
|
||||
resultVariable,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingType getPartMappingType() {
|
||||
return discriminatorMapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaTypeDescriptor<?> getJavaTypeDescriptor() {
|
||||
return discriminatorMapping.getJavaTypeDescriptor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigableRole getNavigableRole() {
|
||||
return partRole;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityMappingType findContainingEntityMapping() {
|
||||
return discriminatorMapping.getModelPart().findContainingEntityMapping();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelPart findSubPart(String name, EntityMappingType treatTargetType) {
|
||||
if ( AnyDiscriminatorPart.ROLE_NAME.equals( name ) ) {
|
||||
return getDiscriminatorPart();
|
||||
}
|
||||
|
||||
if ( AnyKeyPart.ROLE_NAME.equals( name ) ) {
|
||||
return getKeyPart();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSubParts(Consumer<ModelPart> consumer, EntityMappingType treatTargetType) {
|
||||
consumer.accept( getDiscriminatorPart() );
|
||||
consumer.accept( getKeyPart() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberOfFetchables() {
|
||||
return 2;
|
||||
}
|
||||
}
|
|
@ -33,6 +33,7 @@ import org.hibernate.engine.spi.CascadeStyles;
|
|||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.mapping.Any;
|
||||
import org.hibernate.mapping.BasicValue;
|
||||
import org.hibernate.mapping.Collection;
|
||||
import org.hibernate.mapping.Component;
|
||||
|
@ -90,6 +91,7 @@ import org.hibernate.type.descriptor.java.ImmutableMutabilityPlan;
|
|||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.java.MutabilityPlan;
|
||||
import org.hibernate.type.descriptor.java.spi.JavaTypeDescriptorRegistry;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
|
@ -1261,6 +1263,24 @@ public class MappingModelCreationHelper {
|
|||
return (CollectionPart) mappingType.getEmbeddedValueMapping();
|
||||
}
|
||||
|
||||
if ( element instanceof Any ) {
|
||||
final Any anyBootMapping = (Any) element;
|
||||
|
||||
final SessionFactoryImplementor sessionFactory = creationProcess.getCreationContext().getSessionFactory();
|
||||
final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration();
|
||||
final JavaTypeDescriptorRegistry jtdRegistry = typeConfiguration.getJavaTypeDescriptorRegistry();
|
||||
final JavaTypeDescriptor<Object> baseJtd = jtdRegistry.getDescriptor(Object.class);
|
||||
|
||||
return new DiscriminatedCollectionPart(
|
||||
CollectionPart.Nature.ELEMENT,
|
||||
collectionDescriptor.getNavigableRole(),
|
||||
baseJtd,
|
||||
anyBootMapping,
|
||||
anyBootMapping.getType(),
|
||||
creationProcess
|
||||
);
|
||||
}
|
||||
|
||||
if ( element instanceof OneToMany || element instanceof ToOne ) {
|
||||
final EntityType elementEntityType = (EntityType) collectionDescriptor.getElementType();
|
||||
final EntityPersister associatedEntity = creationProcess.getEntityPersister( elementEntityType.getAssociatedEntityName() );
|
||||
|
|
|
@ -10,6 +10,7 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.metamodel.mapping.MappingModelCreationLogger;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.NonTransientException;
|
||||
|
|
|
@ -6290,9 +6290,7 @@ public abstract class AbstractEntityPersister
|
|||
return optimisticallyLocked;
|
||||
}
|
||||
},
|
||||
bootProperty.isLazy()
|
||||
? new FetchStrategy( FetchTiming.DELAYED, FetchStyle.SELECT )
|
||||
: new FetchStrategy( FetchTiming.IMMEDIATE, FetchStyle.SELECT ),
|
||||
bootProperty.isLazy() ? FetchTiming.DELAYED : FetchTiming.IMMEDIATE,
|
||||
propertyAccess,
|
||||
bootProperty,
|
||||
(AnyType) attrType,
|
||||
|
@ -6348,7 +6346,7 @@ public abstract class AbstractEntityPersister
|
|||
}
|
||||
|
||||
@Override
|
||||
public JavaTypeDescriptor getMappedJavaTypeDescriptor() {
|
||||
public JavaTypeDescriptor<?> getMappedJavaTypeDescriptor() {
|
||||
return javaTypeDescriptor;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
* 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.any.annotations;
|
||||
|
||||
import org.hibernate.LazyInitializationException;
|
||||
import org.hibernate.query.spi.QueryImplementor;
|
||||
|
||||
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.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
@DomainModel(
|
||||
annotatedPackageNames = "org.hibernate.orm.test.any.annotations",
|
||||
annotatedClasses = {
|
||||
StringProperty.class,
|
||||
IntegerProperty.class,
|
||||
LongProperty.class,
|
||||
PropertySet.class,
|
||||
LazyPropertySet.class,
|
||||
PropertyMap.class,
|
||||
PropertyList.class,
|
||||
CharProperty.class
|
||||
}
|
||||
)
|
||||
@SessionFactory
|
||||
public class AnyTest {
|
||||
@BeforeEach
|
||||
public void createTestData(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
{
|
||||
final PropertySet set1 = new PropertySet("string");
|
||||
final Property property = new StringProperty("name", "Alex");
|
||||
set1.setSomeProperty(property);
|
||||
set1.addGeneralProperty(property);
|
||||
session.save(set1);
|
||||
|
||||
final PropertySet set2 = new PropertySet("integer");
|
||||
final Property property2 = new IntegerProperty("age", 33);
|
||||
set2.setSomeProperty(property2);
|
||||
set2.addGeneralProperty(property2);
|
||||
session.save(set2);
|
||||
}
|
||||
|
||||
{
|
||||
final PropertyMap map = new PropertyMap("sample");
|
||||
map.getProperties().put("name", new StringProperty("name", "Alex"));
|
||||
map.getProperties().put("age", new IntegerProperty("age", 33));
|
||||
session.save(map);
|
||||
}
|
||||
|
||||
{
|
||||
final PropertyList list = new PropertyList("sample");
|
||||
final StringProperty stringProperty = new StringProperty("name", "Alex");
|
||||
final IntegerProperty integerProperty = new IntegerProperty("age", 33);
|
||||
final LongProperty longProperty = new LongProperty("distance", 121L);
|
||||
final CharProperty charProp = new CharProperty("Est", 'E');
|
||||
|
||||
list.setSomeProperty(longProperty);
|
||||
|
||||
list.addGeneralProperty(stringProperty);
|
||||
list.addGeneralProperty(integerProperty);
|
||||
list.addGeneralProperty(longProperty);
|
||||
list.addGeneralProperty(charProp);
|
||||
|
||||
session.save(list);
|
||||
}
|
||||
|
||||
{
|
||||
final LazyPropertySet set = new LazyPropertySet( "string" );
|
||||
final Property property = new StringProperty( "name", "Alex" );
|
||||
set.setSomeProperty( property );
|
||||
session.save( set );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void dropTestData(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "delete StringProperty" ).executeUpdate();
|
||||
session.createQuery( "delete IntegerProperty" ).executeUpdate();
|
||||
session.createQuery( "delete LongProperty" ).executeUpdate();
|
||||
session.createQuery( "delete CharProperty" ).executeUpdate();
|
||||
|
||||
session.createQuery( "delete PropertyList" ).executeUpdate();
|
||||
session.createQuery( "delete PropertyMap" ).executeUpdate();
|
||||
session.createQuery( "delete PropertySet" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultAnyAssociation(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
final QueryImplementor<PropertySet> query = session.createQuery("select s from PropertySet s where name = :name", PropertySet.class);
|
||||
|
||||
{
|
||||
final PropertySet result = query.setParameter( "name", "string" ).uniqueResult();
|
||||
assertNotNull( result );
|
||||
assertNotNull( result.getSomeProperty() );
|
||||
assertTrue( result.getSomeProperty() instanceof StringProperty );
|
||||
assertEquals( "Alex", result.getSomeProperty().asString() );
|
||||
assertNotNull( result.getGeneralProperties() );
|
||||
assertEquals( 1, result.getGeneralProperties().size() );
|
||||
assertEquals( "Alex", result.getGeneralProperties().get( 0 ).asString() );
|
||||
}
|
||||
|
||||
{
|
||||
final PropertySet result = query.setParameter( "name", "integer" ).uniqueResult();
|
||||
assertNotNull( result );
|
||||
assertNotNull( result.getSomeProperty() );
|
||||
assertTrue( result.getSomeProperty() instanceof IntegerProperty );
|
||||
assertEquals( "33", result.getSomeProperty().asString() );
|
||||
assertNotNull( result.getGeneralProperties() );
|
||||
assertEquals( 1, result.getGeneralProperties().size() );
|
||||
assertEquals( "33", result.getGeneralProperties().get( 0 ).asString() );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManyToAnyWithMap(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
final PropertyMap actualMap = session
|
||||
.createQuery( "SELECT m FROM PropertyMap m WHERE m.name = :name", PropertyMap.class )
|
||||
.setParameter( "name", "sample" )
|
||||
.uniqueResult();
|
||||
|
||||
assertNotNull( actualMap );
|
||||
assertNotNull( actualMap.getProperties() );
|
||||
|
||||
Property property = actualMap.getProperties().get( "name" );
|
||||
assertNotNull( property );
|
||||
assertTrue( property instanceof StringProperty );
|
||||
assertEquals( "Alex", property.asString() );
|
||||
|
||||
property = actualMap.getProperties().get( "age" );
|
||||
assertNotNull( property );
|
||||
assertTrue( property instanceof IntegerProperty );
|
||||
assertEquals( "33", property.asString() );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMetaDataUseWithManyToAny(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
//noinspection unchecked
|
||||
final PropertyList<Property> actualList = session
|
||||
.createQuery( "SELECT l FROM PropertyList l WHERE l.name = :name", PropertyList.class )
|
||||
.setParameter( "name", "sample" )
|
||||
.uniqueResult();
|
||||
|
||||
assertNotNull( actualList );
|
||||
assertNotNull( actualList.getGeneralProperties() );
|
||||
assertEquals( 4, actualList.getGeneralProperties().size() );
|
||||
|
||||
Property property = actualList.getSomeProperty();
|
||||
assertNotNull( property );
|
||||
assertTrue( property instanceof LongProperty );
|
||||
assertEquals( "121", property.asString() );
|
||||
|
||||
assertEquals( "Alex", actualList.getGeneralProperties().get( 0 )
|
||||
.asString() );
|
||||
assertEquals( "33", actualList.getGeneralProperties().get( 1 ).asString() );
|
||||
assertEquals( "121", actualList.getGeneralProperties().get( 2 ).asString() );
|
||||
assertEquals( "E", actualList.getGeneralProperties().get( 3 ).asString() );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFetchEager(SessionFactoryScope scope) {
|
||||
final PropertySet result = scope.fromTransaction(
|
||||
session -> {
|
||||
final PropertySet localResult = session.createQuery("select s from PropertySet s where name = :name", PropertySet.class)
|
||||
.setParameter("name", "string")
|
||||
.getSingleResult();
|
||||
assertNotNull( localResult );
|
||||
assertNotNull( localResult.getSomeProperty() );
|
||||
|
||||
return localResult;
|
||||
}
|
||||
);
|
||||
|
||||
assertTrue( result.getSomeProperty() instanceof StringProperty );
|
||||
assertEquals( "Alex", result.getSomeProperty().asString() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFetchLazy(SessionFactoryScope scope) {
|
||||
final LazyPropertySet result = scope.fromTransaction(
|
||||
session -> {
|
||||
final LazyPropertySet localResult = session.createQuery("select s from LazyPropertySet s where name = :name", LazyPropertySet.class)
|
||||
.setParameter("name", "string")
|
||||
.getSingleResult();
|
||||
assertNotNull( localResult );
|
||||
assertNotNull( localResult.getSomeProperty() );
|
||||
|
||||
return localResult;
|
||||
}
|
||||
);
|
||||
|
||||
try {
|
||||
result.getSomeProperty().asString();
|
||||
fail( "should not get the property string after session closed." );
|
||||
}
|
||||
catch (LazyInitializationException e) {
|
||||
// expected
|
||||
}
|
||||
catch (Exception e) {
|
||||
fail( "should not throw exception other than LazyInitializationException." );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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>.
|
||||
* 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.annotations.any;
|
||||
package org.hibernate.orm.test.any.annotations;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
|
@ -1,14 +1,10 @@
|
|||
/*
|
||||
* 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>.
|
||||
* 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.annotations.any;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
package org.hibernate.orm.test.any.annotations;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embeddable;
|
||||
|
@ -21,67 +17,63 @@ import javax.persistence.Table;
|
|||
import org.hibernate.annotations.Any;
|
||||
import org.hibernate.annotations.AnyMetaDef;
|
||||
import org.hibernate.annotations.MetaValue;
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
public class EmbeddedAnyTest extends BaseEntityManagerFunctionalTestCase {
|
||||
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;
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[]{ Foo.class, Bar1.class, Bar2.class };
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@DomainModel( annotatedClasses = { EmbeddedAnyTest.Foo.class, EmbeddedAnyTest.Bar1.class, EmbeddedAnyTest.Bar2.class } )
|
||||
@SessionFactory
|
||||
public class EmbeddedAnyTest {
|
||||
@BeforeEach
|
||||
public void createTestData(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
final Foo foo1 = new Foo();
|
||||
foo1.setId( 1 );
|
||||
|
||||
final Bar1 bar1 = new Bar1();
|
||||
bar1.setId( 1 );
|
||||
bar1.setBar1( "bar 1" );
|
||||
bar1.setBarType( "1" );
|
||||
|
||||
final FooEmbeddable foo1Embedded = new FooEmbeddable();
|
||||
foo1Embedded.setBar( bar1 );
|
||||
|
||||
foo1.setFooEmbedded( foo1Embedded );
|
||||
|
||||
session.persist( bar1 );
|
||||
session.persist( foo1 );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void dropTestData(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "delete Bar2" ).executeUpdate();
|
||||
session.createQuery( "delete Bar1" ).executeUpdate();
|
||||
session.createQuery( "delete Foo" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmbeddedAny() {
|
||||
doInJPA( this::entityManagerFactory, em -> {
|
||||
Foo foo1 = new Foo();
|
||||
foo1.setId( 1 );
|
||||
|
||||
Bar1 bar1 = new Bar1();
|
||||
bar1.setId( 1 );
|
||||
bar1.setBar1( "bar 1" );
|
||||
bar1.setBarType( "1" );
|
||||
|
||||
FooEmbeddable foo1Embedded = new FooEmbeddable();
|
||||
foo1Embedded.setBar( bar1 );
|
||||
|
||||
foo1.setFooEmbedded( foo1Embedded );
|
||||
|
||||
em.persist( bar1 );
|
||||
em.persist( foo1 );
|
||||
} );
|
||||
|
||||
doInJPA( this::entityManagerFactory, em -> {
|
||||
Foo foo2 = new Foo();
|
||||
foo2.setId( 2 );
|
||||
|
||||
Bar2 bar2 = new Bar2();
|
||||
bar2.setId( 2 );
|
||||
bar2.setBar2( "bar 2" );
|
||||
bar2.setBarType( "2" );
|
||||
|
||||
FooEmbeddable foo2Embedded = new FooEmbeddable();
|
||||
foo2Embedded.setBar( bar2 );
|
||||
|
||||
foo2.setFooEmbedded( foo2Embedded );
|
||||
|
||||
em.persist( bar2 );
|
||||
em.persist( foo2 );
|
||||
} );
|
||||
|
||||
doInJPA( this::entityManagerFactory, em -> {
|
||||
Foo foo1 = em.find( Foo.class, 1 );
|
||||
|
||||
assertTrue( foo1.getFooEmbedded().getBar() instanceof Bar1 );
|
||||
assertEquals( "bar 1", ( (Bar1) foo1.getFooEmbedded().getBar() ).getBar1() );
|
||||
} );
|
||||
|
||||
doInJPA( this::entityManagerFactory, em -> {
|
||||
Foo foo2 = em.find( Foo.class, 2 );
|
||||
|
||||
assertTrue( foo2.getFooEmbedded().getBar() instanceof Bar2 );
|
||||
assertEquals( "bar 2", ( (Bar2) foo2.getFooEmbedded().getBar() ).getBar2() );
|
||||
} );
|
||||
public void testEmbeddedAny(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
final Foo foo = session.find( Foo.class, 1 );
|
||||
assertTrue( foo.getFooEmbedded().getBar() instanceof Bar1 );
|
||||
assertEquals( "bar 1", ( (Bar1) foo.getFooEmbedded().getBar() ).getBar1() );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Entity(name = "Foo")
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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>.
|
||||
* 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.annotations.any;
|
||||
package org.hibernate.orm.test.any.annotations;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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>.
|
||||
* 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.annotations.any;
|
||||
package org.hibernate.orm.test.any.annotations;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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>.
|
||||
* 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.annotations.any;
|
||||
package org.hibernate.orm.test.any.annotations;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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>.
|
||||
* 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.annotations.any;
|
||||
package org.hibernate.orm.test.any.annotations;
|
||||
|
||||
|
||||
public interface Property {
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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>.
|
||||
* 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.annotations.any;
|
||||
package org.hibernate.orm.test.any.annotations;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.persistence.Column;
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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>.
|
||||
* 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.annotations.any;
|
||||
package org.hibernate.orm.test.any.annotations;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.persistence.Column;
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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>.
|
||||
* 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.annotations.any;
|
||||
package org.hibernate.orm.test.any.annotations;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.persistence.Column;
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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>.
|
||||
* 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.annotations.any;
|
||||
package org.hibernate.orm.test.any.annotations;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
|
@ -1,8 +1,8 @@
|
|||
/*
|
||||
* 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>.
|
||||
* 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
|
||||
*/
|
||||
|
||||
// $Id$
|
||||
|
@ -14,7 +14,7 @@
|
|||
@MetaValue(value = "L", targetEntity = LongProperty.class)
|
||||
})
|
||||
|
||||
package org.hibernate.test.annotations.any;
|
||||
package org.hibernate.orm.test.any.annotations;
|
||||
|
||||
import org.hibernate.annotations.AnyMetaDef;
|
||||
import org.hibernate.annotations.MetaValue;
|
|
@ -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.orm.test.any;
|
||||
package org.hibernate.orm.test.any.hbm;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
|
@ -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.orm.test.any;
|
||||
package org.hibernate.orm.test.any.hbm;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||
|
@ -12,10 +12,10 @@ import org.hibernate.stat.spi.StatisticsImplementor;
|
|||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.hibernate.test.annotations.any.IntegerProperty;
|
||||
import org.hibernate.test.annotations.any.Property;
|
||||
import org.hibernate.test.annotations.any.PropertySet;
|
||||
import org.hibernate.test.annotations.any.StringProperty;
|
||||
import org.hibernate.orm.test.any.annotations.IntegerProperty;
|
||||
import org.hibernate.orm.test.any.annotations.Property;
|
||||
import org.hibernate.orm.test.any.annotations.PropertySet;
|
||||
import org.hibernate.orm.test.any.annotations.StringProperty;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -28,7 +28,7 @@ import static org.junit.Assert.assertTrue;
|
|||
|
||||
@DomainModel(
|
||||
annotatedClasses = { StringProperty.class, IntegerProperty.class },
|
||||
xmlMappings = "org/hibernate/orm/test/any/AnyTestEagerPropertySet.hbm.xml"
|
||||
xmlMappings = "org/hibernate/orm/test/any/hbm/AnyTestEagerPropertySet.hbm.xml"
|
||||
)
|
||||
@SessionFactory( generateStatistics = true )
|
||||
public class AnyEagerHbmTest {
|
|
@ -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.orm.test.any;
|
||||
package org.hibernate.orm.test.any.hbm;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||
|
@ -12,10 +12,10 @@ import org.hibernate.stat.spi.StatisticsImplementor;
|
|||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.hibernate.test.annotations.any.IntegerProperty;
|
||||
import org.hibernate.test.annotations.any.LazyPropertySet;
|
||||
import org.hibernate.test.annotations.any.Property;
|
||||
import org.hibernate.test.annotations.any.StringProperty;
|
||||
import org.hibernate.orm.test.any.annotations.IntegerProperty;
|
||||
import org.hibernate.orm.test.any.annotations.LazyPropertySet;
|
||||
import org.hibernate.orm.test.any.annotations.Property;
|
||||
import org.hibernate.orm.test.any.annotations.StringProperty;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -28,7 +28,7 @@ import static org.junit.Assert.assertTrue;
|
|||
|
||||
@DomainModel(
|
||||
annotatedClasses = { StringProperty.class, IntegerProperty.class },
|
||||
xmlMappings = "org/hibernate/orm/test/any/AnyTestLazyPropertySet.hbm.xml"
|
||||
xmlMappings = "org/hibernate/orm/test/any/hbm/AnyTestLazyPropertySet.hbm.xml"
|
||||
)
|
||||
@SessionFactory( generateStatistics = true )
|
||||
public class AnyLazyHbmTest {
|
|
@ -9,7 +9,7 @@
|
|||
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
||||
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
|
||||
|
||||
<hibernate-mapping package="org.hibernate.test.annotations.any">
|
||||
<hibernate-mapping package="org.hibernate.orm.test.any.annotations">
|
||||
<class name="PropertySet" table="eager_property_set">
|
||||
<id name="id" type="java.lang.Integer">
|
||||
<generator class="increment"/>
|
|
@ -2,14 +2,14 @@
|
|||
<!--
|
||||
~ 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>.
|
||||
~ 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
|
||||
-->
|
||||
<!DOCTYPE hibernate-mapping PUBLIC
|
||||
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
||||
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
|
||||
|
||||
<hibernate-mapping package="org.hibernate.test.annotations.any">
|
||||
<hibernate-mapping package="org.hibernate.orm.test.any.annotations">
|
||||
<class name="LazyPropertySet" table="lazy_property_set">
|
||||
<id name="id" type="java.lang.Integer">
|
||||
<generator class="increment"/>
|
|
@ -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.orm.test.any;
|
||||
package org.hibernate.orm.test.any.hbm;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.query.SemanticException;
|
||||
|
@ -27,7 +27,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||
*/
|
||||
@TestForIssue(jiraKey = "HHH-1663")
|
||||
@ServiceRegistry( settings = @ServiceRegistry.Setting( name = AvailableSettings.USE_SECOND_LEVEL_CACHE, value = "false" ) )
|
||||
@DomainModel( xmlMappings = "org/hibernate/orm/test/any/Person.hbm.xml" )
|
||||
@DomainModel( xmlMappings = "org/hibernate/orm/test/any/hbm/Person.hbm.xml" )
|
||||
@SessionFactory
|
||||
public class AnyTypeTest {
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
||||
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
|
||||
|
||||
<hibernate-mapping package="org.hibernate.orm.test.any">
|
||||
<hibernate-mapping package="org.hibernate.orm.test.any.hbm">
|
||||
|
||||
<class name="Person" table="T_ANY_PERSON">
|
||||
<id name="id" column="ID_">
|
|
@ -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.orm.test.any;
|
||||
package org.hibernate.orm.test.any.hbm;
|
||||
|
||||
|
||||
/**
|
|
@ -1,240 +0,0 @@
|
|||
/*
|
||||
* 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.test.annotations.any;
|
||||
|
||||
import org.hibernate.LazyInitializationException;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.query.Query;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public class AnyTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected boolean isCleanupTestDataRequired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultAnyAssociation() {
|
||||
Session s = openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
|
||||
PropertySet set1 = new PropertySet( "string" );
|
||||
Property property = new StringProperty( "name", "Alex" );
|
||||
set1.setSomeProperty( property );
|
||||
set1.addGeneralProperty( property );
|
||||
s.save( set1 );
|
||||
|
||||
PropertySet set2 = new PropertySet( "integer" );
|
||||
property = new IntegerProperty( "age", 33 );
|
||||
set2.setSomeProperty( property );
|
||||
set2.addGeneralProperty( property );
|
||||
s.save( set2 );
|
||||
|
||||
s.flush();
|
||||
s.clear();
|
||||
|
||||
Query q = s
|
||||
.createQuery( "select s from PropertySet s where name = :name" );
|
||||
q.setParameter( "name", "string" );
|
||||
PropertySet result = (PropertySet) q.uniqueResult();
|
||||
|
||||
assertNotNull( result );
|
||||
assertNotNull( result.getSomeProperty() );
|
||||
assertTrue( result.getSomeProperty() instanceof StringProperty );
|
||||
assertEquals( "Alex", result.getSomeProperty().asString() );
|
||||
assertNotNull( result.getGeneralProperties() );
|
||||
assertEquals( 1, result.getGeneralProperties().size() );
|
||||
assertEquals( "Alex", result.getGeneralProperties().get( 0 ).asString() );
|
||||
|
||||
q.setParameter( "name", "integer" );
|
||||
result = (PropertySet) q.uniqueResult();
|
||||
assertNotNull( result );
|
||||
assertNotNull( result.getSomeProperty() );
|
||||
assertTrue( result.getSomeProperty() instanceof IntegerProperty );
|
||||
assertEquals( "33", result.getSomeProperty().asString() );
|
||||
assertNotNull( result.getGeneralProperties() );
|
||||
assertEquals( 1, result.getGeneralProperties().size() );
|
||||
assertEquals( "33", result.getGeneralProperties().get( 0 ).asString() );
|
||||
|
||||
t.rollback();
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManyToAnyWithMap() throws Exception {
|
||||
|
||||
Session s = openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
|
||||
PropertyMap map = new PropertyMap( "sample" );
|
||||
map.getProperties().put( "name", new StringProperty( "name", "Alex" ) );
|
||||
map.getProperties().put( "age", new IntegerProperty( "age", 33 ) );
|
||||
|
||||
s.save( map );
|
||||
|
||||
s.flush();
|
||||
s.clear();
|
||||
|
||||
Query q = s
|
||||
.createQuery( "SELECT map FROM PropertyMap map WHERE map.name = :name" );
|
||||
q.setParameter( "name", "sample" );
|
||||
PropertyMap actualMap = (PropertyMap) q.uniqueResult();
|
||||
|
||||
assertNotNull( actualMap );
|
||||
assertNotNull( actualMap.getProperties() );
|
||||
|
||||
Property property = actualMap.getProperties().get( "name" );
|
||||
assertNotNull( property );
|
||||
assertTrue( property instanceof StringProperty );
|
||||
assertEquals( "Alex", property.asString() );
|
||||
|
||||
property = actualMap.getProperties().get( "age" );
|
||||
assertNotNull( property );
|
||||
assertTrue( property instanceof IntegerProperty );
|
||||
assertEquals( "33", property.asString() );
|
||||
|
||||
t.rollback();
|
||||
s.close();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMetaDataUseWithManyToAny() {
|
||||
Session s = openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
|
||||
PropertyList list = new PropertyList( "sample" );
|
||||
StringProperty stringProperty = new StringProperty( "name", "Alex" );
|
||||
IntegerProperty integerProperty = new IntegerProperty( "age", 33 );
|
||||
LongProperty longProperty = new LongProperty( "distance", 121L );
|
||||
CharProperty charProp = new CharProperty( "Est", 'E' );
|
||||
|
||||
list.setSomeProperty( longProperty );
|
||||
|
||||
list.addGeneralProperty( stringProperty );
|
||||
list.addGeneralProperty( integerProperty );
|
||||
list.addGeneralProperty( longProperty );
|
||||
list.addGeneralProperty( charProp );
|
||||
|
||||
s.save( list );
|
||||
|
||||
s.flush();
|
||||
s.clear();
|
||||
|
||||
Query q = s
|
||||
.createQuery( "SELECT list FROM PropertyList list WHERE list.name = :name" );
|
||||
q.setParameter( "name", "sample" );
|
||||
PropertyList<Property> actualList = (PropertyList<Property>) q
|
||||
.uniqueResult();
|
||||
|
||||
assertNotNull( actualList );
|
||||
assertNotNull( actualList.getGeneralProperties() );
|
||||
assertEquals( 4, actualList.getGeneralProperties().size() );
|
||||
|
||||
Property property = actualList.getSomeProperty();
|
||||
assertNotNull( property );
|
||||
assertTrue( property instanceof LongProperty );
|
||||
assertEquals( "121", property.asString() );
|
||||
|
||||
assertEquals( "Alex", actualList.getGeneralProperties().get( 0 )
|
||||
.asString() );
|
||||
assertEquals( "33", actualList.getGeneralProperties().get( 1 ).asString() );
|
||||
assertEquals( "121", actualList.getGeneralProperties().get( 2 ).asString() );
|
||||
assertEquals( "E", actualList.getGeneralProperties().get( 3 ).asString() );
|
||||
|
||||
t.rollback();
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFetchEager() {
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
PropertySet set = new PropertySet( "string" );
|
||||
Property property = new StringProperty( "name", "Alex" );
|
||||
set.setSomeProperty( property );
|
||||
s.save( set );
|
||||
} );
|
||||
|
||||
PropertySet result = doInHibernate( this::sessionFactory, s -> {
|
||||
return s.createQuery( "select s from PropertySet s where name = :name", PropertySet.class )
|
||||
.setParameter( "name", "string" )
|
||||
.getSingleResult();
|
||||
} );
|
||||
|
||||
assertNotNull( result );
|
||||
assertNotNull( result.getSomeProperty() );
|
||||
assertTrue( result.getSomeProperty() instanceof StringProperty );
|
||||
assertEquals( "Alex", result.getSomeProperty().asString() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFetchLazy() {
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
LazyPropertySet set = new LazyPropertySet( "string" );
|
||||
Property property = new StringProperty( "name", "Alex" );
|
||||
set.setSomeProperty( property );
|
||||
s.save( set );
|
||||
} );
|
||||
|
||||
LazyPropertySet result = doInHibernate( this::sessionFactory, s -> {
|
||||
return s.createQuery( "select s from LazyPropertySet s where name = :name", LazyPropertySet.class )
|
||||
.setParameter( "name", "string" )
|
||||
.getSingleResult();
|
||||
} );
|
||||
|
||||
assertNotNull( result );
|
||||
assertNotNull( result.getSomeProperty() );
|
||||
|
||||
try {
|
||||
result.getSomeProperty().asString();
|
||||
fail( "should not get the property string after session closed." );
|
||||
}
|
||||
catch (LazyInitializationException e) {
|
||||
// expected
|
||||
}
|
||||
catch (Exception e) {
|
||||
fail( "should not throw exception other than LazyInitializationException." );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class[] getAnnotatedClasses() {
|
||||
return new Class[] {
|
||||
StringProperty.class,
|
||||
IntegerProperty.class,
|
||||
LongProperty.class,
|
||||
PropertySet.class,
|
||||
LazyPropertySet.class,
|
||||
PropertyMap.class,
|
||||
PropertyList.class,
|
||||
CharProperty.class
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String[] getAnnotatedPackages() {
|
||||
return new String[] {
|
||||
"org.hibernate.test.annotations.any"
|
||||
};
|
||||
}
|
||||
|
||||
// Simply having this orm.xml file in the classpath reproduces HHH-4261.
|
||||
@Override
|
||||
protected String[] getOrmXmlFiles() {
|
||||
return new String[] { "org/hibernate/test/annotations/any/orm.xml" };
|
||||
}
|
||||
}
|
|
@ -2,8 +2,8 @@
|
|||
<!--
|
||||
~ 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>.
|
||||
~ 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
|
||||
-->
|
||||
<!DOCTYPE hibernate-mapping PUBLIC
|
||||
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
||||
|
|
|
@ -96,6 +96,7 @@ public @interface DomainModel {
|
|||
Class<? extends DomainModelDescriptor>[] modelDescriptorClasses() default {};
|
||||
Class[] annotatedClasses() default {};
|
||||
String[] annotatedClassNames() default {};
|
||||
String[] annotatedPackageNames() default {};
|
||||
String[] xmlMappings() default {};
|
||||
ExtraQueryImport[] extraQueryImports() default {};
|
||||
Class<?>[] extraQueryImportClasses() default {};
|
||||
|
|
|
@ -16,6 +16,7 @@ import org.hibernate.boot.Metadata;
|
|||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistry;
|
||||
import org.hibernate.boot.spi.MetadataImplementor;
|
||||
import org.hibernate.internal.util.JavaHelper;
|
||||
import org.hibernate.mapping.Collection;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
|
@ -88,6 +89,10 @@ public class DomainModelExtension
|
|||
|
||||
final MetadataSources metadataSources = new MetadataSources( serviceRegistry );
|
||||
|
||||
for ( String annotatedPackageName : domainModelAnnotation.annotatedPackageNames() ) {
|
||||
metadataSources.addPackage( JavaHelper.getPackageFor( annotatedPackageName ) );
|
||||
}
|
||||
|
||||
for ( StandardDomainModel standardDomainModel : domainModelAnnotation.standardModels() ) {
|
||||
standardDomainModel.getDescriptor().applyDomainModel( metadataSources );
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue