initial discriminator hierarchy support
This commit is contained in:
parent
3c65085123
commit
f5c3ae181c
|
@ -20,13 +20,5 @@ public interface AttributeMapping extends ModelPart, ValueMapping {
|
||||||
|
|
||||||
ManagedMappingType getDeclaringType();
|
ManagedMappingType getDeclaringType();
|
||||||
|
|
||||||
default boolean isDeclaredOnTypeOrSuperType(ManagedMappingType targetType) {
|
|
||||||
if ( getDeclaringType() instanceof EntityMappingType ) {
|
|
||||||
return ( (EntityMappingType) getDeclaringType() ).isTypeOrSuperType( targetType );
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyAccess getPropertyAccess();
|
PropertyAccess getPropertyAccess();
|
||||||
}
|
}
|
||||||
|
|
|
@ -278,8 +278,8 @@ public class EmbeddableMappingType implements ManagedMappingType {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getNumberOfDeclaredAttributeMappings() {
|
public AttributeMapping findAttributeMapping(String name) {
|
||||||
return getNumberOfAttributeMappings();
|
return attributeMappings.get( name );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -292,11 +292,6 @@ public class EmbeddableMappingType implements ManagedMappingType {
|
||||||
attributeMappings.values().forEach( action );
|
attributeMappings.values().forEach( action );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isTypeOrSuperType(ManagedMappingType targetType) {
|
|
||||||
return targetType == null || targetType == this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ModelPart findSubPart(String name, EntityMappingType treatTargetType) {
|
public ModelPart findSubPart(String name, EntityMappingType treatTargetType) {
|
||||||
return attributeMappings.get( name );
|
return attributeMappings.get( name );
|
||||||
|
|
|
@ -6,9 +6,17 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.metamodel.mapping;
|
package org.hibernate.metamodel.mapping;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import org.hibernate.NotYetImplementedFor6Exception;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
import org.hibernate.sql.results.spi.DomainResultAssembler;
|
||||||
|
import org.hibernate.sql.results.spi.Fetchable;
|
||||||
|
import org.hibernate.sql.results.spi.RowProcessingState;
|
||||||
|
|
||||||
|
import static org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer.UNFETCHED_PROPERTY;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* todo (6.0) : make this implement RootTableGroupProducer, etc instead of EntityPersister?
|
* todo (6.0) : make this implement RootTableGroupProducer, etc instead of EntityPersister?
|
||||||
|
@ -29,6 +37,53 @@ public interface EntityMappingType extends ManagedMappingType {
|
||||||
return getEntityPersister().getEntityName();
|
return getEntityPersister().getEntityName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
// Inheritance
|
||||||
|
|
||||||
|
default AttributeMapping findDeclaredAttributeMapping(String name) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number of attributes defined on this class - do not access attributes defined on the super
|
||||||
|
*/
|
||||||
|
default int getNumberOfDeclaredAttributeMappings() {
|
||||||
|
return getDeclaredAttributeMappings().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get access to the attributes defined on this class - do not access attributes defined on the super
|
||||||
|
*/
|
||||||
|
default Collection<AttributeMapping> getDeclaredAttributeMappings() {
|
||||||
|
throw new NotYetImplementedFor6Exception( getClass() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visit attributes defined on this class - do not visit attributes defined on the super
|
||||||
|
*/
|
||||||
|
default void visitDeclaredAttributeMappings(Consumer<AttributeMapping> action) {
|
||||||
|
throw new NotYetImplementedFor6Exception( getClass() );
|
||||||
|
}
|
||||||
|
|
||||||
|
default EntityMappingType getSuperMappingType() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
default boolean isTypeOrSuperType(EntityMappingType targetType) {
|
||||||
|
return targetType == this;
|
||||||
|
}
|
||||||
|
|
||||||
|
default boolean isTypeOrSuperType(ManagedMappingType targetType) {
|
||||||
|
if ( targetType instanceof EntityMappingType ) {
|
||||||
|
return isTypeOrSuperType( (EntityMappingType) targetType );
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
// Special model parts - identifier, discriminator, etc
|
||||||
|
|
||||||
EntityIdentifierMapping getIdentifierMapping();
|
EntityIdentifierMapping getIdentifierMapping();
|
||||||
|
|
||||||
EntityVersionMapping getVersionMapping();
|
EntityVersionMapping getVersionMapping();
|
||||||
|
@ -39,19 +94,6 @@ public interface EntityMappingType extends ManagedMappingType {
|
||||||
|
|
||||||
NaturalIdMapping getNaturalIdMapping();
|
NaturalIdMapping getNaturalIdMapping();
|
||||||
|
|
||||||
@Override
|
|
||||||
default boolean isTypeOrSuperType(ManagedMappingType targetType) {
|
|
||||||
if ( targetType instanceof EntityMappingType ) {
|
|
||||||
return isTypeOrSuperType( (EntityMappingType) targetType );
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
default boolean isTypeOrSuperType(EntityMappingType targetType) {
|
|
||||||
return targetType == this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visit the mappings, but limited to just attributes defined
|
* Visit the mappings, but limited to just attributes defined
|
||||||
* in the targetType or its super-type(s) if any.
|
* in the targetType or its super-type(s) if any.
|
||||||
|
@ -80,35 +122,41 @@ public interface EntityMappingType extends ManagedMappingType {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default void visitAttributeMappings(Consumer<AttributeMapping> action) {
|
default void visitAttributeMappings(Consumer<AttributeMapping> action) {
|
||||||
visitAttributeMappings( action, null );
|
getAttributeMappings().forEach( action );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Customer <- DomesticCustomer <- OtherCustomer
|
||||||
* Visit the mappings, but limited to just attributes defined
|
|
||||||
* in the targetType or its super-type(s) if any.
|
default Object[] extractConcreteTypeStateValues(
|
||||||
*
|
Map<AttributeMapping, DomainResultAssembler> assemblerMapping,
|
||||||
* @apiNote Passing {@code null} indicates that subclasses should be included. This
|
RowProcessingState rowProcessingState) {
|
||||||
* matches legacy non-TREAT behavior and meets the need for EntityGraph processing
|
// todo (6.0) : getNumberOfAttributeMappings() needs to be fixed for this to work - bad walking of hierarchy
|
||||||
*/
|
final Object[] values = new Object[ getNumberOfAttributeMappings() ];
|
||||||
default void visitStateArrayContributors(Consumer<StateArrayContributorMapping> mappingConsumer, EntityMappingType targetType) {
|
|
||||||
visitAttributeMappings(
|
visitFetchables(
|
||||||
modelPart -> {
|
new Consumer<Fetchable>() {
|
||||||
if ( modelPart instanceof StateArrayContributorMapping ) {
|
private int index;
|
||||||
if ( targetType == null
|
|
||||||
|| ( (StateArrayContributorMapping) modelPart ).isDeclaredOnTypeOrSuperType( targetType ) ) {
|
@Override
|
||||||
mappingConsumer.accept( ( (StateArrayContributorMapping) modelPart ) );
|
public void accept(Fetchable fetchable) {
|
||||||
}
|
assert fetchable instanceof StateArrayContributorMapping;
|
||||||
|
|
||||||
|
final DomainResultAssembler assembler = assemblerMapping.get( fetchable );
|
||||||
|
final Object value = assembler == null ? UNFETCHED_PROPERTY : assembler.assemble( rowProcessingState );
|
||||||
|
|
||||||
|
values[index++] = value;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
targetType
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default void visitStateArrayContributors(Consumer<StateArrayContributorMapping> mappingConsumer) {
|
default void visitStateArrayContributors(Consumer<StateArrayContributorMapping> mappingConsumer) {
|
||||||
visitStateArrayContributors( mappingConsumer, null );
|
visitAttributeMappings(
|
||||||
|
attributeMapping -> mappingConsumer.accept( (StateArrayContributorMapping) attributeMapping )
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo (6.0) : not sure we actually need this distinction at the mapping model level...
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.metamodel.mapping;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import org.hibernate.NotYetImplementedFor6Exception;
|
||||||
import org.hibernate.sql.results.spi.FetchableContainer;
|
import org.hibernate.sql.results.spi.FetchableContainer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -18,14 +19,23 @@ import org.hibernate.sql.results.spi.FetchableContainer;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface ManagedMappingType extends MappingType, FetchableContainer {
|
public interface ManagedMappingType extends MappingType, FetchableContainer {
|
||||||
int getNumberOfAttributeMappings();
|
|
||||||
int getNumberOfDeclaredAttributeMappings();
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number of attributes defined on this class and any supers
|
||||||
|
*/
|
||||||
|
int getNumberOfAttributeMappings();
|
||||||
|
|
||||||
|
default AttributeMapping findAttributeMapping(String name) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get access to the attributes defined on this class and any supers
|
||||||
|
*/
|
||||||
Collection<AttributeMapping> getAttributeMappings();
|
Collection<AttributeMapping> getAttributeMappings();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @todo (6.0) : consider dropping this in favor of a form passing the ManagedMappingType
|
* Visit attributes defined on this class and any supers
|
||||||
* which indicates the type to limit the attribute search to (the type and its super-type)
|
|
||||||
*/
|
*/
|
||||||
void visitAttributeMappings(Consumer<AttributeMapping> action);
|
void visitAttributeMappings(Consumer<AttributeMapping> action);
|
||||||
|
|
||||||
|
@ -42,6 +52,4 @@ public interface ManagedMappingType extends MappingType, FetchableContainer {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isTypeOrSuperType(ManagedMappingType targetType);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,8 @@ import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||||
import org.hibernate.sql.results.internal.domain.basic.BasicFetch;
|
import org.hibernate.sql.results.internal.domain.basic.BasicFetch;
|
||||||
|
import org.hibernate.sql.results.internal.domain.basic.BasicResult;
|
||||||
|
import org.hibernate.sql.results.spi.DomainResult;
|
||||||
import org.hibernate.sql.results.spi.DomainResultCreationState;
|
import org.hibernate.sql.results.spi.DomainResultCreationState;
|
||||||
import org.hibernate.sql.results.spi.Fetch;
|
import org.hibernate.sql.results.spi.Fetch;
|
||||||
import org.hibernate.sql.results.spi.FetchParent;
|
import org.hibernate.sql.results.spi.FetchParent;
|
||||||
|
@ -75,6 +77,31 @@ public class EntityDiscriminatorMappingImpl implements EntityDiscriminatorMappin
|
||||||
return FetchStrategy.IMMEDIATE_JOIN;
|
return FetchStrategy.IMMEDIATE_JOIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> DomainResult<T> createDomainResult(
|
||||||
|
NavigablePath navigablePath,
|
||||||
|
TableGroup tableGroup,
|
||||||
|
String resultVariable,
|
||||||
|
DomainResultCreationState creationState) {
|
||||||
|
final SqlSelection sqlSelection = resolveSqlSelection( tableGroup, creationState );
|
||||||
|
|
||||||
|
//noinspection unchecked
|
||||||
|
return new BasicResult(
|
||||||
|
sqlSelection.getValuesArrayPosition(),
|
||||||
|
resultVariable,
|
||||||
|
getJavaTypeDescriptor(),
|
||||||
|
navigablePath
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void applySqlSelections(
|
||||||
|
NavigablePath navigablePath,
|
||||||
|
TableGroup tableGroup,
|
||||||
|
DomainResultCreationState creationState) {
|
||||||
|
resolveSqlSelection( tableGroup, creationState );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Fetch generateFetch(
|
public Fetch generateFetch(
|
||||||
FetchParent fetchParent,
|
FetchParent fetchParent,
|
||||||
|
@ -104,6 +131,7 @@ public class EntityDiscriminatorMappingImpl implements EntityDiscriminatorMappin
|
||||||
creationState
|
creationState
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SqlSelection resolveSqlSelection(TableGroup tableGroup, DomainResultCreationState creationState) {
|
private SqlSelection resolveSqlSelection(TableGroup tableGroup, DomainResultCreationState creationState) {
|
||||||
final SqlExpressionResolver expressionResolver = creationState.getSqlAstCreationState().getSqlExpressionResolver();
|
final SqlExpressionResolver expressionResolver = creationState.getSqlAstCreationState().getSqlExpressionResolver();
|
||||||
|
|
||||||
|
|
|
@ -5294,15 +5294,19 @@ public abstract class AbstractEntityPersister
|
||||||
accessOptimizer.setPropertyValues( object, values );
|
accessOptimizer.setPropertyValues( object, values );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int i = 0;
|
visitFetchables(
|
||||||
for ( Map.Entry<String, AttributeMapping> entries : declaredAttributeMappings.entrySet() ) {
|
fetchable -> {
|
||||||
AttributeMapping attributeMapping = entries.getValue();
|
final AttributeMapping attribute = (AttributeMapping) fetchable;
|
||||||
final Setter setter = attributeMapping
|
final int stateArrayPosition = ( (StateArrayContributorMapping) attribute ).getStateArrayPosition();
|
||||||
.getPropertyAccess()
|
final Object value = values[stateArrayPosition];
|
||||||
.getSetter();
|
if ( value != UNFETCHED_PROPERTY ) {
|
||||||
setter.set( object, values[i], getFactory() );
|
final Setter setter = attribute.getPropertyAccess().getSetter();
|
||||||
i++;
|
setter.set( object, value, getFactory() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
null
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5320,21 +5324,13 @@ public abstract class AbstractEntityPersister
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
final Object[] values = new Object[ getNumberOfAttributeMappings() ];
|
final Object[] values = new Object[ getNumberOfAttributeMappings() ];
|
||||||
final AtomicInteger index = new AtomicInteger( 0 );
|
for ( int i = 0; i < attributeMappings.size(); i++ ) {
|
||||||
|
values[ i ] = attributeMappings.get( i ).getAttributeMetadataAccess()
|
||||||
//noinspection Convert2Lambda
|
.resolveAttributeMetadata( this )
|
||||||
visitAttributeMappings(
|
|
||||||
new Consumer<AttributeMapping>() {
|
|
||||||
@Override
|
|
||||||
public void accept(AttributeMapping mapping) {
|
|
||||||
values[ index.getAndIncrement() ] = mapping.getAttributeMetadataAccess()
|
|
||||||
.resolveAttributeMetadata( AbstractEntityPersister.this )
|
|
||||||
.getPropertyAccess()
|
.getPropertyAccess()
|
||||||
.getGetter()
|
.getGetter()
|
||||||
.get( object );
|
.get( object );
|
||||||
}
|
}
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
@ -5441,16 +5437,15 @@ public abstract class AbstractEntityPersister
|
||||||
return accessOptimizer.getPropertyValues( entity );
|
return accessOptimizer.getPropertyValues( entity );
|
||||||
}
|
}
|
||||||
|
|
||||||
final Object[] result = new Object[declaredAttributeMappings.size()];
|
final Collection<AttributeMapping> attributeMappings = getAttributeMappings();
|
||||||
int i = 0;
|
|
||||||
for ( Map.Entry<String, AttributeMapping> entries : declaredAttributeMappings.entrySet() ) {
|
final Object[] result = new Object[this.attributeMappings.size()];
|
||||||
AttributeMapping attributeMapping = entries.getValue();
|
for ( int i = 0; i < this.attributeMappings.size(); i++ ) {
|
||||||
result[i] = attributeMapping.getPropertyAccess().getGetter().getForInsert(
|
result[i] = this.attributeMappings.get( i ).getPropertyAccess().getGetter().getForInsert(
|
||||||
entity,
|
entity,
|
||||||
mergeMap,
|
mergeMap,
|
||||||
session
|
session
|
||||||
);
|
);
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -6059,31 +6054,35 @@ public abstract class AbstractEntityPersister
|
||||||
private EntityDiscriminatorMapping discriminatorMapping;
|
private EntityDiscriminatorMapping discriminatorMapping;
|
||||||
|
|
||||||
private SortedMap<String, AttributeMapping> declaredAttributeMappings = new TreeMap<>();
|
private SortedMap<String, AttributeMapping> declaredAttributeMappings = new TreeMap<>();
|
||||||
private Collection<AttributeMapping> attributeMappings;
|
private List<AttributeMapping> attributeMappings;
|
||||||
|
|
||||||
private ReflectionOptimizer.AccessOptimizer accessOptimizer;
|
private ReflectionOptimizer.AccessOptimizer accessOptimizer;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitAttributeMappings(Consumer<AttributeMapping> action) {
|
||||||
|
attributeMappings.forEach( action );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void prepareMappingModel(MappingModelCreationProcess creationProcess) {
|
public void prepareMappingModel(MappingModelCreationProcess creationProcess) {
|
||||||
if ( identifierMapping != null ) {
|
if ( identifierMapping != null ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final RuntimeModelCreationContext creationContext = creationProcess.getCreationContext();
|
if ( superMappingType != null ) {
|
||||||
|
( (InFlightEntityMappingType) superMappingType ).prepareMappingModel( creationProcess );
|
||||||
final PersistentClass bootEntityDescriptor = creationContext
|
|
||||||
.getBootModel()
|
|
||||||
.getEntityBinding( getEntityName() );
|
|
||||||
|
|
||||||
// todo (6.0) : should we create these only on root?
|
|
||||||
|
|
||||||
|
this.identifierMapping = superMappingType.getIdentifierMapping();
|
||||||
|
this.versionMapping = superMappingType.getVersionMapping();
|
||||||
|
this.discriminatorMapping = superMappingType.getDiscriminatorMapping();
|
||||||
|
this.naturalIdMapping = superMappingType.getNaturalIdMapping();
|
||||||
|
}
|
||||||
|
else {
|
||||||
identifierMapping = creationProcess.processSubPart(
|
identifierMapping = creationProcess.processSubPart(
|
||||||
EntityIdentifierMapping.ROLE_LOCAL_NAME,
|
EntityIdentifierMapping.ROLE_LOCAL_NAME,
|
||||||
(role, creationProcess1) -> generateIdentifierMapping( creationProcess )
|
(role, creationProcess1) -> generateIdentifierMapping( creationProcess )
|
||||||
);
|
);
|
||||||
|
|
||||||
naturalIdMapping = null;
|
|
||||||
|
|
||||||
if ( getVersionType() == null ) {
|
if ( getVersionType() == null ) {
|
||||||
versionMapping = null;
|
versionMapping = null;
|
||||||
}
|
}
|
||||||
|
@ -6109,6 +6108,16 @@ public abstract class AbstractEntityPersister
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo (6.0) : support for natural-id not yet implemented
|
||||||
|
naturalIdMapping = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final RuntimeModelCreationContext creationContext = creationProcess.getCreationContext();
|
||||||
|
|
||||||
|
final PersistentClass bootEntityDescriptor = creationContext
|
||||||
|
.getBootModel()
|
||||||
|
.getEntityBinding( getEntityName() );
|
||||||
|
|
||||||
final EntityMetamodel currentEntityMetamodel = this.getEntityMetamodel();
|
final EntityMetamodel currentEntityMetamodel = this.getEntityMetamodel();
|
||||||
|
|
||||||
int stateArrayPosition = superMappingType == null ? 0 : superMappingType.getNumberOfAttributeMappings();
|
int stateArrayPosition = superMappingType == null ? 0 : superMappingType.getNumberOfAttributeMappings();
|
||||||
|
@ -6117,6 +6126,10 @@ public abstract class AbstractEntityPersister
|
||||||
final NonIdentifierAttribute runtimeAttrDefinition = currentEntityMetamodel.getProperties()[i];
|
final NonIdentifierAttribute runtimeAttrDefinition = currentEntityMetamodel.getProperties()[i];
|
||||||
final Property bootProperty = bootEntityDescriptor.getProperty( runtimeAttrDefinition.getName() );
|
final Property bootProperty = bootEntityDescriptor.getProperty( runtimeAttrDefinition.getName() );
|
||||||
|
|
||||||
|
if ( superMappingType != null && superMappingType.findAttributeMapping( bootProperty.getName() ) != null ) {
|
||||||
|
// its defined on the super-type, skip it here
|
||||||
|
}
|
||||||
|
else {
|
||||||
declaredAttributeMappings.put(
|
declaredAttributeMappings.put(
|
||||||
runtimeAttrDefinition.getName(),
|
runtimeAttrDefinition.getName(),
|
||||||
generateNonIdAttributeMapping(
|
generateNonIdAttributeMapping(
|
||||||
|
@ -6128,6 +6141,9 @@ public abstract class AbstractEntityPersister
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getAttributeMappings();
|
||||||
|
|
||||||
final ReflectionOptimizer reflectionOptimizer = representationStrategy.getReflectionOptimizer();
|
final ReflectionOptimizer reflectionOptimizer = representationStrategy.getReflectionOptimizer();
|
||||||
|
|
||||||
|
@ -6172,6 +6188,21 @@ public abstract class AbstractEntityPersister
|
||||||
return declaredAttributeMappings.size();
|
return declaredAttributeMappings.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<AttributeMapping> getDeclaredAttributeMappings() {
|
||||||
|
return declaredAttributeMappings.values();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitDeclaredAttributeMappings(Consumer<AttributeMapping> action) {
|
||||||
|
declaredAttributeMappings.forEach( (key,value) -> action.accept( value ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityMappingType getSuperMappingType() {
|
||||||
|
return superMappingType;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isTypeOrSuperType(EntityMappingType targetType) {
|
public boolean isTypeOrSuperType(EntityMappingType targetType) {
|
||||||
if ( targetType == null ) {
|
if ( targetType == null ) {
|
||||||
|
@ -6317,11 +6348,7 @@ public abstract class AbstractEntityPersister
|
||||||
attributeMappings = new ArrayList<>();
|
attributeMappings = new ArrayList<>();
|
||||||
|
|
||||||
if ( superMappingType != null ) {
|
if ( superMappingType != null ) {
|
||||||
superMappingType.visitAttributeMappings(
|
superMappingType.visitAttributeMappings( attributeMappings::add );
|
||||||
attributeMappings::add,
|
|
||||||
// only walk up the hierarchy
|
|
||||||
superMappingType
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
attributeMappings.addAll( declaredAttributeMappings.values() );
|
attributeMappings.addAll( declaredAttributeMappings.values() );
|
||||||
|
@ -6332,6 +6359,28 @@ public abstract class AbstractEntityPersister
|
||||||
return attributeMappings;
|
return attributeMappings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AttributeMapping findDeclaredAttributeMapping(String name) {
|
||||||
|
return declaredAttributeMappings.get( name );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AttributeMapping findAttributeMapping(String name) {
|
||||||
|
final AttributeMapping declaredAttribute = declaredAttributeMappings.get( name );
|
||||||
|
if ( declaredAttribute != null ) {
|
||||||
|
return declaredAttribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( superMappingType != null ) {
|
||||||
|
final AttributeMapping fromSuperType = superMappingType.findAttributeMapping( name );
|
||||||
|
if ( fromSuperType != null ) {
|
||||||
|
return fromSuperType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ModelPart findSubPart(String name, EntityMappingType treatTargetType) {
|
public ModelPart findSubPart(String name, EntityMappingType treatTargetType) {
|
||||||
LOG.tracef( "#findSubPart(`%s`)", name );
|
LOG.tracef( "#findSubPart(`%s`)", name );
|
||||||
|
@ -6397,7 +6446,6 @@ public abstract class AbstractEntityPersister
|
||||||
EntityMappingType treatTargetType) {
|
EntityMappingType treatTargetType) {
|
||||||
if ( getIdentifierMapping() instanceof FetchableContainer ) {
|
if ( getIdentifierMapping() instanceof FetchableContainer ) {
|
||||||
// essentially means the entity has a composite id - ask the embeddable to visit its fetchables
|
// essentially means the entity has a composite id - ask the embeddable to visit its fetchables
|
||||||
// - todo (6.0) : determine whether this should call `#visitFetchables` or `#visitKeyFetchables`
|
|
||||||
( (FetchableContainer) getIdentifierMapping() ).visitFetchables( fetchableConsumer, treatTargetType );
|
( (FetchableContainer) getIdentifierMapping() ).visitFetchables( fetchableConsumer, treatTargetType );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6408,41 +6456,23 @@ public abstract class AbstractEntityPersister
|
||||||
public void visitFetchables(
|
public void visitFetchables(
|
||||||
Consumer<Fetchable> fetchableConsumer,
|
Consumer<Fetchable> fetchableConsumer,
|
||||||
EntityMappingType treatTargetType) {
|
EntityMappingType treatTargetType) {
|
||||||
//noinspection unchecked
|
for ( int i = 0; i < attributeMappings.size(); i++ ) {
|
||||||
visitStateArrayContributors(
|
fetchableConsumer.accept( (Fetchable) attributeMappings.get( i ) );
|
||||||
(Consumer) fetchableConsumer,
|
|
||||||
treatTargetType
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
if ( treatTargetType == null || treatTargetType.isTypeOrSuperType( this ) ) {
|
||||||
public void visitStateArrayContributors(
|
visitSubTypeAttributeMappings(
|
||||||
Consumer<StateArrayContributorMapping> mappingConsumer,
|
attributeMapping -> fetchableConsumer.accept( (Fetchable) attributeMapping )
|
||||||
EntityMappingType targetType) {
|
|
||||||
//noinspection Convert2Lambda
|
|
||||||
visitAttributeMappings(
|
|
||||||
new Consumer<AttributeMapping>() {
|
|
||||||
@Override
|
|
||||||
public void accept(AttributeMapping attributeMapping) {
|
|
||||||
if ( attributeMapping instanceof StateArrayContributorMapping ) {
|
|
||||||
mappingConsumer.accept( (StateArrayContributorMapping) attributeMapping );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
targetType
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitAttributeMappings(
|
public void visitAttributeMappings(
|
||||||
Consumer<AttributeMapping> action,
|
Consumer<AttributeMapping> action,
|
||||||
EntityMappingType targetType) {
|
EntityMappingType targetType) {
|
||||||
visitSuperTypeAttributeMappings( action );
|
for ( int i = 0; i < attributeMappings.size(); i++ ) {
|
||||||
|
action.accept( attributeMappings.get( i ) );
|
||||||
declaredAttributeMappings.values().forEach( action );
|
|
||||||
|
|
||||||
if ( targetType == null || targetType.isTypeOrSuperType( this ) ) {
|
|
||||||
visitSubTypeAttributeMappings( action );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6456,8 +6486,11 @@ public abstract class AbstractEntityPersister
|
||||||
@Override
|
@Override
|
||||||
public void visitSubTypeAttributeMappings(Consumer<AttributeMapping> action) {
|
public void visitSubTypeAttributeMappings(Consumer<AttributeMapping> action) {
|
||||||
if ( subclassMappingTypes != null ) {
|
if ( subclassMappingTypes != null ) {
|
||||||
subclassMappingTypes.values().forEach(
|
subclassMappingTypes.forEach(
|
||||||
subclassMappingTypes -> subclassMappingTypes.visitSubTypeAttributeMappings( action )
|
(s, subType) -> {
|
||||||
|
subType.visitDeclaredAttributeMappings( action );
|
||||||
|
subType.visitSubTypeAttributeMappings( action );
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,14 +8,12 @@ package org.hibernate.sql.results.internal.domain.entity;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.IdentityHashMap;
|
import java.util.IdentityHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.NotYetImplementedFor6Exception;
|
|
||||||
import org.hibernate.WrongClassException;
|
import org.hibernate.WrongClassException;
|
||||||
import org.hibernate.cache.spi.access.EntityDataAccess;
|
import org.hibernate.cache.spi.access.EntityDataAccess;
|
||||||
import org.hibernate.cache.spi.entry.CacheEntry;
|
import org.hibernate.cache.spi.entry.CacheEntry;
|
||||||
|
@ -35,8 +33,10 @@ import org.hibernate.event.spi.PostLoadEventListener;
|
||||||
import org.hibernate.event.spi.PreLoadEvent;
|
import org.hibernate.event.spi.PreLoadEvent;
|
||||||
import org.hibernate.event.spi.PreLoadEventListener;
|
import org.hibernate.event.spi.PreLoadEventListener;
|
||||||
import org.hibernate.internal.util.StringHelper;
|
import org.hibernate.internal.util.StringHelper;
|
||||||
|
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||||
import org.hibernate.metamodel.mapping.StateArrayContributorMapping;
|
import org.hibernate.metamodel.mapping.StateArrayContributorMapping;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
import org.hibernate.persister.entity.Loadable;
|
||||||
import org.hibernate.proxy.HibernateProxy;
|
import org.hibernate.proxy.HibernateProxy;
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
import org.hibernate.sql.results.internal.NullValueAssembler;
|
import org.hibernate.sql.results.internal.NullValueAssembler;
|
||||||
|
@ -67,6 +67,7 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
||||||
// these
|
// these
|
||||||
|
|
||||||
private final EntityPersister entityDescriptor;
|
private final EntityPersister entityDescriptor;
|
||||||
|
private final EntityPersister rootEntityDescriptor;
|
||||||
private final NavigablePath navigablePath;
|
private final NavigablePath navigablePath;
|
||||||
private final LockMode lockMode;
|
private final LockMode lockMode;
|
||||||
|
|
||||||
|
@ -76,7 +77,7 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
||||||
private final DomainResultAssembler discriminatorAssembler;
|
private final DomainResultAssembler discriminatorAssembler;
|
||||||
private final DomainResultAssembler versionAssembler;
|
private final DomainResultAssembler versionAssembler;
|
||||||
|
|
||||||
private final Map<StateArrayContributorMapping, DomainResultAssembler> assemblerMap;
|
private final Map<AttributeMapping, DomainResultAssembler> assemblerMap;
|
||||||
|
|
||||||
// per-row state
|
// per-row state
|
||||||
private EntityPersister concreteDescriptor;
|
private EntityPersister concreteDescriptor;
|
||||||
|
@ -98,7 +99,17 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
||||||
Consumer<Initializer> initializerConsumer,
|
Consumer<Initializer> initializerConsumer,
|
||||||
AssemblerCreationState creationState) {
|
AssemblerCreationState creationState) {
|
||||||
super( );
|
super( );
|
||||||
|
|
||||||
this.entityDescriptor = (EntityPersister) resultDescriptor.getEntityValuedModelPart().getEntityMappingType();
|
this.entityDescriptor = (EntityPersister) resultDescriptor.getEntityValuedModelPart().getEntityMappingType();
|
||||||
|
|
||||||
|
final String rootEntityName = entityDescriptor.getRootEntityName();
|
||||||
|
if ( rootEntityName == null || rootEntityName.equals( entityDescriptor.getEntityName() ) ) {
|
||||||
|
this.rootEntityDescriptor = entityDescriptor;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.rootEntityDescriptor = creationState.getSqlAstCreationContext().getDomainModel().findEntityDescriptor( rootEntityName );
|
||||||
|
}
|
||||||
|
|
||||||
this.navigablePath = navigablePath;
|
this.navigablePath = navigablePath;
|
||||||
this.lockMode = lockMode;
|
this.lockMode = lockMode;
|
||||||
|
|
||||||
|
@ -135,13 +146,15 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
||||||
|
|
||||||
assemblerMap = new IdentityHashMap<>( entityDescriptor.getNumberOfAttributeMappings() );
|
assemblerMap = new IdentityHashMap<>( entityDescriptor.getNumberOfAttributeMappings() );
|
||||||
|
|
||||||
entityDescriptor.visitStateArrayContributors(
|
entityDescriptor.visitFetchables(
|
||||||
attributeMapping -> {
|
fetchable -> {
|
||||||
|
final AttributeMapping attributeMapping = (AttributeMapping) fetchable;
|
||||||
|
|
||||||
// todo (6.0) : somehow we need to track whether all state is loaded/resolved
|
// todo (6.0) : somehow we need to track whether all state is loaded/resolved
|
||||||
// note that lazy proxies or uninitialized collections count against
|
// note that lazy proxies or uninitialized collections count against
|
||||||
// that in the affirmative
|
// that in the affirmative
|
||||||
|
|
||||||
final Fetch fetch = resultDescriptor.findFetch( attributeMapping.getAttributeName() );
|
final Fetch fetch = resultDescriptor.findFetch( fetchable.getFetchableName() );
|
||||||
|
|
||||||
final DomainResultAssembler stateAssembler;
|
final DomainResultAssembler stateAssembler;
|
||||||
if ( fetch == null ) {
|
if ( fetch == null ) {
|
||||||
|
@ -156,7 +169,8 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
||||||
}
|
}
|
||||||
|
|
||||||
assemblerMap.put( attributeMapping, stateAssembler );
|
assemblerMap.put( attributeMapping, stateAssembler );
|
||||||
}
|
},
|
||||||
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
initializerConsumer.accept( this );
|
initializerConsumer.accept( this );
|
||||||
|
@ -242,31 +256,33 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
||||||
|
|
||||||
private EntityPersister determineConcreteEntityDescriptor(
|
private EntityPersister determineConcreteEntityDescriptor(
|
||||||
RowProcessingState rowProcessingState,
|
RowProcessingState rowProcessingState,
|
||||||
SharedSessionContractImplementor persistenceContext) throws WrongClassException {
|
SharedSessionContractImplementor session) throws WrongClassException {
|
||||||
if ( discriminatorAssembler == null ) {
|
if ( discriminatorAssembler == null ) {
|
||||||
return entityDescriptor;
|
return entityDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotYetImplementedFor6Exception( getClass() );
|
final Object discriminatorValue = discriminatorAssembler.assemble(
|
||||||
// final Object discriminatorValue = discriminatorAssembler.assemble(
|
rowProcessingState,
|
||||||
// rowProcessingState,
|
rowProcessingState.getJdbcValuesSourceProcessingState().getProcessingOptions()
|
||||||
// rowProcessingState.getJdbcValuesSourceProcessingState().getProcessingOptions()
|
);
|
||||||
// );
|
|
||||||
//
|
final String concreteEntityName = ( (Loadable) entityDescriptor ).getSubclassForDiscriminatorValue( discriminatorValue );
|
||||||
// final String result = entityDescriptor.getDiscriminatorDescriptor()
|
|
||||||
// .getDiscriminatorMappings()
|
if ( concreteEntityName == null ) {
|
||||||
// .discriminatorValueToEntityName( discriminatorValue );
|
// oops - we got an instance of another class hierarchy branch
|
||||||
//
|
throw new WrongClassException(
|
||||||
// if ( result == null ) {
|
"Discriminator: " + discriminatorValue,
|
||||||
// // oops - we got an instance of another class hierarchy branch
|
entityKey.getIdentifier(),
|
||||||
// throw new WrongClassException(
|
entityDescriptor.getEntityName()
|
||||||
// "Discriminator: " + discriminatorValue,
|
);
|
||||||
// entityKey.getIdentifier(),
|
}
|
||||||
// entityDescriptor.getEntityName()
|
|
||||||
// );
|
final EntityPersister concreteType = session.getFactory().getMetamodel().findEntityDescriptor( concreteEntityName );
|
||||||
// }
|
|
||||||
//
|
// verify that the `entityDescriptor` is either == concreteType or its super-type
|
||||||
// return persistenceContext.getFactory().getMetamodel().findEntityDescriptor( result );
|
assert concreteType.isTypeOrSuperType( entityDescriptor );
|
||||||
|
|
||||||
|
return concreteType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
|
@ -454,12 +470,12 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
||||||
|
|
||||||
entityDescriptor.setIdentifier( entityInstance, entityIdentifier, session );
|
entityDescriptor.setIdentifier( entityInstance, entityIdentifier, session );
|
||||||
|
|
||||||
resolvedEntityState = new Object[ assemblerMap.size() ];
|
resolvedEntityState = concreteDescriptor.extractConcreteTypeStateValues(
|
||||||
assemblerMap.forEach(
|
assemblerMap,
|
||||||
(key, value) -> resolvedEntityState[ key.getStateArrayPosition() ] = value.assemble( rowProcessingState )
|
rowProcessingState
|
||||||
);
|
);
|
||||||
|
|
||||||
entityDescriptor.setPropertyValues( entityInstance, resolvedEntityState );
|
concreteDescriptor.setPropertyValues( entityInstance, resolvedEntityState );
|
||||||
|
|
||||||
persistenceContext.addEntity(
|
persistenceContext.addEntity(
|
||||||
entityKey,
|
entityKey,
|
||||||
|
@ -483,12 +499,12 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
||||||
version,
|
version,
|
||||||
lockMode,
|
lockMode,
|
||||||
true,
|
true,
|
||||||
entityDescriptor,
|
concreteDescriptor,
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
final SessionFactoryImplementor factory = session.getFactory();
|
final SessionFactoryImplementor factory = session.getFactory();
|
||||||
final EntityDataAccess cacheAccess = entityDescriptor.getCacheAccessStrategy();
|
final EntityDataAccess cacheAccess = concreteDescriptor.getCacheAccessStrategy();
|
||||||
if ( cacheAccess != null && session.getCacheMode().isPutEnabled() ) {
|
if ( cacheAccess != null && session.getCacheMode().isPutEnabled() ) {
|
||||||
|
|
||||||
if ( EntityLoadingLogger.DEBUG_ENABLED ) {
|
if ( EntityLoadingLogger.DEBUG_ENABLED ) {
|
||||||
|
@ -498,10 +514,10 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final CacheEntry entry = entityDescriptor.buildCacheEntry( entityInstance, resolvedEntityState, version, session );
|
final CacheEntry entry = concreteDescriptor.buildCacheEntry( entityInstance, resolvedEntityState, version, session );
|
||||||
final Object cacheKey = cacheAccess.generateCacheKey(
|
final Object cacheKey = cacheAccess.generateCacheKey(
|
||||||
entityIdentifier,
|
entityIdentifier,
|
||||||
entityDescriptor,
|
rootEntityDescriptor,
|
||||||
factory,
|
factory,
|
||||||
session.getTenantIdentifier()
|
session.getTenantIdentifier()
|
||||||
);
|
);
|
||||||
|
@ -512,11 +528,11 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
||||||
// 2) Session#clear + some form of load
|
// 2) Session#clear + some form of load
|
||||||
//
|
//
|
||||||
// we need to be careful not to clobber the lock here in the cache so that it can be rolled back if need be
|
// we need to be careful not to clobber the lock here in the cache so that it can be rolled back if need be
|
||||||
if ( persistenceContext.wasInsertedDuringTransaction( entityDescriptor, entityIdentifier ) ) {
|
if ( persistenceContext.wasInsertedDuringTransaction( concreteDescriptor, entityIdentifier ) ) {
|
||||||
cacheAccess.update(
|
cacheAccess.update(
|
||||||
session,
|
session,
|
||||||
cacheKey,
|
cacheKey,
|
||||||
entityDescriptor.getCacheEntryStructure().structure( entry ),
|
rootEntityDescriptor.getCacheEntryStructure().structure( entry ),
|
||||||
version,
|
version,
|
||||||
version
|
version
|
||||||
);
|
);
|
||||||
|
@ -528,14 +544,14 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
||||||
final boolean put = cacheAccess.putFromLoad(
|
final boolean put = cacheAccess.putFromLoad(
|
||||||
session,
|
session,
|
||||||
cacheKey,
|
cacheKey,
|
||||||
entityDescriptor.getCacheEntryStructure().structure( entry ),
|
rootEntityDescriptor.getCacheEntryStructure().structure( entry ),
|
||||||
version,
|
version,
|
||||||
//useMinimalPuts( session, entityEntry )
|
//useMinimalPuts( session, entityEntry )
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
if ( put && factory.getStatistics().isStatisticsEnabled() ) {
|
if ( put && factory.getStatistics().isStatisticsEnabled() ) {
|
||||||
factory.getStatistics().entityCachePut( entityDescriptor.getNavigableRole(), cacheAccess.getRegion().getName() );
|
factory.getStatistics().entityCachePut( rootEntityDescriptor.getNavigableRole(), cacheAccess.getRegion().getName() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
@ -554,7 +570,7 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isReallyReadOnly = isReadOnly( rowProcessingState, session );
|
boolean isReallyReadOnly = isReadOnly( rowProcessingState, session );
|
||||||
if ( ! entityDescriptor.isMutable() ) {
|
if ( ! concreteDescriptor.isMutable() ) {
|
||||||
isReallyReadOnly = true;
|
isReallyReadOnly = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -575,7 +591,7 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
||||||
else {
|
else {
|
||||||
//take a snapshot
|
//take a snapshot
|
||||||
TypeHelper.deepCopy(
|
TypeHelper.deepCopy(
|
||||||
entityDescriptor,
|
concreteDescriptor,
|
||||||
resolvedEntityState,
|
resolvedEntityState,
|
||||||
resolvedEntityState,
|
resolvedEntityState,
|
||||||
attributeMapping -> attributeMapping.getAttributeMetadataAccess().resolveAttributeMetadata( concreteDescriptor ).isUpdatable()
|
attributeMapping -> attributeMapping.getAttributeMetadataAccess().resolveAttributeMetadata( concreteDescriptor ).isUpdatable()
|
||||||
|
@ -583,7 +599,7 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
||||||
persistenceContext.setEntryStatus( entityEntry, Status.MANAGED );
|
persistenceContext.setEntryStatus( entityEntry, Status.MANAGED );
|
||||||
}
|
}
|
||||||
|
|
||||||
entityDescriptor.afterInitialize( entityInstance, session );
|
concreteDescriptor.afterInitialize( entityInstance, session );
|
||||||
|
|
||||||
if ( EntityLoadingLogger.DEBUG_ENABLED ) {
|
if ( EntityLoadingLogger.DEBUG_ENABLED ) {
|
||||||
EntityLoadingLogger.INSTANCE.debugf(
|
EntityLoadingLogger.INSTANCE.debugf(
|
||||||
|
@ -593,7 +609,7 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( factory.getStatistics().isStatisticsEnabled() ) {
|
if ( factory.getStatistics().isStatisticsEnabled() ) {
|
||||||
factory.getStatistics().loadEntity( entityDescriptor.getEntityName() );
|
factory.getStatistics().loadEntity( concreteDescriptor.getEntityName() );
|
||||||
}
|
}
|
||||||
|
|
||||||
postLoad( rowProcessingState );
|
postLoad( rowProcessingState );
|
||||||
|
|
|
@ -12,6 +12,7 @@ import java.util.List;
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||||
import org.hibernate.metamodel.mapping.AttributeMapping;
|
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||||
|
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
|
||||||
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||||
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
|
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
|
||||||
|
@ -68,18 +69,17 @@ public abstract class AbstractEntityResultNode extends AbstractFetchParent imple
|
||||||
creationState
|
creationState
|
||||||
);
|
);
|
||||||
|
|
||||||
// final DiscriminatorMappDescriptor<?> discriminatorDescriptor = entityDescriptor.getHierarchy().getDiscriminatorDescriptor();
|
if ( entityDescriptor.getDiscriminatorMapping() != null ) {
|
||||||
// if ( discriminatorDescriptor == null ) {
|
discriminatorResult = entityDescriptor.getDiscriminatorMapping().createDomainResult(
|
||||||
// discriminatorResult = null;
|
navigablePath.append( EntityDiscriminatorMapping.ROLE_NAME ),
|
||||||
// }
|
entityTableGroup,
|
||||||
// else {
|
null,
|
||||||
// discriminatorResult = discriminatorDescriptor.createDomainResult(
|
creationState
|
||||||
// navigablePath.append( DiscriminatorDescriptor.NAVIGABLE_NAME ),
|
);
|
||||||
// null,
|
}
|
||||||
// creationState
|
else {
|
||||||
// );
|
|
||||||
// }
|
|
||||||
discriminatorResult = null;
|
discriminatorResult = null;
|
||||||
|
}
|
||||||
|
|
||||||
final EntityVersionMapping versionDescriptor = entityDescriptor.getVersionMapping();
|
final EntityVersionMapping versionDescriptor = entityDescriptor.getVersionMapping();
|
||||||
if ( versionDescriptor == null ) {
|
if ( versionDescriptor == null ) {
|
||||||
|
|
|
@ -72,36 +72,13 @@ public class InheritanceTests {
|
||||||
assert foreignCustomerDescriptor.isTypeOrSuperType( foreignCustomerDescriptor );
|
assert foreignCustomerDescriptor.isTypeOrSuperType( foreignCustomerDescriptor );
|
||||||
}
|
}
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
public void createTestData(SessionFactoryScope scope) {
|
|
||||||
scope.inTransaction(
|
|
||||||
session -> {
|
|
||||||
session.persist( new DomesticCustomer( 1, "domestic", "123" ) );
|
|
||||||
session.persist( new ForeignCustomer( 2, "foreign", "987" ) );
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterEach
|
|
||||||
public void cleanupTestData(SessionFactoryScope scope) {
|
|
||||||
scope.inTransaction(
|
|
||||||
session -> {
|
|
||||||
session.createQuery( "from DomesticCustomer", DomesticCustomer.class ).list().forEach(
|
|
||||||
cust -> session.delete( cust )
|
|
||||||
);
|
|
||||||
session.createQuery( "from ForeignCustomer", ForeignCustomer.class ).list().forEach(
|
|
||||||
cust -> session.delete( cust )
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@FailureExpected
|
// @FailureExpected
|
||||||
public void rootQueryExecutionTest(SessionFactoryScope scope) {
|
public void rootQueryExecutionTest(SessionFactoryScope scope) {
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
{
|
{
|
||||||
|
// [name, taxId, vat]
|
||||||
final List<Customer> results = session.createQuery(
|
final List<Customer> results = session.createQuery(
|
||||||
"select c from Customer c",
|
"select c from Customer c",
|
||||||
Customer.class
|
Customer.class
|
||||||
|
@ -112,11 +89,15 @@ public class InheritanceTests {
|
||||||
for ( Customer result : results ) {
|
for ( Customer result : results ) {
|
||||||
if ( result.getId() == 1 ) {
|
if ( result.getId() == 1 ) {
|
||||||
assertThat( result, instanceOf( DomesticCustomer.class ) );
|
assertThat( result, instanceOf( DomesticCustomer.class ) );
|
||||||
assertThat( ( (DomesticCustomer) result ).getTaxId(), is( "123" ) );
|
final DomesticCustomer customer = (DomesticCustomer) result;
|
||||||
|
assertThat( customer.getName(), is( "domestic" ) );
|
||||||
|
assertThat( (customer).getTaxId(), is( "123" ) );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
assertThat( result.getId(), is( 2 ) );
|
assertThat( result.getId(), is( 2 ) );
|
||||||
assertThat( ( (ForeignCustomer) result ).getVat(), is( "987" ) );
|
final ForeignCustomer customer = (ForeignCustomer) result;
|
||||||
|
assertThat( customer.getName(), is( "foreign" ) );
|
||||||
|
assertThat( (customer).getVat(), is( "987" ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,6 +137,30 @@ public class InheritanceTests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void createTestData(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
session.persist( new DomesticCustomer( 1, "domestic", "123" ) );
|
||||||
|
session.persist( new ForeignCustomer( 2, "foreign", "987" ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void cleanupTestData(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
session.createQuery( "from DomesticCustomer", DomesticCustomer.class ).list().forEach(
|
||||||
|
cust -> session.delete( cust )
|
||||||
|
);
|
||||||
|
session.createQuery( "from ForeignCustomer", ForeignCustomer.class ).list().forEach(
|
||||||
|
cust -> session.delete( cust )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Entity( name = "Customer" )
|
@Entity( name = "Customer" )
|
||||||
@Inheritance( strategy = InheritanceType.SINGLE_TABLE )
|
@Inheritance( strategy = InheritanceType.SINGLE_TABLE )
|
||||||
@Table( name = "customer" )
|
@Table( name = "customer" )
|
||||||
|
|
|
@ -7,14 +7,23 @@
|
||||||
package org.hibernate.orm.test.sql.exec;
|
package org.hibernate.orm.test.sql.exec;
|
||||||
|
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||||
import org.hibernate.orm.test.metamodel.mapping.SmokeTests.Component;
|
import org.hibernate.orm.test.metamodel.mapping.SmokeTests.Component;
|
||||||
import org.hibernate.orm.test.metamodel.mapping.SmokeTests.Gender;
|
import org.hibernate.orm.test.metamodel.mapping.SmokeTests.Gender;
|
||||||
import org.hibernate.orm.test.metamodel.mapping.SmokeTests.OtherEntity;
|
import org.hibernate.orm.test.metamodel.mapping.SmokeTests.OtherEntity;
|
||||||
import org.hibernate.orm.test.metamodel.mapping.SmokeTests.SimpleEntity;
|
import org.hibernate.orm.test.metamodel.mapping.SmokeTests.SimpleEntity;
|
||||||
import org.hibernate.query.Query;
|
import org.hibernate.query.Query;
|
||||||
import org.hibernate.query.spi.QueryImplementor;
|
import org.hibernate.query.spi.QueryImplementor;
|
||||||
|
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||||
|
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
import org.hibernate.testing.orm.junit.FailureExpected;
|
import org.hibernate.testing.orm.junit.FailureExpected;
|
||||||
|
@ -46,7 +55,12 @@ import static org.hibernate.orm.test.metamodel.mapping.SmokeTests.Gender.MALE;
|
||||||
SmokeTests.BasicSetterBasedDto.class
|
SmokeTests.BasicSetterBasedDto.class
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ServiceRegistry
|
@ServiceRegistry(
|
||||||
|
settings = {
|
||||||
|
@ServiceRegistry.Setting( name = AvailableSettings.POOL_SIZE, value = "15" ),
|
||||||
|
@ServiceRegistry.Setting( name = AvailableSettings.USE_SECOND_LEVEL_CACHE, value = "false" )
|
||||||
|
}
|
||||||
|
)
|
||||||
@SessionFactory( exportSchema = true )
|
@SessionFactory( exportSchema = true )
|
||||||
public class SmokeTests {
|
public class SmokeTests {
|
||||||
|
|
||||||
|
@ -279,6 +293,60 @@ public class SmokeTests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testQueryConcurrency(SessionFactoryScope scope) throws InterruptedException {
|
||||||
|
final StatisticsImplementor statistics = scope.getSessionFactory().getStatistics();
|
||||||
|
statistics.clear();
|
||||||
|
|
||||||
|
final int numberOfIterations = 400;
|
||||||
|
final int numberOfForks = 50;
|
||||||
|
|
||||||
|
final ExecutorService executor = Executors.newFixedThreadPool( 5 );
|
||||||
|
|
||||||
|
try {
|
||||||
|
for ( int f = 0; f < numberOfForks; f++ ) {
|
||||||
|
final ArrayList<Callable<String>> tasks = CollectionHelper.arrayList( numberOfIterations );
|
||||||
|
|
||||||
|
for ( int i = 0; i < numberOfIterations; i++ ) {
|
||||||
|
tasks.add( () -> executeQueriesForConcurrency( scope ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
executor.invokeAll( tasks );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
// make sure all iterations/tasks have completed
|
||||||
|
executor.shutdown();
|
||||||
|
executor.awaitTermination( 15, TimeUnit.SECONDS );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String executeQueriesForConcurrency(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
final QueryImplementor<Component> query1 = session.createQuery(
|
||||||
|
"select e.component from SimpleEntity e where e.component.attribute1 = :param",
|
||||||
|
Component.class
|
||||||
|
);
|
||||||
|
query1.setParameter( "param", "a1" ).list();
|
||||||
|
|
||||||
|
final QueryImplementor<Component> query2 = session.createQuery(
|
||||||
|
"select e.component from SimpleEntity e where e.component.attribute1 = :param",
|
||||||
|
Component.class
|
||||||
|
);
|
||||||
|
query2.setParameter( "param", "b1" ).list();
|
||||||
|
|
||||||
|
final QueryImplementor<Component> query3 = session.createQuery(
|
||||||
|
"select e from SimpleEntity e where e.component.attribute1 = :param",
|
||||||
|
Component.class
|
||||||
|
);
|
||||||
|
query3.setParameter( "param", "a1" ).list();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
// Dynamic instantiations
|
// Dynamic instantiations
|
||||||
|
|
|
@ -84,7 +84,9 @@ public class SessionFactoryExtension
|
||||||
sessionFactoryBuilder.applyName( sessionFactoryConfig.sessionFactoryName() );
|
sessionFactoryBuilder.applyName( sessionFactoryConfig.sessionFactoryName() );
|
||||||
}
|
}
|
||||||
|
|
||||||
sessionFactoryBuilder.applyStatisticsSupport( sessionFactoryConfig.generateStatistics() );
|
if ( sessionFactoryConfig.generateStatistics() ) {
|
||||||
|
sessionFactoryBuilder.applyStatisticsSupport( true );
|
||||||
|
}
|
||||||
|
|
||||||
if ( ! sessionFactoryConfig.interceptorClass().equals( Interceptor.class ) ) {
|
if ( ! sessionFactoryConfig.interceptorClass().equals( Interceptor.class ) ) {
|
||||||
sessionFactoryBuilder.applyInterceptor( sessionFactoryConfig.interceptorClass().newInstance() );
|
sessionFactoryBuilder.applyInterceptor( sessionFactoryConfig.interceptorClass().newInstance() );
|
||||||
|
|
Loading…
Reference in New Issue