preliminary support for collections - lists and sets tested (excluding entity-valued elements and map-key)

This commit is contained in:
Steve Ebersole 2019-10-31 17:43:54 -05:00
parent 093f410953
commit c89ee3761a
76 changed files with 3249 additions and 402 deletions

View File

@ -36,7 +36,8 @@ public class EnumeratedValueResolution<E extends Enum<E>> implements BasicValue.
this.domainJtd = domainJtd;
this.jdbcJtd = jdbcJtd;
this.std = std;
this.valueConverter = valueConverter;
// this.valueConverter = valueConverter;
this.valueConverter = null;
}
@Override

View File

@ -25,6 +25,7 @@ import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.cfg.MetadataSourceType;
import org.hibernate.collection.internal.StandardCollectionSemanticsResolver;
import org.hibernate.collection.spi.CollectionSemanticsResolver;
import org.hibernate.dialect.function.SQLFunction;
import org.hibernate.metamodel.internal.StandardManagedTypeRepresentationResolver;
@ -61,7 +62,8 @@ public interface MetadataBuildingOptions {
}
default CollectionSemanticsResolver getPersistentCollectionRepresentationResolver() {
throw new NotYetImplementedFor6Exception( getClass() );
// for now always return the standard one
return StandardCollectionSemanticsResolver.INSTANCE;
}
/**

View File

@ -21,6 +21,8 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.loader.CollectionAliases;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.RowProcessingState;
import org.hibernate.type.Type;
import org.jboss.logging.Logger;
@ -190,6 +192,31 @@ public class PersistentArrayHolder extends AbstractPersistentCollection {
return element;
}
@Override
public Object readFrom(
RowProcessingState rowProcessingState,
DomainResultAssembler elementAssembler,
DomainResultAssembler indexAssembler,
DomainResultAssembler identifierAssembler,
Object owner) throws HibernateException {
assert elementAssembler != null;
assert indexAssembler != null;
assert identifierAssembler == null;
final Object element = elementAssembler.assemble( rowProcessingState );
final int index = (int) indexAssembler.assemble( rowProcessingState );
for ( int i = tempList.size(); i<=index; i++) {
//noinspection unchecked
tempList.add( i, null );
}
//noinspection unchecked
tempList.set( index, element );
return element;
}
@Override
@SuppressWarnings("unchecked")
public Iterator entries(CollectionPersister persister) {

View File

@ -22,6 +22,8 @@ import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.loader.CollectionAliases;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.RowProcessingState;
import org.hibernate.type.Type;
/**
@ -133,6 +135,24 @@ public class PersistentBag extends AbstractPersistentCollection implements List
return element;
}
@Override
public Object readFrom(
RowProcessingState rowProcessingState,
DomainResultAssembler elementAssembler,
DomainResultAssembler indexAssembler,
DomainResultAssembler identifierAssembler,
Object owner) throws HibernateException {
assert indexAssembler == null;
assert identifierAssembler == null;
final Object element = elementAssembler.assemble( rowProcessingState );
if ( element != null ) {
//noinspection unchecked
bag.add( element );
}
return element;
}
@Override
public void beforeInitialize(CollectionPersister persister, int anticipatedSize) {
this.bag = (List) persister.getCollectionType().instantiate( anticipatedSize );

View File

@ -22,6 +22,8 @@ import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.loader.CollectionAliases;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.RowProcessingState;
import org.hibernate.type.Type;
/**
@ -372,6 +374,30 @@ public class PersistentIdentifierBag extends AbstractPersistentCollection implem
return element;
}
@Override
public Object readFrom(
RowProcessingState rowProcessingState,
DomainResultAssembler elementAssembler,
DomainResultAssembler indexAssembler,
DomainResultAssembler identifierAssembler,
Object owner) throws HibernateException {
assert indexAssembler == null;
final Object element = elementAssembler.assemble( rowProcessingState );
final Object identifier = identifierAssembler.assemble( rowProcessingState );
final Object old = identifiers.put(
values.size(),
identifier
);
if ( old == null ) {
//maintain correct duplication if loaded in a cartesian product
values.add( element );
}
return element;
}
@Override
@SuppressWarnings("unchecked")
public Serializable getSnapshot(CollectionPersister persister) throws HibernateException {

View File

@ -20,6 +20,8 @@ import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.loader.CollectionAliases;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.RowProcessingState;
import org.hibernate.type.Type;
/**
@ -206,9 +208,9 @@ public class PersistentList extends AbstractPersistentCollection implements List
}
@Override
@SuppressWarnings("unchecked")
public boolean containsAll(Collection coll) {
read();
//noinspection unchecked
return list.containsAll( coll );
}
@ -262,9 +264,9 @@ public class PersistentList extends AbstractPersistentCollection implements List
}
@Override
@SuppressWarnings("unchecked")
public boolean retainAll(Collection coll) {
initialize( true );
//noinspection unchecked
if ( list.retainAll( coll ) ) {
dirty();
return true;
@ -275,7 +277,6 @@ public class PersistentList extends AbstractPersistentCollection implements List
}
@Override
@SuppressWarnings("unchecked")
public void clear() {
if ( isClearQueueEnabled() ) {
queueOperation( new Clear() );
@ -290,7 +291,6 @@ public class PersistentList extends AbstractPersistentCollection implements List
}
@Override
@SuppressWarnings("unchecked")
public Object get(int index) {
if ( index < 0 ) {
throw new ArrayIndexOutOfBoundsException( "negative index" );
@ -300,7 +300,6 @@ public class PersistentList extends AbstractPersistentCollection implements List
}
@Override
@SuppressWarnings("unchecked")
public Object set(int index, Object value) {
if (index<0) {
throw new ArrayIndexOutOfBoundsException("negative index");
@ -310,6 +309,7 @@ public class PersistentList extends AbstractPersistentCollection implements List
if ( old==UNKNOWN ) {
write();
//noinspection unchecked
return list.set( index, value );
}
else {
@ -319,7 +319,6 @@ public class PersistentList extends AbstractPersistentCollection implements List
}
@Override
@SuppressWarnings("unchecked")
public Object remove(int index) {
if ( index < 0 ) {
throw new ArrayIndexOutOfBoundsException( "negative index" );
@ -338,45 +337,40 @@ public class PersistentList extends AbstractPersistentCollection implements List
}
@Override
@SuppressWarnings("unchecked")
public void add(int index, Object value) {
if ( index < 0 ) {
throw new ArrayIndexOutOfBoundsException( "negative index" );
}
write();
//noinspection unchecked
list.add( index, value );
}
@Override
@SuppressWarnings("unchecked")
public int indexOf(Object value) {
read();
return list.indexOf( value );
}
@Override
@SuppressWarnings("unchecked")
public int lastIndexOf(Object value) {
read();
return list.lastIndexOf( value );
}
@Override
@SuppressWarnings("unchecked")
public ListIterator listIterator() {
read();
return new ListIteratorProxy( list.listIterator() );
}
@Override
@SuppressWarnings("unchecked")
public ListIterator listIterator(int index) {
read();
return new ListIteratorProxy( list.listIterator( index ) );
}
@Override
@SuppressWarnings("unchecked")
public java.util.List subList(int from, int to) {
read();
return new ListProxy( list.subList( from, to ) );
@ -409,6 +403,32 @@ public class PersistentList extends AbstractPersistentCollection implements List
return element;
}
@Override
public Object readFrom(
RowProcessingState rowProcessingState,
DomainResultAssembler elementAssembler,
DomainResultAssembler indexAssembler,
DomainResultAssembler identifierAssembler,
Object owner) throws HibernateException {
assert elementAssembler != null;
assert indexAssembler != null;
assert identifierAssembler == null;
final Object element = elementAssembler.assemble( rowProcessingState );
final int index = (int) indexAssembler.assemble( rowProcessingState );
//pad with nulls from the current last element up to the new index
for ( int i = list.size(); i<=index; i++) {
//noinspection unchecked
list.add( i, null );
}
//noinspection unchecked
list.set( index, element );
return element;
}
@Override
@SuppressWarnings("unchecked")
public Iterator entries(CollectionPersister persister) {

View File

@ -22,6 +22,8 @@ import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.loader.CollectionAliases;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.RowProcessingState;
import org.hibernate.type.Type;
@ -176,7 +178,6 @@ public class PersistentMap extends AbstractPersistentCollection implements Map {
}
@Override
@SuppressWarnings("unchecked")
public Object put(Object key, Object value) {
if ( isPutQueueEnabled() ) {
final Object old = readElementByIndex( key );
@ -186,6 +187,7 @@ public class PersistentMap extends AbstractPersistentCollection implements Map {
}
}
initialize( true );
//noinspection unchecked
final Object old = map.put( key, value );
// would be better to use the element-type to determine
// whether the old and the new are equal here; the problem being
@ -198,7 +200,6 @@ public class PersistentMap extends AbstractPersistentCollection implements Map {
}
@Override
@SuppressWarnings("unchecked")
public Object remove(Object key) {
if ( isPutQueueEnabled() ) {
final Object old = readElementByIndex( key );
@ -218,7 +219,6 @@ public class PersistentMap extends AbstractPersistentCollection implements Map {
}
@Override
@SuppressWarnings("unchecked")
public void putAll(Map puts) {
if ( puts.size() > 0 ) {
initialize( true );
@ -230,7 +230,6 @@ public class PersistentMap extends AbstractPersistentCollection implements Map {
}
@Override
@SuppressWarnings("unchecked")
public void clear() {
if ( isClearQueueEnabled() ) {
queueOperation( new Clear() );
@ -245,34 +244,29 @@ public class PersistentMap extends AbstractPersistentCollection implements Map {
}
@Override
@SuppressWarnings("unchecked")
public Set keySet() {
read();
return new SetProxy( map.keySet() );
}
@Override
@SuppressWarnings("unchecked")
public Collection values() {
read();
return new SetProxy( map.values() );
}
@Override
@SuppressWarnings("unchecked")
public Set entrySet() {
read();
return new EntrySetProxy( map.entrySet() );
}
@Override
@SuppressWarnings("unchecked")
public boolean empty() {
return map.isEmpty();
}
@Override
@SuppressWarnings("unchecked")
public String toString() {
read();
return map.toString();
@ -281,7 +275,6 @@ public class PersistentMap extends AbstractPersistentCollection implements Map {
private transient List<Object[]> loadingEntries;
@Override
@SuppressWarnings("unchecked")
public Object readFrom(
ResultSet rs,
CollectionPersister persister,
@ -298,6 +291,30 @@ public class PersistentMap extends AbstractPersistentCollection implements Map {
return element;
}
@Override
public Object readFrom(
RowProcessingState rowProcessingState,
DomainResultAssembler elementAssembler,
DomainResultAssembler indexAssembler,
DomainResultAssembler identifierAssembler,
Object owner) throws HibernateException {
assert elementAssembler != null;
assert indexAssembler != null;
assert identifierAssembler == null;
final Object element = elementAssembler.assemble( rowProcessingState );
if ( element != null ) {
final Object index = indexAssembler.assemble( rowProcessingState );
if ( loadingEntries == null ) {
loadingEntries = new ArrayList<>();
}
loadingEntries.add( new Object[] { index, element } );
}
return element;
}
@Override
@SuppressWarnings("unchecked")
public boolean endRead() {

View File

@ -21,6 +21,8 @@ import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.loader.CollectionAliases;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.RowProcessingState;
import org.hibernate.type.Type;
@ -342,6 +344,27 @@ public class PersistentSet extends AbstractPersistentCollection implements java.
return element;
}
@Override
public Object readFrom(
RowProcessingState rowProcessingState,
DomainResultAssembler elementAssembler,
DomainResultAssembler indexAssembler,
DomainResultAssembler identifierAssembler,
Object owner) throws HibernateException {
assert elementAssembler != null;
assert indexAssembler == null;
assert identifierAssembler == null;
final Object element = elementAssembler.assemble( rowProcessingState );
if ( element != null ) {
//noinspection unchecked
tempList.add( element );
}
return element;
}
@Override
@SuppressWarnings("unchecked")
public void beginRead() {

View File

@ -0,0 +1,84 @@
/*
* 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.collection.internal;
import org.hibernate.MappingException;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.collection.spi.CollectionSemantics;
import org.hibernate.collection.spi.CollectionSemanticsResolver;
import org.hibernate.mapping.Array;
import org.hibernate.mapping.Bag;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.IdentifierBag;
import org.hibernate.mapping.List;
import org.hibernate.mapping.Map;
import org.hibernate.mapping.PrimitiveArray;
import org.hibernate.mapping.Set;
/**
* Standard implementation of CollectionSemanticsResolver
*
* @author Steve Ebersole
*/
public class StandardCollectionSemanticsResolver implements CollectionSemanticsResolver {
/**
* Singleton access
*/
public static final StandardCollectionSemanticsResolver INSTANCE = new StandardCollectionSemanticsResolver();
@Override
public CollectionSemantics resolveRepresentation(Collection bootDescriptor) {
if ( bootDescriptor instanceof PrimitiveArray ) {
throw new NotYetImplementedFor6Exception();
}
if ( bootDescriptor instanceof Array ) {
return StandardArraySemantics.INSTANCE;
}
if ( bootDescriptor instanceof Bag ) {
return StandardBagSemantics.INSTANCE;
}
if ( bootDescriptor instanceof IdentifierBag ) {
return StandardIdentifierBagSemantics.INSTANCE;
}
if ( bootDescriptor instanceof List ) {
return StandardListSemantics.INSTANCE;
}
if ( bootDescriptor instanceof Map ) {
if ( bootDescriptor.isSorted() ) {
return StandardSortedMapSemantics.INSTANCE;
}
if ( bootDescriptor.hasOrder() ) {
return StandardOrderedMapSemantics.INSTANCE;
}
return StandardMapSemantics.INSTANCE;
}
if ( bootDescriptor instanceof Set ) {
if ( bootDescriptor.isSorted() ) {
return StandardSortedSetSemantics.INSTANCE;
}
if ( bootDescriptor.hasOrder() ) {
return StandardOrderedSetSemantics.INSTANCE;
}
return StandardSetSemantics.INSTANCE;
}
throw new MappingException(
"Unexpected org.hibernate.mapping.Collection impl ["
+ bootDescriptor + "]; unknown CollectionSemantics"
);
}
}

View File

@ -9,6 +9,7 @@ package org.hibernate.collection.spi;
import java.util.Iterator;
import java.util.function.Consumer;
import org.hibernate.Incubating;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.metamodel.CollectionClassification;
import org.hibernate.persister.collection.CollectionPersister;
@ -22,6 +23,7 @@ import org.hibernate.persister.collection.CollectionPersister;
* @author Steve Ebersole
* @author Gavin King
*/
@Incubating
public interface CollectionSemantics<C> {
/**
* Get the classification of collections described by this semantic

View File

@ -6,9 +6,12 @@
*/
package org.hibernate.collection.spi;
import org.hibernate.Incubating;
import org.hibernate.mapping.Collection;
/**
* Resolve the collection semantics for the given mapped collection
*
* todo (6.0) ...
*
* Ideally would act as the contract that allows pluggable resolution of
@ -17,6 +20,7 @@ import org.hibernate.mapping.Collection;
*
* @author Steve Ebersole
*/
@Incubating
public interface CollectionSemanticsResolver {
// really need some form of access to the attribute site
CollectionSemantics resolveRepresentation(Collection bootDescriptor);

View File

@ -16,6 +16,8 @@ import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.loader.CollectionAliases;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.RowProcessingState;
import org.hibernate.type.Type;
/**
@ -173,6 +175,13 @@ public interface PersistentCollection {
Object readFrom(ResultSet rs, CollectionPersister role, CollectionAliases descriptor, Object owner)
throws HibernateException, SQLException;
Object readFrom(
RowProcessingState rowProcessingState,
DomainResultAssembler elementAssembler,
DomainResultAssembler indexAssembler,
DomainResultAssembler identifierAssembler,
Object owner) throws HibernateException;
/**
* Get the identifier of the given collection entry. This refers to the collection identifier, not the
* identifier of the (possibly) entity elements. This is only valid for invocation on the

View File

@ -0,0 +1,25 @@
/*
* 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;
import org.hibernate.metamodel.CollectionClassification;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.sql.results.spi.DomainResultCreationState;
/**
* Descriptor for the collection identifier. Only used with {@link CollectionClassification#IDBAG} collections
*
* @author Steve Ebersole
*/
public interface CollectionIdentifierDescriptor {
DomainResult createDomainResult(
NavigablePath collectionPath,
TableGroup tableGroup,
DomainResultCreationState creationState);
}

View File

@ -15,5 +15,5 @@ import org.hibernate.collection.spi.CollectionSemantics;
* @author Steve Ebersole
*/
public interface CollectionMappingType<C> extends MappingType {
CollectionSemantics<C> getCCollectionSemantics();
CollectionSemantics<C> getCollectionSemantics();
}

View File

@ -0,0 +1,48 @@
/*
* 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;
import org.hibernate.sql.results.spi.Fetchable;
/**
* @author Steve Ebersole
*/
public interface CollectionPart extends ModelPart, Fetchable {
enum Nature {
ELEMENT( "{element}" ),
INDEX( "{index}" );
private final String name;
Nature(String name) {
this.name = name;
}
public String getName() {
return name;
}
public static Nature fromName(String name) {
if ( ELEMENT.name.equals( name ) ) {
return ELEMENT;
}
else if ( INDEX.name.equals( name ) ) {
return INDEX;
}
throw new IllegalArgumentException(
"Unrecognized CollectionPart Nature name [" + name
+ "]; expecting `" + ELEMENT.name + "` or `"
+ INDEX.name + "`"
);
}
}
Nature getNature();
ModelPart getPartTypeDescriptor();
}

View File

@ -102,6 +102,7 @@ public class EmbeddableMappingType implements ManagedMappingType {
CompositeType compositeType,
MappingModelCreationProcess creationProcess) {
final String containingTableExpression = valueMapping.getContainingTableExpression();
final List<String> mappedColumnExpressions = valueMapping.getMappedColumnExpressions();
final Type[] subtypes = compositeType.getSubtypes();
@ -196,6 +197,11 @@ public class EmbeddableMappingType implements ManagedMappingType {
throw new NotYetImplementedFor6Exception( getClass() );
}
@Override
public int getNumberOfFetchables() {
return attributeMappings.size();
}
@Override
public void visitFetchables(
Consumer<Fetchable> fetchableConsumer,

View File

@ -14,12 +14,13 @@ import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoinProducer;
import org.hibernate.sql.results.spi.Fetchable;
import org.hibernate.sql.results.spi.FetchableContainer;
/**
* @author Steve Ebersole
*/
public interface EmbeddableValuedModelPart extends ModelPart, FetchableContainer, TableGroupJoinProducer {
public interface EmbeddableValuedModelPart extends ModelPart, Fetchable, FetchableContainer, TableGroupJoinProducer {
EmbeddableMappingType getEmbeddableTypeDescriptor();
/**

View File

@ -0,0 +1,19 @@
/*
* 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;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.sql.results.spi.DomainResultCreationState;
/**
* @author Steve Ebersole
*/
public interface ForeignKeyDescriptor {
DomainResult createDomainResult(NavigablePath collectionPath, TableGroup tableGroup, DomainResultCreationState creationState);
}

View File

@ -6,15 +6,39 @@
*/
package org.hibernate.metamodel.mapping;
import java.util.function.Consumer;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.sql.ast.tree.from.TableGroupJoinProducer;
import org.hibernate.sql.results.spi.Fetchable;
import org.hibernate.sql.results.spi.FetchableContainer;
/**
* @author Steve Ebersole
*/
public interface PluralAttributeMapping extends AttributeMapping, StateArrayContributorMapping {
public interface PluralAttributeMapping
extends AttributeMapping, StateArrayContributorMapping, TableGroupJoinProducer, FetchableContainer {
CollectionPersister getCollectionDescriptor();
ModelPart getValueDescriptor();
ForeignKeyDescriptor getKeyDescriptor();
ModelPart getIndexDescriptor();
CollectionPart getIndexDescriptor();
CollectionPart getElementDescriptor();
CollectionIdentifierDescriptor getIdentifierDescriptor();
@Override
default void visitKeyFetchables(Consumer<Fetchable> fetchableConsumer, EntityMappingType treatTargetType) {
final CollectionPart indexDescriptor = getIndexDescriptor();
if ( indexDescriptor != null ) {
fetchableConsumer.accept( indexDescriptor );
}
}
@Override
default void visitFetchables(Consumer<Fetchable> fetchableConsumer, EntityMappingType treatTargetType) {
fetchableConsumer.accept( getElementDescriptor() );
}
}

View File

@ -13,14 +13,17 @@ import org.hibernate.LockMode;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchTiming;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.sqm.sql.SqlExpressionResolver;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.results.SqlResultsLogger;
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;
@ -36,13 +39,24 @@ import org.hibernate.type.spi.TypeConfiguration;
*
* @author Steve Ebersole
*/
public class BasicValuedCollectionPart implements BasicValuedModelPart {
public class BasicValuedCollectionPart implements CollectionPart, BasicValuedModelPart {
private final CollectionPersister collectionDescriptor;
private final Nature nature;
private final BasicType mapper;
private final BasicValueConverter valueConverter;
private final String tableExpression;
private final String columnExpression;
public BasicValuedCollectionPart(
CollectionPersister collectionDescriptor,
Nature nature,
BasicType mapper,
BasicValueConverter valueConverter,
String tableExpression,
String columnExpression) {
this.collectionDescriptor = collectionDescriptor;
this.nature = nature;
this.mapper = mapper;
this.valueConverter = valueConverter;
@ -50,14 +64,15 @@ public class BasicValuedCollectionPart implements BasicValuedModelPart {
this.columnExpression = columnExpression;
}
enum Nature { ELEMENT, INDEX }
@Override
public Nature getNature() {
return nature;
}
private final Nature nature;
private final BasicType mapper;
private final BasicValueConverter valueConverter;
private final String tableExpression;
private final String columnExpression;
@Override
public BasicType getPartTypeDescriptor() {
return mapper;
}
@Override
public String getContainingTableExpression() {
@ -91,7 +106,9 @@ public class BasicValuedCollectionPart implements BasicValuedModelPart {
return new BasicResult(
sqlSelection.getValuesArrayPosition(),
resultVariable,
getJavaTypeDescriptor()
getJavaTypeDescriptor(),
valueConverter,
navigablePath
);
}
@ -100,9 +117,9 @@ public class BasicValuedCollectionPart implements BasicValuedModelPart {
return exprResolver.resolveSqlSelection(
exprResolver.resolveSqlExpression(
SqlExpressionResolver.createColumnReferenceKey( tableExpression, columnExpression ),
SqlExpressionResolver.createColumnReferenceKey( tableGroup.getPrimaryTableReference(), columnExpression ),
sqlAstProcessingState -> new ColumnReference(
tableGroup.resolveTableReference( tableExpression ).getIdentificationVariable(),
tableGroup.getPrimaryTableReference().getIdentificationVariable(),
columnExpression,
mapper,
creationState.getSqlAstCreationState().getCreationContext().getSessionFactory()
@ -148,6 +165,12 @@ public class BasicValuedCollectionPart implements BasicValuedModelPart {
LockMode lockMode,
String resultVariable,
DomainResultCreationState creationState) {
SqlResultsLogger.INSTANCE.debugf(
"Generating Fetch for collection-part : `%s` -> `%s`",
collectionDescriptor.getRole(),
nature.getName()
);
final SqlSelection sqlSelection = resolveSqlSelection(
creationState.getSqlAstCreationState().getFromClauseAccess().findTableGroup( fetchablePath.getParent() ),
creationState

View File

@ -0,0 +1,83 @@
/*
* 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 org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.CollectionIdentifierDescriptor;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.sqm.sql.SqlAstCreationState;
import org.hibernate.query.sqm.sql.SqlExpressionResolver;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.from.TableGroup;
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.type.BasicType;
/**
* @author Steve Ebersole
*/
public class CollectionIdentifierDescriptorImpl implements CollectionIdentifierDescriptor {
private final CollectionPersister collectionDescriptor;
private final String columnName;
private final BasicType type;
public CollectionIdentifierDescriptorImpl(
CollectionPersister collectionDescriptor,
String columnName,
BasicType type) {
this.collectionDescriptor = collectionDescriptor;
this.columnName = columnName;
this.type = type;
}
@Override
public DomainResult createDomainResult(
NavigablePath collectionPath,
TableGroup tableGroup,
DomainResultCreationState creationState) {
final SqlAstCreationState astCreationState = creationState.getSqlAstCreationState();
final SqlAstCreationContext astCreationContext = astCreationState.getCreationContext();
final SessionFactoryImplementor sessionFactory = astCreationContext.getSessionFactory();
final SqlExpressionResolver sqlExpressionResolver = astCreationState.getSqlExpressionResolver();
final SqlSelection sqlSelection = sqlExpressionResolver.resolveSqlSelection(
sqlExpressionResolver.resolveSqlExpression(
SqlExpressionResolver.createColumnReferenceKey(
tableGroup.getPrimaryTableReference(),
columnName
),
p -> new ColumnReference(
tableGroup.getPrimaryTableReference().getIdentificationVariable(),
columnName,
type,
sessionFactory
)
),
type.getJavaTypeDescriptor(),
sessionFactory.getTypeConfiguration()
);
//noinspection unchecked
return new BasicResult(
sqlSelection.getValuesArrayPosition(),
null,
type.getJavaTypeDescriptor(),
collectionPath
);
}
@Override
public String toString() {
return getClass().getSimpleName() + "(" + collectionDescriptor.getRole() + ")";
}
}

View File

@ -31,6 +31,7 @@ import org.hibernate.query.sqm.sql.SqlExpressionResolver;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.JoinType;
import org.hibernate.sql.ast.spi.SqlAliasBase;
import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
@ -39,7 +40,9 @@ import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.from.CompositeTableGroup;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.from.TableGroupProducer;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.from.TableReferenceCollector;
import org.hibernate.sql.results.internal.domain.composite.CompositeFetch;
import org.hibernate.sql.results.internal.domain.composite.CompositeResult;
import org.hibernate.sql.results.spi.DomainResult;
@ -162,6 +165,7 @@ public class EmbeddedAttributeMapping
this,
fetchParent,
fetchTiming,
getAttributeMetadataAccess().resolveAttributeMetadata( null ).isNullable(),
creationState
);
}
@ -245,8 +249,44 @@ public class EmbeddedAttributeMapping
);
}
@Override
public void applyTableReferences(
SqlAliasBase sqlAliasBase,
JoinType baseJoinType,
TableReferenceCollector collector,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
getEmbeddableTypeDescriptor().visitAttributeMappings(
attrMapping -> {
if ( attrMapping instanceof TableGroupProducer ) {
( (TableGroupProducer) attrMapping ).applyTableReferences(
sqlAliasBase,
baseJoinType,
collector,
sqlExpressionResolver,
creationContext
);
}
else if ( attrMapping.getMappedTypeDescriptor() instanceof TableGroupProducer ) {
( (TableGroupProducer) attrMapping.getMappedTypeDescriptor() ).applyTableReferences(
sqlAliasBase,
baseJoinType,
collector,
sqlExpressionResolver,
creationContext
);
}
}
);
}
@Override
public String getSqlAliasStem() {
return getAttributeName();
}
@Override
public int getNumberOfFetchables() {
return getEmbeddableTypeDescriptor().getNumberOfAttributeMappings();
}
}

View File

@ -0,0 +1,189 @@
/*
* 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.List;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchTiming;
import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.sqm.sql.SqlAstCreationState;
import org.hibernate.query.sqm.sql.SqlExpressionResolver;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.JoinType;
import org.hibernate.sql.ast.spi.SqlAliasBase;
import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.from.TableReferenceCollector;
import org.hibernate.sql.results.internal.domain.composite.CompositeFetch;
import org.hibernate.sql.results.spi.DomainResultCreationState;
import org.hibernate.sql.results.spi.Fetch;
import org.hibernate.sql.results.spi.FetchParent;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* @author Steve Ebersole
*/
public class EmbeddedCollectionPart implements CollectionPart, EmbeddableValuedModelPart {
private final CollectionPersister collectionDescriptor;
private final Nature nature;
private final EmbeddableMappingType embeddableMappingType;
private final String containingTableExpression;
private final SingularAttributeMapping parentInjectionAttribute;
private final List<String> columnExpressions;
private final String sqlAliasStem;
@SuppressWarnings("WeakerAccess")
public EmbeddedCollectionPart(
CollectionPersister collectionDescriptor,
Nature nature,
EmbeddableMappingType embeddableMappingType,
SingularAttributeMapping parentInjectionAttribute,
String containingTableExpression,
List<String> columnExpressions,
String sqlAliasStem) {
this.collectionDescriptor = collectionDescriptor;
this.nature = nature;
this.embeddableMappingType = embeddableMappingType;
this.parentInjectionAttribute = parentInjectionAttribute;
this.containingTableExpression = containingTableExpression;
this.columnExpressions = columnExpressions;
this.sqlAliasStem = sqlAliasStem;
}
@Override
public Nature getNature() {
return nature;
}
@Override
public EmbeddableMappingType getEmbeddableTypeDescriptor() {
return embeddableMappingType;
}
@Override
public EmbeddableMappingType getPartTypeDescriptor() {
return getEmbeddableTypeDescriptor();
}
@Override
public String getContainingTableExpression() {
return containingTableExpression;
}
@Override
public List<String> getMappedColumnExpressions() {
return columnExpressions;
}
@Override
public SingularAttributeMapping getParentInjectionAttributeMapping() {
return parentInjectionAttribute;
}
@Override
public String getFetchableName() {
return getNature().getName();
}
@Override
public FetchStrategy getMappedFetchStrategy() {
return FetchStrategy.IMMEDIATE_JOIN;
}
@Override
public Fetch generateFetch(
FetchParent fetchParent,
NavigablePath fetchablePath,
FetchTiming fetchTiming,
boolean selected,
LockMode lockMode,
String resultVariable,
DomainResultCreationState creationState) {
return new CompositeFetch(
fetchablePath,
this,
fetchParent,
FetchTiming.IMMEDIATE,
false,
creationState
);
}
@Override
public Expression toSqlExpression(
TableGroup tableGroup,
Clause clause,
SqmToSqlAstConverter walker,
SqlAstCreationState sqlAstCreationState) {
throw new NotYetImplementedFor6Exception( getClass() );
}
@Override
public TableGroupJoin createTableGroupJoin(
NavigablePath navigablePath,
TableGroup lhs,
String explicitSourceAlias,
JoinType joinType,
LockMode lockMode,
SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
throw new NotYetImplementedFor6Exception( getClass() );
}
@Override
public void applyTableReferences(
SqlAliasBase sqlAliasBase,
JoinType baseJoinType,
TableReferenceCollector collector,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
throw new NotYetImplementedFor6Exception( getClass() );
}
@Override
public String getSqlAliasStem() {
return sqlAliasStem;
}
@Override
public ModelPart findSubPart(String name, EntityMappingType treatTargetType) {
return getEmbeddableTypeDescriptor().findSubPart( name, treatTargetType );
}
@Override
public void visitSubParts(Consumer<ModelPart> consumer, EntityMappingType treatTargetType) {
getEmbeddableTypeDescriptor().visitSubParts( consumer, treatTargetType );
}
@Override
public JavaTypeDescriptor getJavaTypeDescriptor() {
return getEmbeddableTypeDescriptor().getJavaTypeDescriptor();
}
@Override
public int getNumberOfFetchables() {
return getEmbeddableTypeDescriptor().getNumberOfAttributeMappings();
}
}

View File

@ -0,0 +1,81 @@
/*
* 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 org.hibernate.LockMode;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchTiming;
import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.spi.DomainResultCreationState;
import org.hibernate.sql.results.spi.Fetch;
import org.hibernate.sql.results.spi.FetchParent;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* @author Steve Ebersole
*/
public class EntityCollectionPart implements CollectionPart, EntityValuedModelPart {
private final Nature nature;
private final EntityMappingType entityMappingType;
@SuppressWarnings("WeakerAccess")
public EntityCollectionPart(Nature nature, EntityMappingType entityMappingType) {
this.nature = nature;
this.entityMappingType = entityMappingType;
}
@Override
public Nature getNature() {
return nature;
}
@Override
public EntityMappingType getPartTypeDescriptor() {
return getEntityMappingType();
}
@Override
public EntityMappingType getEntityMappingType() {
return entityMappingType;
}
@Override
public JavaTypeDescriptor getJavaTypeDescriptor() {
return getEntityMappingType().getJavaTypeDescriptor();
}
@Override
public String getFetchableName() {
return nature.getName();
}
@Override
public FetchStrategy getMappedFetchStrategy() {
return FetchStrategy.IMMEDIATE_JOIN;
}
@Override
public Fetch generateFetch(
FetchParent fetchParent,
NavigablePath fetchablePath,
FetchTiming fetchTiming,
boolean selected,
LockMode lockMode,
String resultVariable,
DomainResultCreationState creationState) {
throw new NotYetImplementedFor6Exception( getClass() );
}
@Override
public int getNumberOfFetchables() {
return entityMappingType.getNumberOfFetchables();
}
}

View File

@ -7,6 +7,10 @@
package org.hibernate.metamodel.mapping.internal;
import java.io.Serializable;
import java.util.Iterator;
import java.util.List;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.function.Consumer;
import org.hibernate.LockMode;
@ -16,36 +20,35 @@ import org.hibernate.collection.internal.StandardArraySemantics;
import org.hibernate.collection.internal.StandardBagSemantics;
import org.hibernate.collection.internal.StandardIdentifierBagSemantics;
import org.hibernate.collection.internal.StandardListSemantics;
import org.hibernate.collection.internal.StandardMapSemantics;
import org.hibernate.collection.internal.StandardOrderedMapSemantics;
import org.hibernate.collection.internal.StandardOrderedSetSemantics;
import org.hibernate.collection.internal.StandardSetSemantics;
import org.hibernate.collection.internal.StandardSortedMapSemantics;
import org.hibernate.collection.internal.StandardSortedSetSemantics;
import org.hibernate.collection.spi.CollectionSemantics;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.mapping.Array;
import org.hibernate.mapping.Bag;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.mapping.BasicValue;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.IdentifierBag;
import org.hibernate.mapping.List;
import org.hibernate.mapping.Map;
import org.hibernate.mapping.IndexedCollection;
import org.hibernate.mapping.OneToMany;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.PrimitiveArray;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.Set;
import org.hibernate.mapping.Selectable;
import org.hibernate.mapping.ToOne;
import org.hibernate.mapping.Value;
import org.hibernate.metamodel.CollectionClassification;
import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.CollectionIdentifierDescriptor;
import org.hibernate.metamodel.mapping.CollectionMappingType;
import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.ManagedMappingType;
import org.hibernate.metamodel.mapping.MappingType;
@ -54,15 +57,19 @@ import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.StateArrayContributorMetadata;
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
import org.hibernate.metamodel.spi.DomainMetamodel;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.collection.SQLLoadableCollection;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Joinable;
import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.persister.walking.internal.FetchStrategyHelper;
import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.sqm.sql.SqlExpressionResolver;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.spi.SqlAliasStemHelper;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Expression;
@ -76,6 +83,7 @@ import org.hibernate.sql.results.spi.Fetch;
import org.hibernate.sql.results.spi.FetchParent;
import org.hibernate.type.BasicType;
import org.hibernate.type.CompositeType;
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;
@ -622,75 +630,152 @@ public class MappingModelCreationHelper {
final Collection bootValueMapping = (Collection) bootProperty.getValue();
final RuntimeModelCreationContext creationContext = creationProcess.getCreationContext();
final CollectionPersister collectionDescriptor = creationContext.getDomainModel().findCollectionDescriptor( bootValueMapping.getRole() );
final SessionFactoryImplementor sessionFactory = creationContext.getSessionFactory();
final Dialect dialect = sessionFactory.getJdbcServices().getJdbcEnvironment().getDialect();
final DomainMetamodel domainModel = creationContext.getDomainModel();
final CollectionPersister collectionDescriptor = domainModel.findCollectionDescriptor( bootValueMapping.getRole() );
assert collectionDescriptor != null;
tableExpression = ( (Joinable) collectionDescriptor ).getTableName();
final String sqlAliasStem = SqlAliasStemHelper.INSTANCE.generateStemFromAttributeName( bootProperty.getName() );
final CollectionMappingType<?> collectionMappingType;
final JavaTypeDescriptorRegistry jtdRegistry = creationContext.getJavaTypeDescriptorRegistry();
if ( bootValueMapping instanceof Array ) {
if ( bootValueMapping instanceof PrimitiveArray ) {
throw new NotYetImplementedFor6Exception();
}
else {
final ForeignKeyDescriptor keyDescriptor = interpretKeyDescriptor(
bootProperty,
bootValueMapping,
dialect,
creationProcess
);
final CollectionPart elementDescriptor = interpretElement(
bootValueMapping,
tableExpression,
collectionDescriptor,
sqlAliasStem,
dialect,
creationProcess
);
final CollectionPart indexDescriptor;
CollectionIdentifierDescriptor identifierDescriptor = null;
final CollectionSemantics collectionSemantics = collectionDescriptor.getCollectionSemantics();
switch ( collectionSemantics.getCollectionClassification() ) {
case ARRAY: {
collectionMappingType = new CollectionMappingTypeImpl(
jtdRegistry.getDescriptor( Object[].class ),
StandardArraySemantics.INSTANCE
);
final BasicValue index = (BasicValue) ( (IndexedCollection) bootValueMapping ).getIndex();
indexDescriptor = new BasicValuedCollectionPart(
collectionDescriptor,
CollectionPart.Nature.INDEX,
creationContext.getTypeConfiguration().getBasicTypeForJavaType( Integer.class ),
// no converter
null,
tableExpression,
index.getColumnIterator().next().getText( dialect )
);
break;
}
}
else if ( bootValueMapping instanceof Bag ) {
case BAG: {
collectionMappingType = new CollectionMappingTypeImpl(
jtdRegistry.getDescriptor( java.util.Collection.class ),
StandardBagSemantics.INSTANCE
);
indexDescriptor = null;
break;
}
else if ( bootValueMapping instanceof IdentifierBag ) {
case IDBAG: {
collectionMappingType = new CollectionMappingTypeImpl(
jtdRegistry.getDescriptor( java.util.Collection.class ),
StandardIdentifierBagSemantics.INSTANCE
);
indexDescriptor = null;
assert collectionDescriptor instanceof SQLLoadableCollection;
final SQLLoadableCollection loadableCollection = (SQLLoadableCollection) collectionDescriptor;
final String identifierColumnName = loadableCollection.getIdentifierColumnName();
assert identifierColumnName != null;
identifierDescriptor = new CollectionIdentifierDescriptorImpl(
collectionDescriptor,
identifierColumnName,
(BasicType) loadableCollection.getIdentifierType()
);
break;
}
else if ( bootValueMapping instanceof List ) {
case LIST: {
final BasicValue index = (BasicValue) ( (IndexedCollection) bootValueMapping ).getIndex();
indexDescriptor = new BasicValuedCollectionPart(
collectionDescriptor,
CollectionPart.Nature.INDEX,
creationContext.getTypeConfiguration().getBasicTypeForJavaType( Integer.class ),
// no converter
null,
tableExpression,
index.getColumnIterator().next().getText( dialect )
);
collectionMappingType = new CollectionMappingTypeImpl(
jtdRegistry.getDescriptor( java.util.List.class ),
StandardListSemantics.INSTANCE
);
break;
}
else if ( bootValueMapping instanceof Map ) {
if ( bootValueMapping.isSorted() ) {
case MAP:
case ORDERED_MAP:
case SORTED_MAP: {
final Class<? extends java.util.Map> mapJavaType = collectionSemantics.getCollectionClassification() == CollectionClassification.SORTED_MAP
? SortedMap.class
: java.util.Map.class;
collectionMappingType = new CollectionMappingTypeImpl(
jtdRegistry.getDescriptor( java.util.SortedMap.class ),
StandardSortedMapSemantics.INSTANCE
jtdRegistry.getDescriptor( mapJavaType ),
collectionSemantics
);
indexDescriptor = interpretMapKey(
bootValueMapping,
collectionDescriptor,
tableExpression,
sqlAliasStem,
dialect,
creationProcess
);
break;
}
case SET:
case ORDERED_SET:
case SORTED_SET: {
final Class<? extends java.util.Set> setJavaType = collectionSemantics.getCollectionClassification() == CollectionClassification.SORTED_MAP
? SortedSet.class
: java.util.Set.class;
collectionMappingType = new CollectionMappingTypeImpl(
jtdRegistry.getDescriptor( setJavaType ),
collectionSemantics
);
indexDescriptor = null;
break;
}
default: {
throw new MappingException(
"Unexpected CollectionClassification : " + collectionSemantics.getCollectionClassification()
);
}
else {
collectionMappingType = new CollectionMappingTypeImpl(
jtdRegistry.getDescriptor( java.util.Map.class ),
bootValueMapping.hasOrder()
? StandardOrderedMapSemantics.INSTANCE
: StandardMapSemantics.INSTANCE
);
}
}
else if ( bootValueMapping instanceof Set ) {
if ( bootValueMapping.isSorted() ) {
collectionMappingType = new CollectionMappingTypeImpl(
jtdRegistry.getDescriptor( java.util.SortedSet.class ),
StandardSortedSetSemantics.INSTANCE
);
}
else {
collectionMappingType = new CollectionMappingTypeImpl(
jtdRegistry.getDescriptor( java.util.Set.class ),
bootValueMapping.hasOrder()
? StandardOrderedSetSemantics.INSTANCE
: StandardSetSemantics.INSTANCE
);
}
}
else {
throw new MappingException( "Unexpected org.hibernate.mapping.Collection impl : " + bootValueMapping );
}
final StateArrayContributorMetadata contributorMetadata = new StateArrayContributorMetadata() {
@ -733,7 +818,7 @@ public class MappingModelCreationHelper {
final FetchStyle style = FetchStrategyHelper.determineFetchStyleByMetadata(
( (OuterJoinLoadable) declaringType ).getFetchMode( stateArrayPosition ),
collectionDescriptor.getCollectionType(),
creationContext.getSessionFactory()
sessionFactory
);
return new PluralAttributeMappingImpl(
@ -742,15 +827,15 @@ public class MappingModelCreationHelper {
entityMappingType -> contributorMetadata,
collectionMappingType,
stateArrayPosition,
tableExpression,
attrColumnExpressions,
null,
null,
keyDescriptor,
elementDescriptor,
indexDescriptor,
identifierDescriptor,
new FetchStrategy(
FetchStrategyHelper.determineFetchTiming(
style,
collectionDescriptor.getCollectionType(),
creationContext.getSessionFactory()
sessionFactory
),
style
),
@ -760,6 +845,156 @@ public class MappingModelCreationHelper {
);
}
private static ForeignKeyDescriptor interpretKeyDescriptor(
Property bootProperty,
Collection bootValueMapping,
Dialect dialect,
MappingModelCreationProcess creationProcess) {
final Type keyType = bootValueMapping.getKey().getType();
if ( keyType instanceof BasicType ) {
assert bootValueMapping.getKey().getColumnSpan() == 1;
return new SimpleForeignKeyDescriptor(
bootValueMapping.getKey().getColumnIterator().next().getText( dialect ),
(BasicType) keyType
);
}
throw new NotYetImplementedFor6Exception(
"Support for composite collection foreign-keys not yet implemented: " + bootValueMapping.getRole()
);
}
private static CollectionPart interpretMapKey(
Collection bootValueMapping,
CollectionPersister collectionDescriptor,
String tableExpression,
String sqlAliasStem,
Dialect dialect,
MappingModelCreationProcess creationProcess) {
assert bootValueMapping instanceof IndexedCollection;
final IndexedCollection indexedCollection = (IndexedCollection) bootValueMapping;
final Value bootMapKeyDescriptor = indexedCollection.getIndex();
if ( bootMapKeyDescriptor instanceof BasicValue ) {
final BasicValue basicValue = (BasicValue) bootMapKeyDescriptor;
return new BasicValuedCollectionPart(
collectionDescriptor,
CollectionPart.Nature.INDEX,
basicValue.resolve().getResolvedBasicType(),
basicValue.resolve().getValueConverter(),
tableExpression,
basicValue.getColumnIterator().next().getText( dialect )
);
}
if ( bootMapKeyDescriptor instanceof Component ) {
final Component component = (Component) bootMapKeyDescriptor;
final CompositeType compositeType = (CompositeType) component.getType();
final List<String> columnExpressions = CollectionHelper.arrayList( component.getColumnSpan() );
final Iterator<Selectable> columnIterator = component.getColumnIterator();
while ( columnIterator.hasNext() ) {
columnExpressions.add( columnIterator.next().getText( dialect ) );
}
final EmbeddableMappingType mappingType = EmbeddableMappingType.from(
component,
compositeType,
inflightDescriptor -> new EmbeddedCollectionPart(
collectionDescriptor,
CollectionPart.Nature.INDEX,
inflightDescriptor,
// parent-injection
null,
tableExpression,
columnExpressions,
sqlAliasStem
),
creationProcess
);
return (CollectionPart) mappingType.getEmbeddedValueMapping();
}
throw new NotYetImplementedFor6Exception(
"Support for plural attributes with index type [" + bootMapKeyDescriptor + "] not yet implemented"
);
}
private static CollectionPart interpretElement(
Collection bootDescriptor,
String tableExpression,
CollectionPersister collectionDescriptor,
String sqlAliasStem,
Dialect dialect,
MappingModelCreationProcess creationProcess) {
final Value element = bootDescriptor.getElement();
if ( element instanceof BasicValue ) {
final BasicValue basicElement = (BasicValue) element;
return new BasicValuedCollectionPart(
collectionDescriptor,
CollectionPart.Nature.ELEMENT,
basicElement.resolve().getResolvedBasicType(),
basicElement.resolve().getValueConverter(),
tableExpression,
basicElement.getColumnIterator().next().getText( dialect )
);
}
if ( element instanceof Component ) {
final Component component = (Component) element;
final CompositeType compositeType = (CompositeType) collectionDescriptor.getElementType();
final List<String> columnExpressions = CollectionHelper.arrayList( component.getColumnSpan() );
final Iterator<Selectable> columnIterator = component.getColumnIterator();
while ( columnIterator.hasNext() ) {
columnExpressions.add( columnIterator.next().getText( dialect ) );
}
final EmbeddableMappingType mappingType = EmbeddableMappingType.from(
component,
compositeType,
embeddableMappingType -> new EmbeddedCollectionPart(
collectionDescriptor,
CollectionPart.Nature.ELEMENT,
embeddableMappingType,
// parent-injection
null,
tableExpression,
columnExpressions,
sqlAliasStem
),
creationProcess
);
return (CollectionPart) mappingType.getEmbeddedValueMapping();
}
if ( element instanceof OneToMany || element instanceof ToOne ) {
final EntityPersister associatedEntity;
if ( element instanceof OneToMany ) {
associatedEntity = creationProcess.getEntityPersister(
( (OneToMany) element ).getReferencedEntityName()
);
}
else {
// many-to-many
associatedEntity = creationProcess.getEntityPersister(
( (ToOne) element ).getReferencedEntityName()
);
}
return new EntityCollectionPart( CollectionPart.Nature.ELEMENT, associatedEntity );
}
throw new NotYetImplementedFor6Exception(
"Support for plural attributes with element type [" + element + "] not yet implemented"
);
}
private static class CollectionMappingTypeImpl implements CollectionMappingType {
private final JavaTypeDescriptor collectionJtd;
private final CollectionSemantics semantics;
@ -773,7 +1008,7 @@ public class MappingModelCreationHelper {
}
@Override
public CollectionSemantics getCCollectionSemantics() {
public CollectionSemantics getCollectionSemantics() {
return semantics;
}

View File

@ -6,12 +6,17 @@
*/
package org.hibernate.metamodel.mapping.internal;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.metamodel.mapping.CollectionIdentifierDescriptor;
import org.hibernate.metamodel.mapping.CollectionMappingType;
import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.ManagedMappingType;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
@ -20,7 +25,18 @@ import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.sqm.sql.SqlAstCreationState;
import org.hibernate.query.sqm.sql.SqlExpressionResolver;
import org.hibernate.sql.ast.JoinType;
import org.hibernate.sql.ast.spi.SqlAliasBase;
import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator;
import org.hibernate.sql.ast.spi.SqlAliasStemHelper;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupBuilder;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.from.TableReferenceCollector;
import org.hibernate.sql.results.internal.domain.collection.DelayedCollectionFetch;
import org.hibernate.sql.results.internal.domain.collection.EagerCollectionFetch;
import org.hibernate.sql.results.spi.DomainResultCreationState;
import org.hibernate.sql.results.spi.Fetch;
import org.hibernate.sql.results.spi.FetchParent;
@ -33,17 +49,18 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
private final PropertyAccess propertyAccess;
private final StateArrayContributorMetadataAccess stateArrayContributorMetadataAccess;
private final ForeignKeyDescriptor fkDescriptor;
private final CollectionPart elementDescriptor;
private final CollectionPart indexDescriptor;
private final CollectionIdentifierDescriptor identifierDescriptor;
private final FetchStrategy fetchStrategy;
private final String tableExpression;
private final String[] attrColumnExpressions;
private final ModelPart elementDescriptor;
private final ModelPart indexDescriptor;
private final CascadeStyle cascadeStyle;
private final CollectionPersister collectionDescriptor;
private final String sqlAliasStem;
@SuppressWarnings("WeakerAccess")
public PluralAttributeMappingImpl(
String attributeName,
@ -51,10 +68,10 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
StateArrayContributorMetadataAccess stateArrayContributorMetadataAccess,
CollectionMappingType collectionMappingType,
int stateArrayPosition,
String tableExpression,
String[] attrColumnExpressions,
ModelPart elementDescriptor,
ModelPart indexDescriptor,
ForeignKeyDescriptor fkDescriptor,
CollectionPart elementDescriptor,
CollectionPart indexDescriptor,
CollectionIdentifierDescriptor identifierDescriptor,
FetchStrategy fetchStrategy,
CascadeStyle cascadeStyle,
ManagedMappingType declaringType,
@ -63,36 +80,47 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
this.propertyAccess = propertyAccess;
this.stateArrayContributorMetadataAccess = stateArrayContributorMetadataAccess;
this.stateArrayPosition = stateArrayPosition;
this.tableExpression = tableExpression;
this.attrColumnExpressions = attrColumnExpressions;
this.fkDescriptor = fkDescriptor;
this.elementDescriptor = elementDescriptor;
this.indexDescriptor = indexDescriptor;
this.identifierDescriptor = identifierDescriptor;
this.fetchStrategy = fetchStrategy;
this.cascadeStyle = cascadeStyle;
this.collectionDescriptor = collectionDescriptor;
}
this.sqlAliasStem = SqlAliasStemHelper.INSTANCE.generateStemFromAttributeName( attributeName );
}
@Override
public CollectionMappingType getMappedTypeDescriptor() {
return (CollectionMappingType) super.getMappedTypeDescriptor();
}
@Override
public ForeignKeyDescriptor getKeyDescriptor() {
return fkDescriptor;
}
@Override
public CollectionPersister getCollectionDescriptor() {
return collectionDescriptor;
}
@Override
public ModelPart getValueDescriptor() {
public CollectionPart getElementDescriptor() {
return elementDescriptor;
}
@Override
public ModelPart getIndexDescriptor() {
public CollectionPart getIndexDescriptor() {
return indexDescriptor;
}
@Override
public CollectionIdentifierDescriptor getIdentifierDescriptor() {
return identifierDescriptor;
}
@Override
public int getStateArrayPosition() {
return stateArrayPosition;
@ -128,8 +156,119 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
String resultVariable,
DomainResultCreationState creationState) {
final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState();
final TableGroup collectionTableGroup = sqlAstCreationState.getFromClauseAccess().getTableGroup( fetchablePath );
throw new NotYetImplementedFor6Exception( getClass() );
if ( fetchTiming == FetchTiming.IMMEDIATE || selected ) {
final TableGroup collectionTableGroup = sqlAstCreationState.getFromClauseAccess().resolveTableGroup(
fetchablePath,
p -> {
final TableGroupJoin tableGroupJoin = createTableGroupJoin(
fetchablePath,
sqlAstCreationState.getFromClauseAccess().getTableGroup( fetchParent.getNavigablePath() ),
null,
JoinType.LEFT,
lockMode,
creationState.getSqlAliasBaseManager(),
creationState.getSqlAstCreationState().getSqlExpressionResolver(),
creationState.getSqlAstCreationState().getCreationContext()
);
return tableGroupJoin.getJoinedGroup();
}
);
return new EagerCollectionFetch(
fetchablePath,
this,
fkDescriptor.createDomainResult( fetchablePath, collectionTableGroup, creationState ),
getAttributeMetadataAccess().resolveAttributeMetadata( null ).isNullable(),
fetchParent,
creationState
);
}
return new DelayedCollectionFetch(
fetchablePath,
this,
true,
fetchParent
);
}
@Override
public String getSqlAliasStem() {
return sqlAliasStem;
}
@Override
public TableGroupJoin createTableGroupJoin(
NavigablePath navigablePath,
TableGroup lhs,
String explicitSourceAlias,
JoinType joinType,
LockMode lockMode,
SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
final String aliasRoot = explicitSourceAlias == null ? sqlAliasStem : explicitSourceAlias;
final SqlAliasBase sqlAliasBase = aliasBaseGenerator.createSqlAliasBase( aliasRoot );
final TableGroupBuilder tableGroupBuilder = TableGroupBuilder.builder(
navigablePath,
this,
lockMode,
sqlAliasBase,
creationContext.getSessionFactory()
);
applyTableReferences(
sqlAliasBase,
joinType,
tableGroupBuilder,
sqlExpressionResolver,
creationContext
);
return new TableGroupJoin( navigablePath, joinType, tableGroupBuilder.build() );
}
@Override
public void applyTableReferences(
SqlAliasBase sqlAliasBase,
JoinType baseJoinType,
TableReferenceCollector collector,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
getCollectionDescriptor().applyTableReferences( sqlAliasBase, baseJoinType, collector, sqlExpressionResolver, creationContext );
}
@Override
public ModelPart findSubPart(String name, EntityMappingType treatTargetType) {
final CollectionPart.Nature nature = CollectionPart.Nature.fromName( name );
if ( nature == CollectionPart.Nature.ELEMENT ) {
return elementDescriptor;
}
else if ( nature == CollectionPart.Nature.INDEX ) {
return indexDescriptor;
}
return null;
}
@Override
public void visitSubParts(Consumer<ModelPart> consumer, EntityMappingType treatTargetType) {
consumer.accept( elementDescriptor );
if ( indexDescriptor != null ) {
consumer.accept( indexDescriptor );
}
}
@Override
public int getNumberOfFetchables() {
return indexDescriptor == null ? 1 : 2;
}
@Override
public String toString() {
return "PluralAttribute(" + getCollectionDescriptor().getRole() + ")";
}
}

View File

@ -0,0 +1,64 @@
/*
* 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 org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.sqm.sql.SqlAstCreationState;
import org.hibernate.query.sqm.sql.SqlExpressionResolver;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.results.internal.domain.basic.BasicResult;
import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.sql.results.spi.DomainResultCreationState;
/**
* @author Steve Ebersole
*/
public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor {
private final String keyColumnExpression;
private final JdbcMapping jdbcMapping;
public SimpleForeignKeyDescriptor(String keyColumnExpression, JdbcMapping jdbcMapping) {
this.keyColumnExpression = keyColumnExpression;
this.jdbcMapping = jdbcMapping;
}
@Override
public DomainResult createDomainResult(
NavigablePath collectionPath,
TableGroup tableGroup,
DomainResultCreationState creationState) {
final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState();
final SqlExpressionResolver sqlExpressionResolver = sqlAstCreationState.getSqlExpressionResolver();
final SqlSelection sqlSelection = sqlExpressionResolver.resolveSqlSelection(
sqlExpressionResolver.resolveSqlExpression(
SqlExpressionResolver.createColumnReferenceKey(
tableGroup.getPrimaryTableReference(),
keyColumnExpression
),
s -> new ColumnReference(
tableGroup.getPrimaryTableReference().getIdentificationVariable(),
keyColumnExpression,
jdbcMapping,
creationState.getSqlAstCreationState().getCreationContext().getSessionFactory()
)
),
jdbcMapping.getJavaTypeDescriptor(),
sqlAstCreationState.getCreationContext().getDomainModel().getTypeConfiguration()
);
//noinspection unchecked
return new BasicResult(
sqlSelection.getValuesArrayPosition(),
null,
jdbcMapping.getJavaTypeDescriptor()
);
}
}

View File

@ -7,12 +7,12 @@
package org.hibernate.metamodel.mapping.internal;
import org.hibernate.LockMode;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchTiming;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
import org.hibernate.metamodel.mapping.ManagedMappingType;
import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.query.NavigablePath;
@ -29,7 +29,7 @@ public class SingularAssociationAttributeMapping extends AbstractSingularAttribu
int stateArrayPosition,
StateArrayContributorMetadataAccess attributeMetadataAccess,
FetchStrategy mappedFetchStrategy,
MappingType type,
EntityMappingType type,
ManagedMappingType declaringType,
PropertyAccess propertyAccess) {
super(
@ -43,9 +43,14 @@ public class SingularAssociationAttributeMapping extends AbstractSingularAttribu
);
}
@Override
public EntityMappingType getMappedTypeDescriptor() {
return (EntityMappingType) super.getMappedTypeDescriptor();
}
@Override
public EntityMappingType getEntityMappingType() {
return null;
return getMappedTypeDescriptor();
}
@Override
@ -57,6 +62,11 @@ public class SingularAssociationAttributeMapping extends AbstractSingularAttribu
LockMode lockMode,
String resultVariable,
DomainResultCreationState creationState) {
return null;
throw new NotYetImplementedFor6Exception( getClass() );
}
@Override
public int getNumberOfFetchables() {
return getEntityMappingType().getNumberOfFetchables();
}
}

View File

@ -16,7 +16,6 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import org.hibernate.AssertionFailure;
import org.hibernate.FetchMode;
@ -33,6 +32,7 @@ import org.hibernate.cache.spi.entry.CacheEntryStructure;
import org.hibernate.cache.spi.entry.StructuredCollectionCacheEntry;
import org.hibernate.cache.spi.entry.StructuredMapCacheEntry;
import org.hibernate.cache.spi.entry.UnstructuredCacheEntry;
import org.hibernate.collection.spi.CollectionSemantics;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.batch.internal.BasicBatchKey;
@ -56,6 +56,7 @@ import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.jdbc.Expectation;
import org.hibernate.jdbc.Expectations;
import org.hibernate.loader.collection.CollectionInitializer;
import org.hibernate.mapping.BasicValue;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Formula;
@ -64,9 +65,9 @@ import org.hibernate.mapping.IndexedCollection;
import org.hibernate.mapping.List;
import org.hibernate.mapping.Selectable;
import org.hibernate.mapping.Table;
import org.hibernate.mapping.Value;
import org.hibernate.metadata.CollectionMetadata;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.PropertyMapping;
@ -84,18 +85,23 @@ import org.hibernate.persister.walking.spi.CompositeCollectionElementDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition;
import org.hibernate.persister.walking.spi.EntityDefinition;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.query.sqm.sql.SqlExpressionResolver;
import org.hibernate.sql.Alias;
import org.hibernate.sql.SelectFragment;
import org.hibernate.sql.SimpleSelect;
import org.hibernate.sql.Template;
import org.hibernate.sql.ast.JoinType;
import org.hibernate.sql.ast.spi.SqlAliasBase;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.from.TableReferenceCollector;
import org.hibernate.type.AnyType;
import org.hibernate.type.AssociationType;
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.JavaTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration;
import org.jboss.logging.Logger;
@ -234,10 +240,26 @@ public abstract class AbstractCollectionPersister
private final Comparator comparator;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// "mapping model"
private final CollectionSemantics collectionSemantics;
private final BasicValueConverter elementConverter;
private final BasicValueConverter indexConverter;
// temprary
private final BasicType convertedElementType;
private final BasicType convertedIndexType;
public AbstractCollectionPersister(
Collection collectionBinding,
Collection collectionBootDescriptor,
CollectionDataAccess cacheAccessStrategy,
PersisterCreationContext creationContext) throws MappingException, CacheException {
final Value elementBootDescriptor = collectionBootDescriptor.getElement();
final Value indexBootDescriptor = collectionBootDescriptor instanceof IndexedCollection
? ( (IndexedCollection) collectionBootDescriptor ).getIndex()
: null;
final Database database = creationContext.getMetadata().getDatabase();
final JdbcEnvironment jdbcEnvironment = database.getJdbcEnvironment();
@ -245,7 +267,7 @@ public abstract class AbstractCollectionPersister
this.factory = creationContext.getSessionFactory();
this.cacheAccessStrategy = cacheAccessStrategy;
if ( factory.getSessionFactoryOptions().isStructuredCacheEntriesEnabled() ) {
cacheEntryStructure = collectionBinding.isMap()
cacheEntryStructure = collectionBootDescriptor.isMap()
? StructuredMapCacheEntry.INSTANCE
: StructuredCollectionCacheEntry.INSTANCE;
}
@ -255,54 +277,54 @@ public abstract class AbstractCollectionPersister
dialect = factory.getDialect();
sqlExceptionHelper = factory.getSQLExceptionHelper();
collectionType = collectionBinding.getCollectionType();
navigableRole = new NavigableRole( collectionBinding.getRole() );
entityName = collectionBinding.getOwnerEntityName();
collectionType = collectionBootDescriptor.getCollectionType();
navigableRole = new NavigableRole( collectionBootDescriptor.getRole() );
entityName = collectionBootDescriptor.getOwnerEntityName();
ownerPersister = factory.getEntityPersister( entityName );
queryLoaderName = collectionBinding.getLoaderName();
isMutable = collectionBinding.isMutable();
mappedByProperty = collectionBinding.getMappedByProperty();
queryLoaderName = collectionBootDescriptor.getLoaderName();
isMutable = collectionBootDescriptor.isMutable();
mappedByProperty = collectionBootDescriptor.getMappedByProperty();
Table table = collectionBinding.getCollectionTable();
fetchMode = collectionBinding.getElement().getFetchMode();
elementType = collectionBinding.getElement().getType();
Table table = collectionBootDescriptor.getCollectionTable();
fetchMode = elementBootDescriptor.getFetchMode();
elementType = elementBootDescriptor.getType();
// isSet = collectionBinding.isSet();
// isSorted = collectionBinding.isSorted();
isPrimitiveArray = collectionBinding.isPrimitiveArray();
isArray = collectionBinding.isArray();
subselectLoadable = collectionBinding.isSubselectLoadable();
isPrimitiveArray = collectionBootDescriptor.isPrimitiveArray();
isArray = collectionBootDescriptor.isArray();
subselectLoadable = collectionBootDescriptor.isSubselectLoadable();
qualifiedTableName = determineTableName( table, jdbcEnvironment );
int spacesSize = 1 + collectionBinding.getSynchronizedTables().size();
int spacesSize = 1 + collectionBootDescriptor.getSynchronizedTables().size();
spaces = new String[spacesSize];
spaces[0] = qualifiedTableName;
Iterator iter = collectionBinding.getSynchronizedTables().iterator();
Iterator iter = collectionBootDescriptor.getSynchronizedTables().iterator();
for ( int i = 1; i < spacesSize; i++ ) {
spaces[i] = (String) iter.next();
}
sqlWhereString = StringHelper.isNotEmpty( collectionBinding.getWhere() ) ? "( " + collectionBinding.getWhere() + ") " : null;
sqlWhereString = StringHelper.isNotEmpty( collectionBootDescriptor.getWhere() ) ? "( " + collectionBootDescriptor.getWhere() + ") " : null;
hasWhere = sqlWhereString != null;
sqlWhereStringTemplate = hasWhere ?
Template.renderWhereStringTemplate( sqlWhereString, dialect, factory.getSqlFunctionRegistry() ) :
null;
hasOrphanDelete = collectionBinding.hasOrphanDelete();
hasOrphanDelete = collectionBootDescriptor.hasOrphanDelete();
int batch = collectionBinding.getBatchSize();
int batch = collectionBootDescriptor.getBatchSize();
if ( batch == -1 ) {
batch = factory.getSessionFactoryOptions().getDefaultBatchFetchSize();
}
batchSize = batch;
isVersioned = collectionBinding.isOptimisticLocked();
isVersioned = collectionBootDescriptor.isOptimisticLocked();
// KEY
keyType = collectionBinding.getKey().getType();
iter = collectionBinding.getKey().getColumnIterator();
int keySpan = collectionBinding.getKey().getColumnSpan();
keyType = collectionBootDescriptor.getKey().getType();
iter = collectionBootDescriptor.getKey().getColumnIterator();
int keySpan = collectionBootDescriptor.getKey().getColumnSpan();
keyColumnNames = new String[keySpan];
keyColumnAliases = new String[keySpan];
int k = 0;
@ -328,7 +350,7 @@ public abstract class AbstractCollectionPersister
elementPersister = null;
}
int elementSpan = collectionBinding.getElement().getColumnSpan();
int elementSpan = elementBootDescriptor.getColumnSpan();
elementColumnAliases = new String[elementSpan];
elementColumnNames = new String[elementSpan];
elementColumnWriters = new String[elementSpan];
@ -341,13 +363,13 @@ public abstract class AbstractCollectionPersister
elementColumnIsInPrimaryKey = new boolean[elementSpan];
boolean isPureFormula = true;
boolean hasNotNullableColumns = false;
boolean oneToMany = collectionBinding.isOneToMany();
boolean oneToMany = collectionBootDescriptor.isOneToMany();
boolean[] columnInsertability = null;
if ( !oneToMany ) {
columnInsertability = collectionBinding.getElement().getColumnInsertability();
columnInsertability = elementBootDescriptor.getColumnInsertability();
}
int j = 0;
iter = collectionBinding.getElement().getColumnIterator();
iter = elementBootDescriptor.getColumnIterator();
while ( iter.hasNext() ) {
Selectable selectable = (Selectable) iter.next();
elementColumnAliases[j] = selectable.getAlias( dialect, table );
@ -390,10 +412,10 @@ public abstract class AbstractCollectionPersister
// INDEX AND ROW SELECT
hasIndex = collectionBinding.isIndexed();
hasIndex = collectionBootDescriptor.isIndexed();
if ( hasIndex ) {
// NativeSQL: collect index column and auto-aliases
IndexedCollection indexedCollection = (IndexedCollection) collectionBinding;
IndexedCollection indexedCollection = (IndexedCollection) collectionBootDescriptor;
indexType = indexedCollection.getIndex().getType();
int indexSpan = indexedCollection.getIndex().getColumnSpan();
boolean[] indexColumnInsertability = indexedCollection.getIndex().getColumnInsertability();
@ -440,12 +462,12 @@ public abstract class AbstractCollectionPersister
baseIndex = 0;
}
hasIdentifier = collectionBinding.isIdentified();
hasIdentifier = collectionBootDescriptor.isIdentified();
if ( hasIdentifier ) {
if ( collectionBinding.isOneToMany() ) {
if ( collectionBootDescriptor.isOneToMany() ) {
throw new MappingException( "one-to-many collections with identifiers are not supported" );
}
IdentifierCollection idColl = (IdentifierCollection) collectionBinding;
IdentifierCollection idColl = (IdentifierCollection) collectionBootDescriptor;
identifierType = idColl.getIdentifier().getType();
iter = idColl.getIdentifier().getColumnIterator();
Column col = (Column) iter.next();
@ -473,68 +495,68 @@ public abstract class AbstractCollectionPersister
// sqlSelectString = sqlSelectString();
// sqlSelectRowString = sqlSelectRowString();
if ( collectionBinding.getCustomSQLInsert() == null ) {
if ( collectionBootDescriptor.getCustomSQLInsert() == null ) {
sqlInsertRowString = generateInsertRowString();
insertCallable = false;
insertCheckStyle = ExecuteUpdateResultCheckStyle.COUNT;
}
else {
sqlInsertRowString = collectionBinding.getCustomSQLInsert();
insertCallable = collectionBinding.isCustomInsertCallable();
insertCheckStyle = collectionBinding.getCustomSQLInsertCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( collectionBinding.getCustomSQLInsert(), insertCallable )
: collectionBinding.getCustomSQLInsertCheckStyle();
sqlInsertRowString = collectionBootDescriptor.getCustomSQLInsert();
insertCallable = collectionBootDescriptor.isCustomInsertCallable();
insertCheckStyle = collectionBootDescriptor.getCustomSQLInsertCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( collectionBootDescriptor.getCustomSQLInsert(), insertCallable )
: collectionBootDescriptor.getCustomSQLInsertCheckStyle();
}
if ( collectionBinding.getCustomSQLUpdate() == null ) {
if ( collectionBootDescriptor.getCustomSQLUpdate() == null ) {
sqlUpdateRowString = generateUpdateRowString();
updateCallable = false;
updateCheckStyle = ExecuteUpdateResultCheckStyle.COUNT;
}
else {
sqlUpdateRowString = collectionBinding.getCustomSQLUpdate();
updateCallable = collectionBinding.isCustomUpdateCallable();
updateCheckStyle = collectionBinding.getCustomSQLUpdateCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( collectionBinding.getCustomSQLUpdate(), insertCallable )
: collectionBinding.getCustomSQLUpdateCheckStyle();
sqlUpdateRowString = collectionBootDescriptor.getCustomSQLUpdate();
updateCallable = collectionBootDescriptor.isCustomUpdateCallable();
updateCheckStyle = collectionBootDescriptor.getCustomSQLUpdateCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( collectionBootDescriptor.getCustomSQLUpdate(), insertCallable )
: collectionBootDescriptor.getCustomSQLUpdateCheckStyle();
}
if ( collectionBinding.getCustomSQLDelete() == null ) {
if ( collectionBootDescriptor.getCustomSQLDelete() == null ) {
sqlDeleteRowString = generateDeleteRowString();
deleteCallable = false;
deleteCheckStyle = ExecuteUpdateResultCheckStyle.NONE;
}
else {
sqlDeleteRowString = collectionBinding.getCustomSQLDelete();
deleteCallable = collectionBinding.isCustomDeleteCallable();
sqlDeleteRowString = collectionBootDescriptor.getCustomSQLDelete();
deleteCallable = collectionBootDescriptor.isCustomDeleteCallable();
deleteCheckStyle = ExecuteUpdateResultCheckStyle.NONE;
}
if ( collectionBinding.getCustomSQLDeleteAll() == null ) {
if ( collectionBootDescriptor.getCustomSQLDeleteAll() == null ) {
sqlDeleteString = generateDeleteString();
deleteAllCallable = false;
deleteAllCheckStyle = ExecuteUpdateResultCheckStyle.NONE;
}
else {
sqlDeleteString = collectionBinding.getCustomSQLDeleteAll();
deleteAllCallable = collectionBinding.isCustomDeleteAllCallable();
sqlDeleteString = collectionBootDescriptor.getCustomSQLDeleteAll();
deleteAllCallable = collectionBootDescriptor.isCustomDeleteAllCallable();
deleteAllCheckStyle = ExecuteUpdateResultCheckStyle.NONE;
}
sqlSelectSizeString = generateSelectSizeString( collectionBinding.isIndexed() && !collectionBinding.isMap() );
sqlSelectSizeString = generateSelectSizeString( collectionBootDescriptor.isIndexed() && !collectionBootDescriptor.isMap() );
sqlDetectRowByIndexString = generateDetectRowByIndexString();
sqlDetectRowByElementString = generateDetectRowByElementString();
sqlSelectRowByIndexString = generateSelectRowByIndexString();
logStaticSQL();
isLazy = collectionBinding.isLazy();
isExtraLazy = collectionBinding.isExtraLazy();
isLazy = collectionBootDescriptor.isLazy();
isExtraLazy = collectionBootDescriptor.isExtraLazy();
isInverse = collectionBinding.isInverse();
isInverse = collectionBootDescriptor.isInverse();
if ( collectionBinding.isArray() ) {
elementClass = ( (org.hibernate.mapping.Array) collectionBinding ).getElementClass();
if ( collectionBootDescriptor.isArray() ) {
elementClass = ( (org.hibernate.mapping.Array) collectionBootDescriptor ).getElementClass();
}
else {
// for non-arrays, we don't need to know the element class
@ -569,9 +591,9 @@ public abstract class AbstractCollectionPersister
}
}
hasOrder = collectionBinding.getOrderBy() != null;
hasOrder = collectionBootDescriptor.getOrderBy() != null;
if ( hasOrder ) {
LOG.debugf( "Translating order-by fragment [%s] for collection role : %s", collectionBinding.getOrderBy(), getRole() );
LOG.debugf( "Translating order-by fragment [%s] for collection role : %s", collectionBootDescriptor.getOrderBy(), getRole() );
// orderByTranslation = Template.translateOrderBy(
// collectionBinding.getOrderBy(),
// new ColumnMapperImpl(),
@ -587,20 +609,20 @@ public abstract class AbstractCollectionPersister
}
// Handle any filters applied to this collectionBinding
filterHelper = new FilterHelper( collectionBinding.getFilters(), factory);
filterHelper = new FilterHelper( collectionBootDescriptor.getFilters(), factory);
// Handle any filters applied to this collectionBinding for many-to-many
manyToManyFilterHelper = new FilterHelper( collectionBinding.getManyToManyFilters(), factory);
manyToManyWhereString = StringHelper.isNotEmpty( collectionBinding.getManyToManyWhere() ) ?
"( " + collectionBinding.getManyToManyWhere() + ")" :
manyToManyFilterHelper = new FilterHelper( collectionBootDescriptor.getManyToManyFilters(), factory);
manyToManyWhereString = StringHelper.isNotEmpty( collectionBootDescriptor.getManyToManyWhere() ) ?
"( " + collectionBootDescriptor.getManyToManyWhere() + ")" :
null;
manyToManyWhereTemplate = manyToManyWhereString == null ?
null :
Template.renderWhereStringTemplate( manyToManyWhereString, factory.getDialect(), factory.getSqlFunctionRegistry() );
hasManyToManyOrder = collectionBinding.getManyToManyOrdering() != null;
hasManyToManyOrder = collectionBootDescriptor.getManyToManyOrdering() != null;
if ( hasManyToManyOrder ) {
LOG.debugf( "Translating many-to-many order-by fragment [%s] for collection role : %s", collectionBinding.getOrderBy(), getRole() );
LOG.debugf( "Translating many-to-many order-by fragment [%s] for collection role : %s", collectionBootDescriptor.getOrderBy(), getRole() );
// manyToManyOrderByTranslation = Template.translateOrderBy(
// collectionBinding.getManyToManyOrdering(),
// new ColumnMapperImpl(),
@ -614,9 +636,37 @@ public abstract class AbstractCollectionPersister
// manyToManyOrderByTranslation = null;
}
comparator = collectionBinding.getComparator();
comparator = collectionBootDescriptor.getComparator();
initCollectionPropertyMap();
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// "mapping model"
this.collectionSemantics = creationContext.getBootstrapContext()
.getMetadataBuildingOptions()
.getPersistentCollectionRepresentationResolver()
.resolveRepresentation( collectionBootDescriptor );
if ( elementBootDescriptor instanceof BasicValue ) {
final BasicValue.Resolution<?> basicTypeResolution = ( (BasicValue) elementBootDescriptor ).resolve();
this.elementConverter = basicTypeResolution.getValueConverter();
this.convertedElementType = basicTypeResolution.getResolvedBasicType();
}
else {
this.elementConverter = null;
this.convertedElementType = null;
}
if ( indexBootDescriptor instanceof BasicValue ) {
final BasicValue.Resolution<?> basicTypeResolution = ( (BasicValue) indexBootDescriptor ).resolve();
this.indexConverter = basicTypeResolution.getValueConverter();
this.convertedIndexType = basicTypeResolution.getResolvedBasicType();
}
else {
this.indexConverter = null;
this.convertedIndexType = null;
}
}
@Override
@ -872,6 +922,16 @@ public abstract class AbstractCollectionPersister
return elementType;
}
@Override
public BasicValueConverter getElementConverter() {
return elementConverter;
}
@Override
public BasicValueConverter getIndexConverter() {
return indexConverter;
}
/**
* Return the element class of an array, or null otherwise. needed by arrays
*/
@ -947,7 +1007,14 @@ public abstract class AbstractCollectionPersister
*/
protected int writeElement(PreparedStatement st, Object elt, int i, SharedSessionContractImplementor session)
throws HibernateException, SQLException {
if ( elementConverter != null ) {
//noinspection unchecked
final Object converted = elementConverter.toRelationalValue( elt );
convertedElementType.getJdbcValueBinder().bind( st, converted, i, session );
}
else {
getElementType().nullSafeSet( st, elt, i, elementColumnIsSettable, session );
}
return i + ArrayHelper.countTrue( elementColumnIsSettable );
}
@ -957,7 +1024,16 @@ public abstract class AbstractCollectionPersister
*/
protected int writeIndex(PreparedStatement st, Object index, int i, SharedSessionContractImplementor session)
throws HibernateException, SQLException {
if ( indexConverter != null ) {
//noinspection unchecked
final Object converted = indexConverter.toRelationalValue( index );
//noinspection unchecked
convertedIndexType.getJdbcValueBinder().bind( st, converted, i, session );
}
else {
getIndexType().nullSafeSet( st, incrementIndexByBase( index ), i, indexColumnIsSettable, session );
}
return i + ArrayHelper.countTrue( indexColumnIsSettable );
}
@ -976,7 +1052,13 @@ public abstract class AbstractCollectionPersister
if ( elementIsPureFormula ) {
throw new AssertionFailure( "cannot use a formula-based element in the where condition" );
}
if ( elementConverter != null ) {
final Object converted = elementConverter.toRelationalValue( elt );
convertedElementType.getJdbcValueBinder().bind( st, converted, i, session );
}
else {
getElementType().nullSafeSet( st, elt, i, elementColumnIsInPrimaryKey, session );
}
return i + elementColumnAliases.length;
}
@ -989,7 +1071,13 @@ public abstract class AbstractCollectionPersister
if ( indexContainsFormula ) {
throw new AssertionFailure( "cannot use a formula-based index in the where condition" );
}
if ( indexConverter != null ) {
final Object converted = indexConverter.toRelationalValue( index );
convertedIndexType.getJdbcValueBinder().bind( st, converted, i, session );
}
else {
getIndexType().nullSafeSet( st, incrementIndexByBase( index ), i, session );
}
return i + indexColumnAliases.length;
}
@ -2297,4 +2385,51 @@ public abstract class AbstractCollectionPersister
}
};
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// "mapping model"
@Override
public void applyTableReferences(
SqlAliasBase sqlAliasBase,
JoinType baseJoinType,
TableReferenceCollector collector,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
if ( isOneToMany() ) {
// one-to-many does not define a "collection table"
assert elementPersister != null;
}
else {
// we do have a "collection table" - apply it first
collector.applySecondaryTableReferences(
new TableReference( qualifiedTableName, sqlAliasBase.generateNewAlias(), false, getFactory() ),
baseJoinType,
(lhs, rhs, joinType) -> {
// create the join-predicate between the owner table and the collection table
throw new NotYetImplementedFor6Exception( getClass() );
}
);
}
if ( elementPersister != null ) {
elementPersister.applyTableReferences(
sqlAliasBase,
// todo (6.0) : determine the proper join-type to use
JoinType.LEFT,
collector,
sqlExpressionResolver,
creationContext
);
}
}
@Override
public CollectionSemantics getCollectionSemantics() {
return collectionSemantics;
}
}

View File

@ -32,6 +32,7 @@ import org.hibernate.loader.collection.BatchingCollectionInitializerBuilder;
import org.hibernate.loader.collection.CollectionInitializer;
import org.hibernate.loader.collection.SubselectCollectionLoader;
import org.hibernate.mapping.Collection;
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
import org.hibernate.persister.entity.Joinable;
import org.hibernate.persister.spi.PersisterCreationContext;
import org.hibernate.pretty.MessageHelper;

View File

@ -14,17 +14,26 @@ import java.util.Map;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.cache.spi.access.CollectionDataAccess;
import org.hibernate.cache.spi.entry.CacheEntryStructure;
import org.hibernate.collection.spi.CollectionSemantics;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.metadata.CollectionMetadata;
import org.hibernate.metamodel.CollectionClassification;
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.walking.spi.CollectionDefinition;
import org.hibernate.query.sqm.sql.SqlExpressionResolver;
import org.hibernate.sql.ast.JoinType;
import org.hibernate.sql.ast.spi.SqlAliasBase;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.tree.from.TableReferenceCollector;
import org.hibernate.sql.ast.tree.from.TableReferenceContributor;
import org.hibernate.type.CollectionType;
import org.hibernate.type.Type;
@ -62,7 +71,7 @@ import org.hibernate.type.Type;
* @see org.hibernate.collection.spi.PersistentCollection
* @author Gavin King
*/
public interface CollectionPersister extends CollectionDefinition {
public interface CollectionPersister extends CollectionDefinition, TableReferenceContributor {
/**
* Initialize the given collection with the given key
* TODO: add owner argument!!
@ -103,6 +112,21 @@ public interface CollectionPersister extends CollectionDefinition {
* Return the element class of an array, or null otherwise
*/
Class getElementClass();
/**
* The value converter for the element values of this collection
*/
default BasicValueConverter getElementConverter() {
return null;
}
/**
* The value converter for index values of this collection (effectively map keys only)
*/
default BasicValueConverter getIndexConverter() {
return null;
}
/**
* Read the key from a row of the JDBC <tt>ResultSet</tt>
*/
@ -332,4 +356,30 @@ public interface CollectionPersister extends CollectionDefinition {
* @see CollectionClassification#SORTED_SET
*/
Comparator<?> getSortingComparator();
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// mapping model
@Override
default void applyTableReferences(
SqlAliasBase sqlAliasBase,
JoinType baseJoinType,
TableReferenceCollector collector,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
throw new NotYetImplementedFor6Exception(
"The persister used for this collection [" + getNavigableRole()
+ "] does not yet implement support for use in SQL AST creation;"
+ " should implement `TableReferenceContributor#applyTableReferences`"
);
}
default CollectionSemantics getCollectionSemantics() {
throw new NotYetImplementedFor6Exception(
"The persister used for this collection [" + getNavigableRole()
+ "] does not yet implement support for `"
+ CollectionSemantics.class.getName() + "`"
);
}
}

View File

@ -184,7 +184,9 @@ import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.QueryLiteral;
import org.hibernate.sql.ast.tree.from.StandardTableGroup;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupBuilder;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.from.TableReferenceCollector;
import org.hibernate.sql.ast.tree.from.TableReferenceJoin;
import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate;
import org.hibernate.sql.ast.tree.predicate.Junction;
@ -1187,20 +1189,23 @@ public abstract class AbstractEntityPersister
SqlAstCreationContext creationContext) {
final SqlAliasBase sqlAliasBase = aliasBaseGenerator.createSqlAliasBase( getSqlAliasStem() );
final TableReference primaryTableReference = resolvePrimaryTableReference( sqlAliasBase, sqlExpressionResolver );
final List<TableReferenceJoin> joins = new ArrayList<>( );
resolveTableReferenceJoins( primaryTableReference, sqlAliasBase, tableReferenceJoinType, joins::add, sqlExpressionResolver );
return new StandardTableGroup(
final TableGroupBuilder builder = TableGroupBuilder.builder(
navigablePath,
this,
lockMode,
primaryTableReference,
joins,
sqlAliasBase,
getFactory()
creationContext.getSessionFactory()
);
applyTableReferences(
sqlAliasBase,
tableReferenceJoinType,
builder,
sqlExpressionResolver,
creationContext
);
return builder.build();
}
protected TableReference resolvePrimaryTableReference(
@ -1228,6 +1233,33 @@ public abstract class AbstractEntityPersister
}
}
@Override
public void applyTableReferences(
SqlAliasBase sqlAliasBase,
org.hibernate.sql.ast.JoinType baseJoinType,
TableReferenceCollector collector,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
final TableReference primaryTableReference = resolvePrimaryTableReference(
sqlAliasBase,
sqlExpressionResolver
);
collector.applyPrimaryReference( primaryTableReference );
for ( int i = 1; i < getSubclassTableSpan(); i++ ) {
collector.addTableReferenceJoin(
createTableReferenceJoin(
i,
primaryTableReference,
baseJoinType,
sqlAliasBase,
sqlExpressionResolver
)
);
}
}
protected TableReferenceJoin createTableReferenceJoin(
int subClassTablePosition,
TableReference rootTableReference,
@ -6483,6 +6515,11 @@ public abstract class AbstractEntityPersister
// otherwise, nothing to do
}
@Override
public int getNumberOfFetchables() {
return attributeMappings.size();
}
@Override
public void visitFetchables(
Consumer<Fetchable> fetchableConsumer,

View File

@ -38,8 +38,13 @@ import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.metamodel.spi.EntityRepresentationStrategy;
import org.hibernate.persister.walking.spi.EntityDefinition;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.query.sqm.sql.SqlExpressionResolver;
import org.hibernate.sql.ast.JoinType;
import org.hibernate.sql.ast.spi.SqlAliasBase;
import org.hibernate.sql.ast.spi.SqlAliasStemHelper;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.tree.from.RootTableGroupProducer;
import org.hibernate.sql.ast.tree.from.TableReferenceCollector;
import org.hibernate.tuple.entity.EntityMetamodel;
import org.hibernate.tuple.entity.EntityTuplizer;
import org.hibernate.type.Type;
@ -93,6 +98,11 @@ public interface EntityPersister extends EntityDefinition, EntityValuedModelPart
@Deprecated
void generateEntityDefinition();
@Override
default int getNumberOfFetchables() {
return getNumberOfAttributeMappings();
}
/**
* Finish the initialization of this object. {@link #prepareMappingModel}
* must be called for all entity persisters before calling this method.
@ -906,6 +916,4 @@ public interface EntityPersister extends EntityDefinition, EntityValuedModelPart
default boolean canIdentityInsertBeDelayed() {
return false;
}
}

View File

@ -499,6 +499,7 @@ public abstract class BaseSqmToSqlAstConverter
creationContext
);
lhsTableGroup.addTableGroupJoin( tableGroupJoin );
fromClauseIndex.register( sqmJoin, tableGroupJoin.getJoinedGroup() );
// add any additional join restrictions

View File

@ -37,7 +37,6 @@ public class FromClauseIndex extends SimpleFromClauseAccessImpl {
* Holds *explicitly* fetched joins
*/
private Map<NavigablePath, SqmAttributeJoin> fetchesByPath;
private Map<NavigablePath, Map<NavigablePath, SqmAttributeJoin>> fetchesByParentPath;
private final Set<String> affectedTableNames = new HashSet<>();
@ -61,6 +60,20 @@ public class FromClauseIndex extends SimpleFromClauseAccessImpl {
);
}
}
if ( sqmPath instanceof SqmAttributeJoin ) {
final SqmAttributeJoin sqmJoin = (SqmAttributeJoin) sqmPath;
if ( sqmJoin.isFetched() ) {
registerJoinFetch( sqmJoin );
}
}
}
private void registerJoinFetch(SqmAttributeJoin sqmJoin) {
if ( fetchesByPath == null ) {
fetchesByPath = new HashMap<>();
}
fetchesByPath.put( sqmJoin.getNavigablePath(), sqmJoin );
}
public boolean isResolved(SqmFrom fromElement) {

View File

@ -31,6 +31,7 @@ import org.hibernate.query.spi.QueryParameterBindings;
import org.hibernate.query.sqm.internal.DomainParameterXref;
import org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter;
import org.hibernate.query.sqm.sql.SqlAstCreationState;
import org.hibernate.query.sqm.sql.SqmSelectToSqlAstConverter;
import org.hibernate.query.sqm.tree.expression.SqmLiteralEntityType;
import org.hibernate.query.sqm.tree.from.SqmAttributeJoin;
import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiation;
@ -67,7 +68,7 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
@SuppressWarnings("unchecked")
public class StandardSqmSelectToSqlAstConverter
extends BaseSqmToSqlAstConverter
implements DomainResultCreationState, org.hibernate.query.sqm.sql.SqmSelectToSqlAstConverter {
implements DomainResultCreationState, SqmSelectToSqlAstConverter {
private final LoadQueryInfluencers fetchInfluencers;
private final CircularFetchDetector circularFetchDetector = new CircularFetchDetector();
@ -155,7 +156,7 @@ public class StandardSqmSelectToSqlAstConverter
@Override
public List<Fetch> visitFetches(FetchParent fetchParent) {
final List<Fetch> fetches = CollectionHelper.arrayList( fetchParent.getReferencedMappingType().getNumberOfAttributeMappings() );
final List<Fetch> fetches = CollectionHelper.arrayList( fetchParent.getReferencedMappingType().getNumberOfFetchables() );
//noinspection Convert2Lambda
final Consumer<Fetchable> fetchableConsumer = new Consumer<Fetchable>() {
@ -214,7 +215,7 @@ public class StandardSqmSelectToSqlAstConverter
if ( fetchedJoin != null ) {
// there was an explicit fetch in the SQM
// there should be a TableGroupJoin registered n SqmJoin registered for this `fetchablePath` already
// there should be a TableGroupJoin registered for this `fetchablePath` already
// because it
assert getFromClauseIndex().getTableGroup( fetchablePath ) != null;

View File

@ -6,13 +6,18 @@
*/
package org.hibernate.sql.ast.tree.from;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.JoinType;
import org.hibernate.sql.ast.spi.SqlAliasBase;
import org.hibernate.sql.ast.tree.predicate.Predicate;
/**
* @author Steve Ebersole
@ -23,7 +28,7 @@ public class StandardTableGroup extends AbstractTableGroup {
public StandardTableGroup(
NavigablePath navigablePath,
RootTableGroupProducer tableGroupProducer,
TableGroupProducer tableGroupProducer,
LockMode lockMode,
TableReference primaryTableReference,
List<TableReferenceJoin> tableJoins,
@ -34,11 +39,6 @@ public class StandardTableGroup extends AbstractTableGroup {
this.tableJoins = tableJoins;
}
@Override
public RootTableGroupProducer getModelPart() {
return (RootTableGroupProducer) super.getModelPart();
}
@Override
public void applyAffectedTableNames(Consumer<String> nameCollector) {
// todo (6.0) : if we implement dynamic TableReference creation, this still needs to return the expressions for all mapped tables not just the ones with a TableReference at this time

View File

@ -0,0 +1,131 @@
/*
* 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.sql.ast.tree.from;
import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Function;
import org.hibernate.LockMode;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.JoinType;
import org.hibernate.sql.ast.spi.SqlAliasBase;
/**
* @author Steve Ebersole
*/
public class TableGroupBuilder implements TableReferenceCollector {
public static TableGroupBuilder builder(
NavigablePath path,
TableGroupProducer producer,
LockMode lockMode,
SqlAliasBase sqlAliasBase,
SessionFactoryImplementor sessionFactory) {
return new TableGroupBuilder( path, producer, lockMode, sqlAliasBase, sessionFactory );
}
private final NavigablePath path;
private final TableGroupProducer producer;
private final SessionFactoryImplementor sessionFactory;
private final SqlAliasBase sqlAliasBase;
private final LockMode lockMode;
private final Function<TableReference,TableReferenceJoin> primaryJoinProducer;
private TableReference primaryTableReference;
private TableReference secondaryTableLhs;
private java.util.List<TableReferenceJoin> tableJoins;
private TableGroupBuilder(
NavigablePath path,
TableGroupProducer producer,
LockMode lockMode,
SqlAliasBase sqlAliasBase,
SessionFactoryImplementor sessionFactory) {
this( path, producer, lockMode, sqlAliasBase, null, sessionFactory );
}
private TableGroupBuilder(
NavigablePath path,
TableGroupProducer producer,
LockMode lockMode,
SqlAliasBase sqlAliasBase,
Function<TableReference,TableReferenceJoin> primaryJoinProducer,
SessionFactoryImplementor sessionFactory) {
this.path = path;
this.producer = producer;
this.lockMode = lockMode;
this.sqlAliasBase = sqlAliasBase;
this.primaryJoinProducer = primaryJoinProducer;
this.sessionFactory = sessionFactory;
}
public TableGroup build() {
if ( primaryTableReference == null ) {
throw new IllegalStateException( "Primary TableReference was not specified : " + path );
}
return new StandardTableGroup(
path,
producer,
lockMode,
primaryTableReference,
tableJoins == null ? Collections.emptyList() : tableJoins,
sqlAliasBase,
sessionFactory
);
}
@Override
public void applyPrimaryReference(TableReference tableReference) {
if ( primaryTableReference != null ) {
assert primaryJoinProducer != null;
addTableReferenceJoin( primaryJoinProducer.apply( tableReference ) );
}
else {
primaryTableReference = tableReference;
}
secondaryTableLhs = tableReference;
}
@Override
public void applySecondaryTableReferences(
TableReference tableReference,
JoinType tableReferenceJoinType,
TableReferenceJoinPredicateProducer predicateProducer) {
if ( primaryTableReference == null ) {
primaryTableReference = tableReference;
secondaryTableLhs = primaryTableReference;
}
else {
addTableReferenceJoin(
new TableReferenceJoin(
tableReferenceJoinType,
tableReference,
predicateProducer.producePredicate(
secondaryTableLhs,
tableReference,
tableReferenceJoinType
)
)
);
}
}
public void addTableReferenceJoin(TableReferenceJoin join) {
if ( tableJoins == null ) {
tableJoins = new ArrayList<>();
}
tableJoins.add( join );
}
}

View File

@ -15,7 +15,7 @@ import org.hibernate.query.sqm.sql.SqlAliasBaseManager;
* @author Steve Ebersole
* @author Andrea Boriero
*/
public interface TableGroupProducer extends ModelPartContainer {
public interface TableGroupProducer extends ModelPartContainer, TableReferenceContributor {
/**
* Get the "stem" used as the base for generating SQL table aliases for table
* references that are part of the TableGroup being generated

View File

@ -0,0 +1,38 @@
/*
* 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.sql.ast.tree.from;
import org.hibernate.sql.ast.JoinType;
/**
* Used in constructing {@link TableGroup} references to collect the individual table
* references
*
* @author Steve Ebersole
*/
public interface TableReferenceCollector {
void applyPrimaryReference(TableReference tableReference);
/**
* Collect a table reference as part of the TableGroup.
*
* @param tableReference The TableReference.
* @param joinType The type of join indicated by the mapping of the table, if it is to be joined
* @param predicateProducer Function for creating the join predicate, if it is to be joined. The first
* argument passed to the function is the LHS reference. The second is the same as `tableReference`.
* The result is a SQL AST Predicate to use as the join-predicate
*/
void applySecondaryTableReferences(
TableReference tableReference,
JoinType joinType,
TableReferenceJoinPredicateProducer predicateProducer);
/**
* Directly add a TableReferenceJoin
*/
void addTableReferenceJoin(TableReferenceJoin join);
}

View File

@ -6,19 +6,22 @@
*/
package org.hibernate.sql.ast.tree.from;
import org.hibernate.query.sqm.sql.SqlExpressionResolver;
import org.hibernate.sql.ast.JoinType;
import org.hibernate.sql.ast.spi.SqlAliasBase;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
/**
* @author Steve Ebersole
*/
public interface TableReferenceContributor {
// /**
// * Apply the Tables mapped by this producer to the collector as TableReferences
// */
// void applyTableReferenceJoins(
// ColumnReferenceQualifier lhs,
// JoinType joinType,
// SqlAliasBase sqlAliasBase,
// TableReferenceJoinCollector joinCollector);
/**
* Apply the Tables mapped by this producer to the collector as TableReferences
*/
void applyTableReferences(
SqlAliasBase sqlAliasBase,
JoinType baseJoinType,
TableReferenceCollector collector,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext);
}

View File

@ -0,0 +1,24 @@
/*
* 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.sql.ast.tree.from;
import org.hibernate.sql.ast.JoinType;
import org.hibernate.sql.ast.tree.predicate.Predicate;
/**
* Functional contract for producing the join-predicate related to a {@link TableReferenceJoin}.
*
* @see TableReferenceJoin#getJoinPredicate
* @see TableReferenceCollector#applySecondaryTableReferences
*
* @author Steve Ebersole
*/
@FunctionalInterface
public
interface TableReferenceJoinPredicateProducer {
Predicate producePredicate(TableReference lhs, TableReference rhs, JoinType joinType);
}

View File

@ -0,0 +1,97 @@
/*
* 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.sql.results.internal;
import java.io.Serializable;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.CollectionEntry;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.sql.exec.spi.ExecutionContext;
import org.hibernate.sql.results.spi.CollectionInitializer;
import org.hibernate.sql.results.spi.LoadingCollectionEntry;
/**
* Represents a collection currently being loaded.
*
* @author Steve Ebersole
*/
public class LoadingCollectionEntryImpl implements LoadingCollectionEntry {
private final CollectionPersister collectionDescriptor;
private final CollectionInitializer initializer;
private final Object key;
private final PersistentCollection collectionInstance;
public LoadingCollectionEntryImpl(
CollectionPersister collectionDescriptor,
CollectionInitializer initializer,
Object key,
PersistentCollection collectionInstance) {
this.collectionDescriptor = collectionDescriptor;
this.initializer = initializer;
this.key = key;
this.collectionInstance = collectionInstance;
collectionInstance.beforeInitialize( getCollectionDescriptor(), -1 );
collectionInstance.beginRead();
}
@Override public CollectionPersister getCollectionDescriptor() {
return collectionDescriptor;
}
/**
* Access to the initializer that is responsible for initializing this collection
*/
@Override public CollectionInitializer getInitializer() {
return initializer;
}
@Override public Serializable getKey() {
// todo (6.0) : change from Serializable to Object
return (Serializable) key;
}
@Override public PersistentCollection getCollectionInstance() {
return collectionInstance;
}
@Override
public String toString() {
return getClass().getSimpleName() + "(" + getCollectionDescriptor().getNavigableRole().getFullPath() + "#" + getKey() + ")";
}
@Override public void finishLoading(ExecutionContext executionContext) {
collectionInstance.endRead();
final SharedSessionContractImplementor session = executionContext.getSession();
final PersistenceContext persistenceContext = session.getPersistenceContext();
final CollectionPersister collectionDescriptor = getCollectionDescriptor();
CollectionEntry collectionEntry = persistenceContext.getCollectionEntry( collectionInstance );
if ( collectionEntry == null ) {
collectionEntry = persistenceContext.addInitializedCollection(
collectionDescriptor,
getCollectionInstance(),
getKey()
);
}
else {
collectionEntry.postInitialize( collectionInstance );
}
if ( collectionDescriptor.getCollectionType().hasHolder() ) {
persistenceContext.addCollectionHolder( collectionInstance );
}
// todo (6.0) : there is other logic still needing to be implemented here. caching, etc
// see org.hibernate.engine.loading.internal.CollectionLoadContext#endLoadingCollection in 5.x
}
}

View File

@ -11,7 +11,9 @@ import java.util.List;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.named.RowReaderMemento;
import org.hibernate.sql.exec.spi.Callback;
import org.hibernate.sql.results.spi.CollectionInitializer;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.EntityInitializer;
import org.hibernate.sql.results.spi.Initializer;
import org.hibernate.sql.results.spi.JdbcValuesSourceProcessingOptions;
import org.hibernate.sql.results.spi.JdbcValuesSourceProcessingState;
@ -125,7 +127,17 @@ public class StandardRowReader<T> implements RowReader<T> {
// old
for ( int i = 0; i < initializers.size(); i++ ) {
initializers.get( i ).resolveKey( rowProcessingState );
final Initializer initializer = initializers.get( i );
if ( ! ( initializer instanceof CollectionInitializer ) ) {
initializer.resolveKey( rowProcessingState );
}
}
for ( int i = 0; i < initializers.size(); i++ ) {
final Initializer initializer = initializers.get( i );
if ( initializer instanceof CollectionInitializer ) {
initializer.resolveKey( rowProcessingState );
}
}
for ( int i = 0; i < initializers.size(); i++ ) {

View File

@ -0,0 +1,56 @@
/*
* 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.sql.results.internal.domain.collection;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.results.spi.Fetch;
import org.hibernate.sql.results.spi.FetchParent;
/**
* @author Steve Ebersole
*/
public abstract class CollectionFetch implements Fetch {
private final NavigablePath fetchedPath;
private final PluralAttributeMapping fetchedAttribute;
private final boolean nullable;
private final FetchParent fetchParent;
public CollectionFetch(
NavigablePath fetchedPath,
PluralAttributeMapping fetchedAttribute,
boolean nullable,
FetchParent fetchParent) {
this.fetchedPath = fetchedPath;
this.fetchedAttribute = fetchedAttribute;
this.fetchParent = fetchParent;
this.nullable = nullable;
}
@Override
public FetchParent getFetchParent() {
return fetchParent;
}
@Override
public PluralAttributeMapping getFetchedMapping() {
return fetchedAttribute;
}
@Override
public NavigablePath getNavigablePath() {
return fetchedPath;
}
@Override
public boolean isNullable() {
return nullable;
}
}

View File

@ -0,0 +1,155 @@
/*
* 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.sql.results.internal.domain.collection;
import java.io.Serializable;
import java.util.function.Consumer;
import org.hibernate.collection.spi.CollectionSemantics;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.CollectionKey;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.spi.AssemblerCreationState;
import org.hibernate.sql.results.spi.CollectionInitializer;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.FetchParentAccess;
import org.hibernate.sql.results.spi.Initializer;
import org.hibernate.sql.results.spi.JdbcValuesSourceProcessingOptions;
import org.hibernate.sql.results.spi.LoadingCollectionEntry;
import org.hibernate.sql.results.spi.RowProcessingState;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* @author Steve Ebersole
*/
public class DelayedCollectionAssembler implements DomainResultAssembler {
private final PluralAttributeMapping fetchedMapping;
private final FetchParentAccess parentAccess;
private final CollectionInitializer initializer;
public DelayedCollectionAssembler(
NavigablePath fetchPath,
PluralAttributeMapping fetchedMapping,
FetchParentAccess parentAccess,
Consumer<Initializer> collector,
AssemblerCreationState creationState) {
this.fetchedMapping = fetchedMapping;
this.parentAccess = parentAccess;
this.initializer = new InitializerImpl( fetchPath, fetchedMapping, parentAccess, creationState );
collector.accept( initializer );
}
@Override
public Object assemble(RowProcessingState rowProcessingState, JdbcValuesSourceProcessingOptions options) {
return initializer.getCollectionInstance();
}
@Override
public JavaTypeDescriptor getAssembledJavaTypeDescriptor() {
return fetchedMapping.getJavaTypeDescriptor();
}
private static class InitializerImpl implements CollectionInitializer {
private final NavigablePath fetchedPath;
private final PluralAttributeMapping fetchedMapping;
private final FetchParentAccess parentAccess;
private CollectionKey collectionKey;
private PersistentCollection instance;
public InitializerImpl(
NavigablePath fetchedPath,
PluralAttributeMapping fetchedMapping,
FetchParentAccess parentAccess,
AssemblerCreationState creationState) {
this.fetchedPath = fetchedPath;
this.fetchedMapping = fetchedMapping;
this.parentAccess = parentAccess;
}
@Override
public NavigablePath getNavigablePath() {
return fetchedPath;
}
@Override
public void resolveKey(RowProcessingState rowProcessingState) {
if ( collectionKey != null ) {
// already resolved
return;
}
collectionKey = new CollectionKey(
fetchedMapping.getCollectionDescriptor(),
parentAccess.getParentKey()
);
}
@Override
public void resolveInstance(RowProcessingState rowProcessingState) {
final SharedSessionContractImplementor session = rowProcessingState.getSession();
final PersistenceContext persistenceContext = session.getPersistenceContext();
final LoadingCollectionEntry loadingEntry = persistenceContext.getLoadContexts().findLoadingCollectionEntry( collectionKey );
final PersistentCollection registeredInstance = persistenceContext.getCollection( collectionKey );
if ( loadingEntry != null ) {
instance = loadingEntry.getCollectionInstance();
return;
}
if ( registeredInstance != null ) {
this.instance = registeredInstance;
return;
}
this.instance = makePersistentCollection( fetchedMapping, collectionKey, rowProcessingState );
persistenceContext.addUninitializedCollection(
getInitializingCollectionDescriptor(),
instance,
(Serializable) collectionKey.getKey()
);
}
private static PersistentCollection makePersistentCollection(
PluralAttributeMapping fetchedMapping,
CollectionKey collectionKey,
RowProcessingState rowProcessingState) {
final CollectionPersister collectionDescriptor = fetchedMapping.getCollectionDescriptor();
final CollectionSemantics collectionSemantics = collectionDescriptor.getCollectionSemantics();
return collectionSemantics.instantiateWrapper(
collectionKey.getKey(),
collectionDescriptor,
rowProcessingState.getSession()
);
}
@Override
public void initializeInstance(RowProcessingState rowProcessingState) {
}
@Override
public void finishUpRow(RowProcessingState rowProcessingState) {
collectionKey = null;
instance = null;
}
@Override
public CollectionPersister getInitializingCollectionDescriptor() {
return fetchedMapping.getCollectionDescriptor();
}
@Override
public PersistentCollection getCollectionInstance() {
return instance;
}
}
}

View File

@ -0,0 +1,44 @@
/*
* 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.sql.results.internal.domain.collection;
import java.util.function.Consumer;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.spi.AssemblerCreationState;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.FetchParent;
import org.hibernate.sql.results.spi.FetchParentAccess;
import org.hibernate.sql.results.spi.Initializer;
/**
* @author Steve Ebersole
*/
public class DelayedCollectionFetch extends CollectionFetch {
public DelayedCollectionFetch(
NavigablePath fetchedPath,
PluralAttributeMapping fetchedAttribute,
boolean nullable,
FetchParent fetchParent) {
super( fetchedPath, fetchedAttribute, nullable, fetchParent );
}
@Override
public DomainResultAssembler createAssembler(
FetchParentAccess parentAccess,
Consumer<Initializer> collector,
AssemblerCreationState creationState) {
return new DelayedCollectionAssembler(
getNavigablePath(),
getFetchedMapping(),
parentAccess,
collector,
creationState
);
}
}

View File

@ -0,0 +1,258 @@
/*
* 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.sql.results.internal.domain.collection;
import java.util.function.Consumer;
import org.hibernate.collection.spi.CollectionSemantics;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.CollectionKey;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.internal.LoadingCollectionEntryImpl;
import org.hibernate.sql.results.spi.AssemblerCreationState;
import org.hibernate.sql.results.spi.CollectionInitializer;
import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.Fetch;
import org.hibernate.sql.results.spi.FetchParentAccess;
import org.hibernate.sql.results.spi.Initializer;
import org.hibernate.sql.results.spi.JdbcValuesSourceProcessingOptions;
import org.hibernate.sql.results.spi.LoadContexts;
import org.hibernate.sql.results.spi.LoadingCollectionEntry;
import org.hibernate.sql.results.spi.RowProcessingState;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* @author Steve Ebersole
*/
public class EagerCollectionAssembler implements DomainResultAssembler {
private final PluralAttributeMapping fetchedMapping;
private final FetchParentAccess parentAccess;
private final CollectionInitializer initializer;
public EagerCollectionAssembler(
NavigablePath fetchPath,
PluralAttributeMapping fetchedMapping,
DomainResult fkResult,
Fetch elementFetch,
Fetch indexFetch,
DomainResult identifierResult,
FetchParentAccess parentAccess,
Consumer<Initializer> collector,
AssemblerCreationState creationState) {
this.fetchedMapping = fetchedMapping;
this.parentAccess = parentAccess;
this.initializer = new InitializerImpl(
fetchPath,
fetchedMapping,
parentAccess,
fkResult,
elementFetch,
indexFetch,
identifierResult,
collector,
creationState
);
collector.accept( initializer );
}
@Override
public Object assemble(RowProcessingState rowProcessingState, JdbcValuesSourceProcessingOptions options) {
return initializer.getCollectionInstance();
}
@Override
public JavaTypeDescriptor getAssembledJavaTypeDescriptor() {
return fetchedMapping.getJavaTypeDescriptor();
}
private static class InitializerImpl implements CollectionInitializer {
private final NavigablePath fetchedPath;
private final PluralAttributeMapping fetchedMapping;
private final FetchParentAccess parentAccess;
private final DomainResultAssembler fkAssembler;
private final DomainResultAssembler elementAssembler;
private final DomainResultAssembler indexAssembler;
private final DomainResultAssembler identifierAssembler;
private CollectionKey collectionKey;
private boolean managing;
private Object fkValue;
// todo (6.0) : consider using the initializer itself as the holder of the various "temp" collections
// used while reading a collection. that would mean collection-type specific initializers (List, versus Set)
private PersistentCollection instance;
public InitializerImpl(
NavigablePath fetchedPath,
PluralAttributeMapping fetchedMapping,
FetchParentAccess parentAccess,
DomainResult fkResult,
Fetch elementFetch,
Fetch indexFetch,
DomainResult identifierResult,
Consumer<Initializer> collector,
AssemblerCreationState creationState) {
this.fetchedPath = fetchedPath;
this.fetchedMapping = fetchedMapping;
this.parentAccess = parentAccess;
this.fkAssembler = fkResult.createResultAssembler( collector, creationState );
// questionable what should be the parent access here
this.elementAssembler = elementFetch.createAssembler( parentAccess, collector, creationState );
this.indexAssembler = indexFetch == null
? null
: indexFetch.createAssembler( parentAccess, collector, creationState );
this.identifierAssembler = identifierResult == null
? null
: identifierResult.createResultAssembler( collector, creationState );
}
@Override
public CollectionPersister getInitializingCollectionDescriptor() {
return fetchedMapping.getCollectionDescriptor();
}
@Override
public PersistentCollection getCollectionInstance() {
return instance;
}
@Override
public NavigablePath getNavigablePath() {
return fetchedPath;
}
@Override
public void finishUpRow(RowProcessingState rowProcessingState) {
collectionKey = null;
managing = false;
instance = null;
}
@Override
public void resolveKey(RowProcessingState rowProcessingState) {
if ( collectionKey != null ) {
// already resolved
return;
}
collectionKey = new CollectionKey(
fetchedMapping.getCollectionDescriptor(),
parentAccess.getParentKey()
);
final Object fkValue = fkAssembler.assemble( rowProcessingState );
if ( fkValue == null ) {
// this row has no collection element
return;
}
}
@Override
public void resolveInstance(RowProcessingState rowProcessingState) {
if ( instance != null ) {
// already resolved
return;
}
final PersistenceContext persistenceContext = rowProcessingState.getSession().getPersistenceContext();
// see if the collection is already being initialized
final LoadContexts loadContexts = persistenceContext.getLoadContexts();
final LoadingCollectionEntry existingEntry = loadContexts.findLoadingCollectionEntry( collectionKey );
if ( existingEntry != null ) {
this.instance = existingEntry.getCollectionInstance();
if ( existingEntry.getInitializer() == this ) {
this.managing = true;
}
return;
}
// see if it has been already registered with the Session
final PersistentCollection registeredInstance = persistenceContext.getCollection( collectionKey );
if ( registeredInstance != null ) {
this.instance = registeredInstance;
// it was already registered, so use that wrapper.
if ( ! registeredInstance.wasInitialized() ) {
// if the existing wrapper is not initialized, we will take responsibility for initializing it
managing = true;
rowProcessingState.getJdbcValuesSourceProcessingState().registerLoadingCollection(
collectionKey,
new LoadingCollectionEntryImpl(
getInitializingCollectionDescriptor(),
this,
collectionKey,
registeredInstance
)
);
return;
}
}
this.instance = makePersistentCollection( fetchedMapping, collectionKey, rowProcessingState );
this.managing = true;
rowProcessingState.getJdbcValuesSourceProcessingState().registerLoadingCollection(
collectionKey,
new LoadingCollectionEntryImpl(
fetchedMapping.getCollectionDescriptor(),
this,
collectionKey.getKey(),
instance
)
);
}
private static PersistentCollection makePersistentCollection(
PluralAttributeMapping fetchedMapping,
CollectionKey collectionKey,
RowProcessingState rowProcessingState) {
final CollectionPersister collectionDescriptor = fetchedMapping.getCollectionDescriptor();
final CollectionSemantics collectionSemantics = collectionDescriptor.getCollectionSemantics();
return collectionSemantics.instantiateWrapper(
collectionKey.getKey(),
collectionDescriptor,
rowProcessingState.getSession()
);
}
@Override
public void initializeInstance(RowProcessingState rowProcessingState) {
if ( ! managing ) {
return;
}
final Object fkValue = fkAssembler.assemble( rowProcessingState );
if ( fkValue == null ) {
// this row contains no collection element
return;
}
getCollectionInstance().readFrom(
rowProcessingState,
elementAssembler,
indexAssembler,
identifierAssembler,
parentAccess.getFetchParentInstance()
);
}
}
}

View File

@ -0,0 +1,125 @@
/*
* 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.sql.results.internal.domain.collection;
import java.util.List;
import java.util.function.Consumer;
import org.hibernate.metamodel.mapping.CollectionIdentifierDescriptor;
import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.results.spi.AssemblerCreationState;
import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.DomainResultCreationState;
import org.hibernate.sql.results.spi.Fetch;
import org.hibernate.sql.results.spi.FetchParent;
import org.hibernate.sql.results.spi.FetchParentAccess;
import org.hibernate.sql.results.spi.FetchableContainer;
import org.hibernate.sql.results.spi.Initializer;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* @author Steve Ebersole
*/
public class EagerCollectionFetch extends CollectionFetch implements FetchParent {
private final DomainResult fkResult;
private final Fetch elementFetch;
private final Fetch indexFetch;
private final DomainResult identifierResult;
private final List<Fetch> fetches;
public EagerCollectionFetch(
NavigablePath fetchedPath,
PluralAttributeMapping fetchedAttribute,
DomainResult fkResult,
boolean nullable,
FetchParent fetchParent,
DomainResultCreationState creationState) {
super( fetchedPath, fetchedAttribute, nullable, fetchParent );
this.fkResult = fkResult;
final CollectionIdentifierDescriptor identifierDescriptor = fetchedAttribute.getIdentifierDescriptor();
if ( identifierDescriptor == null ) {
this.identifierResult = null;
}
else {
final TableGroup collectionTableGroup = creationState.getSqlAstCreationState().getFromClauseAccess().getTableGroup( fetchedPath );
this.identifierResult = identifierDescriptor.createDomainResult( fetchedPath, collectionTableGroup, creationState );
}
fetches = creationState.visitFetches( this );
if ( fetchedAttribute.getIndexDescriptor() != null ) {
assert fetches.size() == 2;
indexFetch = fetches.get( 0 );
elementFetch = fetches.get( 1 );
}
else {
assert fetches.size() == 1;
indexFetch = null;
elementFetch = fetches.get( 0 );
}
}
@Override
public DomainResultAssembler createAssembler(
FetchParentAccess parentAccess,
Consumer<Initializer> collector,
AssemblerCreationState creationState) {
return new EagerCollectionAssembler(
getNavigablePath(),
getFetchedMapping(),
fkResult,
elementFetch,
indexFetch,
identifierResult,
parentAccess,
collector,
creationState
);
}
@Override
public FetchableContainer getReferencedMappingContainer() {
return getFetchedMapping();
}
@Override
public PluralAttributeMapping getReferencedMappingType() {
return getFetchedMapping();
}
@Override
public List<Fetch> getFetches() {
return fetches;
}
@Override
public Fetch findFetch(String fetchableName) {
if ( CollectionPart.Nature.ELEMENT.getName().equals( fetchableName ) ) {
return elementFetch;
}
else if ( CollectionPart.Nature.INDEX.getName().equals( fetchableName ) ) {
return indexFetch;
}
else {
throw new IllegalArgumentException(
"Unknown fetchable [" + getFetchedMapping().getCollectionDescriptor().getRole() +
" -> " + fetchableName + "]"
);
}
}
@Override
public JavaTypeDescriptor getResultJavaTypeDescriptor() {
return getFetchedMapping().getJavaTypeDescriptor();
}
}

View File

@ -10,7 +10,7 @@ import java.util.function.Consumer;
import org.hibernate.engine.FetchTiming;
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.internal.domain.AbstractFetchParent;
import org.hibernate.sql.results.spi.AssemblerCreationState;
@ -29,17 +29,20 @@ import org.hibernate.sql.results.spi.Initializer;
public class CompositeFetch extends AbstractFetchParent implements CompositeResultMappingNode, Fetch {
private final FetchParent fetchParent;
private final FetchTiming fetchTiming;
private final boolean nullable;
public CompositeFetch(
NavigablePath navigablePath,
EmbeddedAttributeMapping embeddedAttribute,
EmbeddableValuedModelPart embeddedPartDescriptor,
FetchParent fetchParent,
FetchTiming fetchTiming,
boolean nullable,
DomainResultCreationState creationState) {
super( embeddedAttribute, navigablePath );
super( embeddedPartDescriptor, navigablePath );
this.fetchParent = fetchParent;
this.fetchTiming = fetchTiming;
this.nullable = nullable;
creationState.getSqlAstCreationState().getFromClauseAccess().registerTableGroup(
getNavigablePath(),
@ -49,38 +52,34 @@ public class CompositeFetch extends AbstractFetchParent implements CompositeResu
afterInitialize( creationState );
}
public EmbeddedAttributeMapping getEmbeddedAttributeMapping() {
return (EmbeddedAttributeMapping) super.getFetchContainer();
}
@Override
public FetchParent getFetchParent() {
return fetchParent;
}
@Override
public EmbeddedAttributeMapping getFetchContainer() {
return getEmbeddedAttributeMapping();
public EmbeddableValuedModelPart getFetchContainer() {
return (EmbeddableValuedModelPart) super.getFetchContainer();
}
@Override
public EmbeddedAttributeMapping getReferencedMappingContainer() {
return getEmbeddedAttributeMapping();
public EmbeddableValuedModelPart getReferencedMappingContainer() {
return getFetchContainer();
}
@Override
public Fetchable getFetchedMapping() {
return getEmbeddedAttributeMapping();
return getFetchContainer();
}
@Override
public EmbeddableMappingType getReferencedMappingType() {
return getEmbeddedAttributeMapping().getEmbeddableTypeDescriptor();
return getFetchContainer().getEmbeddableTypeDescriptor();
}
@Override
public boolean isNullable() {
return getEmbeddedAttributeMapping().getAttributeMetadataAccess().resolveAttributeMetadata( null ).isNullable();
return nullable;
}
@Override

View File

@ -27,4 +27,9 @@ public class CompositeFetchInitializer
AssemblerCreationState creationState) {
super( resultDescriptor, fetchParentAccess, initializerConsumer, creationState );
}
@Override
public Object getParentKey() {
return getFetchParentAccess().getParentKey();
}
}

View File

@ -22,4 +22,9 @@ public class CompositeRootInitializer extends AbstractCompositeInitializer {
AssemblerCreationState creationState) {
super( resultDescriptor, null, initializerConsumer, creationState );
}
@Override
public Object getParentKey() {
return null;
}
}

View File

@ -34,7 +34,6 @@ import org.hibernate.event.spi.PreLoadEvent;
import org.hibernate.event.spi.PreLoadEventListener;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.StateArrayContributorMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Loadable;
import org.hibernate.proxy.HibernateProxy;
@ -197,6 +196,11 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
return entityKey.getIdentifier();
}
@Override
public Object getParentKey() {
return getKeyValue();
}
@Override
public Object getFetchParentInstance() {
if ( entityInstance == null ) {

View File

@ -25,8 +25,6 @@ import org.hibernate.sql.results.spi.EntityResult;
public class EntityResultImpl extends AbstractEntityResultNode implements EntityResult {
private final String resultVariable;
public EntityResultImpl(
NavigablePath navigablePath,
EntityValuedModelPart entityValuedModelPart,

View File

@ -8,7 +8,7 @@ package org.hibernate.sql.results.spi;
import java.util.List;
import org.hibernate.metamodel.mapping.ManagedMappingType;
import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.query.NavigablePath;
/**
@ -22,7 +22,7 @@ public interface FetchParent extends ResultSetMappingNode {
/**
* This parent's type
*/
ManagedMappingType getReferencedMappingType();
FetchableContainer getReferencedMappingType();
/**
* Get the property path to this parent

View File

@ -19,6 +19,8 @@ import org.hibernate.query.NavigablePath;
public interface FetchParentAccess {
FetchParentAccess findFirstEntityDescriptorAccess();
Object getParentKey();
/**
* Access to the fetch's parent instance.
*/

View File

@ -15,6 +15,8 @@ import org.hibernate.metamodel.mapping.ModelPartContainer;
* @author Steve Ebersole
*/
public interface FetchableContainer extends ModelPartContainer {
int getNumberOfFetchables();
default void visitKeyFetchables(
Consumer<Fetchable> fetchableConsumer,
EntityMappingType treatTargetType) {

View File

@ -6,8 +6,6 @@
*/
package org.hibernate.sql.results.spi;
import java.sql.ResultSet;
import org.hibernate.engine.spi.CollectionKey;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.PersistenceContext;
@ -18,7 +16,7 @@ import org.hibernate.internal.util.collections.StandardStack;
/**
* Maintains a Stack of processing state related to performing load operations.
* The sCollectionLoadContexttate is defined by {@link JdbcValuesSourceProcessingState} which
* The state is defined by {@link JdbcValuesSourceProcessingState} which
* encapsulates the data to be processed by the load whether the data comes from
* a ResultSet or second-level cache hit.
*

View File

@ -9,9 +9,6 @@ package org.hibernate.sql.results.spi;
import java.io.Serializable;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.CollectionEntry;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.sql.exec.spi.ExecutionContext;
@ -20,76 +17,14 @@ import org.hibernate.sql.exec.spi.ExecutionContext;
*
* @author Steve Ebersole
*/
public class LoadingCollectionEntry {
private final CollectionPersister collectionDescriptor;
private final CollectionInitializer initializer;
// todo (6.0) : change from Serializable to Object
private final Serializable key;
private final PersistentCollection collectionInstance;
public interface LoadingCollectionEntry {
CollectionPersister getCollectionDescriptor();
public LoadingCollectionEntry(
CollectionPersister collectionDescriptor,
CollectionInitializer initializer,
Serializable key,
PersistentCollection collectionInstance) {
this.collectionDescriptor = collectionDescriptor;
this.initializer = initializer;
this.key = key;
this.collectionInstance = collectionInstance;
CollectionInitializer getInitializer();
collectionInstance.beforeInitialize( getCollectionDescriptor(), -1 );
collectionInstance.beginRead();
}
Serializable getKey();
public CollectionPersister getCollectionDescriptor() {
return collectionDescriptor;
}
PersistentCollection getCollectionInstance();
/**
* Access to the initializer that is responsible for initializing this collection
*/
public CollectionInitializer getInitializer() {
return initializer;
}
public Serializable getKey() {
return key;
}
public PersistentCollection getCollectionInstance() {
return collectionInstance;
}
@Override
public String toString() {
return getClass().getSimpleName() + "(" + getCollectionDescriptor().getNavigableRole().getFullPath() + "#" + getKey() + ")";
}
public void finishLoading(ExecutionContext executionContext) {
collectionInstance.endRead();
final SharedSessionContractImplementor session = executionContext.getSession();
final PersistenceContext persistenceContext = session.getPersistenceContext();
final CollectionPersister collectionDescriptor = getCollectionDescriptor();
CollectionEntry collectionEntry = persistenceContext.getCollectionEntry( collectionInstance );
if ( collectionEntry == null ) {
collectionEntry = persistenceContext.addInitializedCollection(
collectionDescriptor,
getCollectionInstance(),
getKey()
);
}
else {
collectionEntry.postInitialize( collectionInstance );
}
if ( collectionDescriptor.getCollectionType().hasHolder() ) {
persistenceContext.addCollectionHolder( collectionInstance );
}
// todo (6.0) : there is other logic still needing to be implemented here. caching, etc
// see org.hibernate.engine.loading.internal.CollectionLoadContext#endLoadingCollection in 5.x
}
void finishLoading(ExecutionContext executionContext);
}

View File

@ -7,6 +7,7 @@
package org.hibernate.type.descriptor.java;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.spi.Primitive;
import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;
@ -16,7 +17,7 @@ import static java.lang.Boolean.TRUE;
*
* @author Steve Ebersole
*/
public class BooleanTypeDescriptor extends AbstractTypeDescriptor<Boolean> {
public class BooleanTypeDescriptor extends AbstractTypeDescriptor<Boolean> implements Primitive<Boolean> {
public static final BooleanTypeDescriptor INSTANCE = new BooleanTypeDescriptor();
private final char characterValueTrue;
@ -130,4 +131,14 @@ public class BooleanTypeDescriptor extends AbstractTypeDescriptor<Boolean> {
public Long toLong(Boolean value) {
return (long) toInt( value );
}
@Override
public Class getPrimitiveClass() {
return boolean.class;
}
@Override
public Boolean getDefaultValue() {
return FALSE;
}
}

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.type.descriptor.java;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.spi.Primitive;
/**
* Descriptor for {@link Byte} handling.
@ -13,7 +14,7 @@ import org.hibernate.type.descriptor.WrapperOptions;
* @author Steve Ebersole
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public class ByteTypeDescriptor extends AbstractTypeDescriptor<Byte> {
public class ByteTypeDescriptor extends AbstractTypeDescriptor<Byte> implements Primitive<Byte> {
public static final ByteTypeDescriptor INSTANCE = new ByteTypeDescriptor();
public ByteTypeDescriptor() {
@ -58,6 +59,7 @@ public class ByteTypeDescriptor extends AbstractTypeDescriptor<Byte> {
}
throw unknownUnwrap( type );
}
@Override
public <X> Byte wrap(X value, WrapperOptions options) {
if ( value == null ) {
@ -74,4 +76,14 @@ public class ByteTypeDescriptor extends AbstractTypeDescriptor<Byte> {
}
throw unknownWrap( value.getClass() );
}
@Override
public Class getPrimitiveClass() {
return byte.class;
}
@Override
public Byte getDefaultValue() {
return 0;
}
}

View File

@ -7,13 +7,14 @@
package org.hibernate.type.descriptor.java;
import org.hibernate.HibernateException;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.spi.Primitive;
/**
* Descriptor for {@link Character} handling.
*
* @author Steve Ebersole
*/
public class CharacterTypeDescriptor extends AbstractTypeDescriptor<Character> {
public class CharacterTypeDescriptor extends AbstractTypeDescriptor<Character> implements Primitive<Character> {
public static final CharacterTypeDescriptor INSTANCE = new CharacterTypeDescriptor();
public CharacterTypeDescriptor() {
@ -66,4 +67,14 @@ public class CharacterTypeDescriptor extends AbstractTypeDescriptor<Character> {
}
throw unknownWrap( value.getClass() );
}
@Override
public Class getPrimitiveClass() {
return char.class;
}
@Override
public Character getDefaultValue() {
return 0;
}
}

View File

@ -10,13 +10,14 @@ import java.math.BigDecimal;
import java.math.BigInteger;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.spi.Primitive;
/**
* Descriptor for {@link Double} handling.
*
* @author Steve Ebersole
*/
public class DoubleTypeDescriptor extends AbstractTypeDescriptor<Double> {
public class DoubleTypeDescriptor extends AbstractTypeDescriptor<Double> implements Primitive<Double> {
public static final DoubleTypeDescriptor INSTANCE = new DoubleTypeDescriptor();
public DoubleTypeDescriptor() {
@ -71,15 +72,25 @@ public class DoubleTypeDescriptor extends AbstractTypeDescriptor<Double> {
if ( value == null ) {
return null;
}
if ( Double.class.isInstance( value ) ) {
if ( value instanceof Double ) {
return (Double) value;
}
if ( Number.class.isInstance( value ) ) {
if ( value instanceof Number ) {
return ( (Number) value ).doubleValue();
}
else if ( String.class.isInstance( value ) ) {
else if ( value instanceof String ) {
return Double.valueOf( ( (String) value ) );
}
throw unknownWrap( value.getClass() );
}
@Override
public Class getPrimitiveClass() {
return double.class;
}
@Override
public Double getDefaultValue() {
return 0.0;
}
}

View File

@ -10,13 +10,14 @@ import java.math.BigDecimal;
import java.math.BigInteger;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.spi.Primitive;
/**
* Descriptor for {@link Float} handling.
*
* @author Steve Ebersole
*/
public class FloatTypeDescriptor extends AbstractTypeDescriptor<Float> {
public class FloatTypeDescriptor extends AbstractTypeDescriptor<Float> implements Primitive<Float> {
public static final FloatTypeDescriptor INSTANCE = new FloatTypeDescriptor();
public FloatTypeDescriptor() {
@ -82,4 +83,14 @@ public class FloatTypeDescriptor extends AbstractTypeDescriptor<Float> {
}
throw unknownWrap( value.getClass() );
}
@Override
public Class getPrimitiveClass() {
return float.class;
}
@Override
public Float getDefaultValue() {
return 0F;
}
}

View File

@ -10,13 +10,14 @@ import java.math.BigDecimal;
import java.math.BigInteger;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.spi.Primitive;
/**
* Descriptor for {@link Integer} handling.
*
* @author Steve Ebersole
*/
public class IntegerTypeDescriptor extends AbstractTypeDescriptor<Integer> {
public class IntegerTypeDescriptor extends AbstractTypeDescriptor<Integer> implements Primitive<Integer> {
public static final IntegerTypeDescriptor INSTANCE = new IntegerTypeDescriptor();
public IntegerTypeDescriptor() {
@ -82,4 +83,14 @@ public class IntegerTypeDescriptor extends AbstractTypeDescriptor<Integer> {
}
throw unknownWrap( value.getClass() );
}
@Override
public Class getPrimitiveClass() {
return int.class;
}
@Override
public Integer getDefaultValue() {
return 0;
}
}

View File

@ -10,13 +10,14 @@ import java.math.BigDecimal;
import java.math.BigInteger;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.spi.Primitive;
/**
* Descriptor for {@link Long} handling.
*
* @author Steve Ebersole
*/
public class LongTypeDescriptor extends AbstractTypeDescriptor<Long> {
public class LongTypeDescriptor extends AbstractTypeDescriptor<Long>implements Primitive<Long> {
public static final LongTypeDescriptor INSTANCE = new LongTypeDescriptor();
public LongTypeDescriptor() {
@ -82,4 +83,14 @@ public class LongTypeDescriptor extends AbstractTypeDescriptor<Long> {
}
throw unknownWrap( value.getClass() );
}
@Override
public Class getPrimitiveClass() {
return long.class;
}
@Override
public Long getDefaultValue() {
return 0L;
}
}

View File

@ -6,13 +6,14 @@
*/
package org.hibernate.type.descriptor.java;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.spi.Primitive;
/**
* Descriptor for {@link Short} handling.
*
* @author Steve Ebersole
*/
public class ShortTypeDescriptor extends AbstractTypeDescriptor<Short> {
public class ShortTypeDescriptor extends AbstractTypeDescriptor<Short> implements Primitive<Short> {
public static final ShortTypeDescriptor INSTANCE = new ShortTypeDescriptor();
public ShortTypeDescriptor() {
@ -72,4 +73,14 @@ public class ShortTypeDescriptor extends AbstractTypeDescriptor<Short> {
}
throw unknownWrap( value.getClass() );
}
@Override
public Class getPrimitiveClass() {
return short.class;
}
@Override
public Short getDefaultValue() {
return 0;
}
}

View File

@ -39,6 +39,7 @@ public class JavaTypeDescriptorRegistry implements JavaTypeDescriptorBaseline.Ba
@SuppressWarnings("unused")
public JavaTypeDescriptorRegistry(TypeConfiguration typeConfiguration) {
this.typeConfiguration = typeConfiguration;
JavaTypeDescriptorBaseline.prime( this );
}

View File

@ -21,6 +21,7 @@ import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.MappingException;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
import org.hibernate.cache.spi.access.EntityDataAccess;
import org.hibernate.cache.spi.access.NaturalIdDataAccess;
@ -58,6 +59,11 @@ import org.hibernate.persister.spi.PersisterClassResolver;
import org.hibernate.persister.spi.PersisterCreationContext;
import org.hibernate.persister.walking.spi.AttributeDefinition;
import org.hibernate.persister.walking.spi.EntityIdentifierDefinition;
import org.hibernate.query.sqm.sql.SqlExpressionResolver;
import org.hibernate.sql.ast.JoinType;
import org.hibernate.sql.ast.spi.SqlAliasBase;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.tree.from.TableReferenceCollector;
import org.hibernate.tuple.entity.BytecodeEnhancementMetadataNonPojoImpl;
import org.hibernate.tuple.entity.EntityMetamodel;
import org.hibernate.tuple.entity.EntityTuplizer;
@ -717,6 +723,16 @@ public class PersisterClassProviderTest {
public JavaTypeDescriptor getMappedJavaTypeDescriptor() {
return null;
}
@Override
public void applyTableReferences(
SqlAliasBase sqlAliasBase,
JoinType baseJoinType,
TableReferenceCollector collector,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
throw new NotYetImplementedFor6Exception( getClass() );
}
}
public static class GoofyException extends RuntimeException {

View File

@ -6,13 +6,16 @@
*/
package org.hibernate.orm.test.metamodel.mapping;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.AttributeConverter;
import javax.persistence.CascadeType;
import javax.persistence.Convert;
import javax.persistence.ElementCollection;
import javax.persistence.Embeddable;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
@ -21,14 +24,20 @@ import javax.persistence.OneToMany;
import javax.persistence.OrderColumn;
import javax.persistence.Table;
import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.DomainMetamodel;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
/**
* @author Steve Ebersole
*/
@ -36,6 +45,7 @@ import org.junit.jupiter.api.Test;
annotatedClasses = {
PluralAttributeTests.SimpleEntity.class,
PluralAttributeTests.EntityContainingLists.class,
PluralAttributeTests.EntityContainingSets.class,
PluralAttributeTests.Component.class
}
)
@ -46,51 +56,50 @@ public class PluralAttributeTests {
@Test
public void testLists(SessionFactoryScope scope) {
System.out.println( "test" );
final DomainMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityMappingType containerEntityDescriptor = domainModel.getEntityDescriptor( EntityContainingLists.class );
assertThat( containerEntityDescriptor.getNumberOfAttributeMappings(), is( 6 ) );
final AttributeMapping listOfBasics = containerEntityDescriptor.findAttributeMapping( "listOfBasics" );
assertThat( listOfBasics, notNullValue() );
final AttributeMapping listOfConvertedBasics = containerEntityDescriptor.findAttributeMapping( "listOfConvertedBasics" );
assertThat( listOfConvertedBasics, notNullValue() );
final AttributeMapping listOfEnums = containerEntityDescriptor.findAttributeMapping( "listOfEnums" );
assertThat( listOfEnums, notNullValue() );
final AttributeMapping listOfComponents = containerEntityDescriptor.findAttributeMapping( "listOfComponents" );
assertThat( listOfComponents, notNullValue() );
final AttributeMapping listOfEntities = containerEntityDescriptor.findAttributeMapping( "listOfEntities" );
assertThat( listOfEntities, notNullValue() );
}
@BeforeAll
public void createTestData(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final EntityContainingLists entityContainingLists = new EntityContainingLists( 1, "first" );
@Test
public void testSets(SessionFactoryScope scope) {
final DomainMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityMappingType containerEntityDescriptor = domainModel.getEntityDescriptor( EntityContainingSets.class );
entityContainingLists.addBasic( "abc" );
entityContainingLists.addBasic( "def" );
entityContainingLists.addBasic( "ghi" );
assertThat( containerEntityDescriptor.getNumberOfAttributeMappings(), is( 6 ) );
entityContainingLists.addConvertedBasic( EnumValue.TWO );
final AttributeMapping setOfBasics = containerEntityDescriptor.findAttributeMapping( "setOfBasics" );
assertThat( setOfBasics, notNullValue() );
entityContainingLists.addEnum( EnumValue.ONE );
entityContainingLists.addEnum( EnumValue.THREE );
final AttributeMapping setOfConvertedBasics = containerEntityDescriptor.findAttributeMapping( "setOfConvertedBasics" );
assertThat( setOfConvertedBasics, notNullValue() );
entityContainingLists.addComponent( new Component( "first-a1", "first-another-a1" ) );
entityContainingLists.addComponent( new Component( "first-a2", "first-another-a2" ) );
entityContainingLists.addSimpleEntity( new SimpleEntity( 1, "simple-1" ) );
entityContainingLists.addSimpleEntity( new SimpleEntity( 2, "simple-2" ) );
final AttributeMapping setOfEnums = containerEntityDescriptor.findAttributeMapping( "setOfEnums" );
assertThat( setOfEnums, notNullValue() );
session.save( entityContainingLists );
}
);
}
final AttributeMapping setOfComponents = containerEntityDescriptor.findAttributeMapping( "setOfComponents" );
assertThat( setOfComponents, notNullValue() );
@AfterAll
public void deleteTestData(SessionFactoryScope scope) {
scope.inTransaction(
session -> session.doWork(
conn -> {
try ( Statement stmnt = conn.createStatement() ) {
stmnt.execute( "delete from EntityContainingLists_listOfEnums" );
stmnt.execute( "delete from EntityContainingLists_listOfConvertedBasics" );
stmnt.execute( "delete from EntityContainingLists_listOfComponents" );
stmnt.execute( "delete from EntityContainingLists_listOfBasics" );
stmnt.execute( "delete from entity_containing_lists_simple_entity" );
stmnt.execute( "delete from entity_containing_lists" );
}
}
)
);
final AttributeMapping setOfEntities = containerEntityDescriptor.findAttributeMapping( "setOfEntities" );
assertThat( setOfEntities, notNullValue() );
}
public enum EnumValue {
@ -198,6 +207,7 @@ public class PluralAttributeTests {
@ElementCollection
@OrderColumn
@Convert( converter = Converter.class )
public List<EnumValue> getListOfConvertedBasics() {
return listOfConvertedBasics;
}
@ -266,6 +276,127 @@ public class PluralAttributeTests {
}
}
@Entity( name = "EntityContainingSets" )
@Table( name = "entity_containing_sets" )
public static class EntityContainingSets {
private Integer id;
private String name;
private Set<String> setOfBasics;
private Set<EnumValue> setOfConvertedBasics;
private Set<EnumValue> setOfEnums;
private Set<Component> setOfComponents;
private Set<SimpleEntity> setOfEntities;
public EntityContainingSets() {
}
public EntityContainingSets(Integer id, String name) {
this.id = id;
this.name = name;
}
@Id
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@ElementCollection
public Set<String> getSetOfBasics() {
return setOfBasics;
}
public void setSetOfBasics(Set<String> setOfBasics) {
this.setOfBasics = setOfBasics;
}
public void addBasic(String value) {
if ( setOfBasics == null ) {
setOfBasics = new HashSet<>();
}
setOfBasics.add( value );
}
@ElementCollection
@Convert( converter = Converter.class )
public Set<EnumValue> getSetOfConvertedBasics() {
return setOfConvertedBasics;
}
public void setSetOfConvertedBasics(Set<EnumValue> setOfConvertedBasics) {
this.setOfConvertedBasics = setOfConvertedBasics;
}
public void addConvertedBasic(EnumValue value) {
if ( setOfConvertedBasics == null ) {
setOfConvertedBasics = new HashSet<>();
}
setOfConvertedBasics.add( value );
}
@ElementCollection
@Enumerated( EnumType.STRING )
public Set<EnumValue> getSetOfEnums() {
return setOfEnums;
}
public void setSetOfEnums(Set<EnumValue> setOfEnums) {
this.setOfEnums = setOfEnums;
}
public void addEnum(EnumValue value) {
if ( setOfEnums == null ) {
setOfEnums = new HashSet<>();
}
setOfEnums.add( value );
}
@ElementCollection
@Embedded
public Set<Component> getSetOfComponents() {
return setOfComponents;
}
public void setSetOfComponents(Set<Component> setOfComponents) {
this.setOfComponents = setOfComponents;
}
public void addComponent(Component value) {
if ( setOfComponents == null ) {
setOfComponents = new HashSet<>();
}
setOfComponents.add( value );
}
@OneToMany( cascade = CascadeType.ALL )
public Set<SimpleEntity> getSetOfEntities() {
return setOfEntities;
}
public void setSetOfEntities(Set<SimpleEntity> setOfEntities) {
this.setOfEntities = setOfEntities;
}
public void addSimpleEntity(SimpleEntity value) {
if ( setOfEntities == null ) {
setOfEntities = new HashSet<>();
}
setOfEntities.add( value );
}
}
@Entity( name = "SimpleEntity" )
@Table( name = "simple_entity" )
public static class SimpleEntity {

View File

@ -24,7 +24,10 @@ import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
import org.hibernate.metamodel.mapping.internal.SingularAssociationAttributeMapping;
import org.hibernate.metamodel.model.convert.internal.NamedEnumValueConverter;
import org.hibernate.metamodel.model.convert.internal.OrdinalEnumValueConverter;
import org.hibernate.metamodel.model.convert.spi.EnumValueConverter;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.type.CustomType;
import org.hibernate.usertype.UserType;
import org.hibernate.testing.hamcrest.CollectionMatchers;
import org.hibernate.testing.orm.junit.DomainModel;
@ -72,8 +75,12 @@ public class SmokeTests {
final BasicValuedSingularAttributeMapping genderAttrMapping = (BasicValuedSingularAttributeMapping) genderPart;
assert "mapping_simple_entity".equals( genderAttrMapping.getContainingTableExpression() );
assert "gender".equals( genderAttrMapping.getMappedColumnExpression() );
assert genderAttrMapping.getConverter() != null;
assert genderAttrMapping.getConverter() instanceof OrdinalEnumValueConverter;
assert genderAttrMapping.getMappedTypeDescriptor() instanceof CustomType;
final UserType userType = ( (CustomType) genderAttrMapping.getMappedTypeDescriptor() ).getUserType();
assert userType instanceof org.hibernate.type.EnumType;
final EnumValueConverter converter = ( (org.hibernate.type.EnumType) userType ).getEnumValueConverter();
assert converter != null;
assert converter instanceof OrdinalEnumValueConverter;
}
{
@ -82,8 +89,13 @@ public class SmokeTests {
final BasicValuedSingularAttributeMapping attrMapping = (BasicValuedSingularAttributeMapping) part;
assert "mapping_simple_entity".equals( attrMapping.getContainingTableExpression() );
assert "gender2".equals( attrMapping.getMappedColumnExpression() );
assert attrMapping.getConverter() != null;
assert attrMapping.getConverter() instanceof NamedEnumValueConverter;
assert attrMapping.getMappedTypeDescriptor() instanceof CustomType;
final UserType userType = ( (CustomType) attrMapping.getMappedTypeDescriptor() ).getUserType();
assert userType instanceof org.hibernate.type.EnumType;
final EnumValueConverter converter = ( (org.hibernate.type.EnumType) userType ).getEnumValueConverter();
assert converter != null;
assert converter instanceof NamedEnumValueConverter;
}
{

View File

@ -35,7 +35,10 @@ import org.hibernate.sql.results.internal.domain.basic.BasicResult;
import org.hibernate.sql.results.internal.SqlSelectionImpl;
import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.type.CustomType;
import org.hibernate.type.EnumType;
import org.hibernate.type.internal.StandardBasicTypeImpl;
import org.hibernate.usertype.UserType;
import org.hibernate.testing.hamcrest.AssignableMatcher;
import org.hibernate.testing.orm.junit.DomainModel;
@ -49,6 +52,7 @@ import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
/**
@ -174,10 +178,15 @@ public class SmokeTests {
assertThat( columnReference.renderSqlFragment( scope.getSessionFactory() ), is( "s1_0.gender" ) );
final MappingModelExpressable selectedExpressable = selectedExpression.getExpressionType();
assertThat( selectedExpressable, instanceOf( StandardBasicTypeImpl.class ) );
final StandardBasicTypeImpl basicType = (StandardBasicTypeImpl) selectedExpressable;
assertThat( basicType.getJavaTypeDescriptor().getJavaType(), AssignableMatcher.assignableTo( Integer.class ) );
assertThat( basicType.getSqlTypeDescriptor().getSqlType(), is( Types.INTEGER ) );
//assertThat( selectedExpressable, instanceOf( StandardBasicTypeImpl.class ) );
// assertThat( basicType.getJavaTypeDescriptor().getJavaType(), AssignableMatcher.assignableTo( Integer.class ) );
// assertThat( basicType.getSqlTypeDescriptor().getSqlType(), is( Types.INTEGER ) );
assertThat( selectedExpressable, instanceOf( CustomType.class ) );
final CustomType basicType = (CustomType) selectedExpressable;
final EnumType enumType = (EnumType) basicType.getUserType();
assertThat( enumType.getEnumValueConverter().getRelationalJavaDescriptor().getJavaType(), AssignableMatcher.assignableTo( Integer.class ) );
assertThat( enumType.sqlTypes()[0], is( Types.INTEGER ) );
assertThat( sqlAst.getDomainResultDescriptors().size(), is( 1 ) );
final DomainResult domainResult = sqlAst.getDomainResultDescriptors().get( 0 );
@ -185,8 +194,10 @@ public class SmokeTests {
final BasicResult scalarDomainResult = (BasicResult) domainResult;
assertThat( scalarDomainResult.getAssembler(), instanceOf( BasicResultAssembler.class ) );
final BasicResultAssembler<?> assembler = (BasicResultAssembler) scalarDomainResult.getAssembler();
assertThat( assembler.getValueConverter(), notNullValue() );
assertThat( assembler.getValueConverter(), instanceOf( OrdinalEnumValueConverter.class ) );
// assertThat( assembler.getValueConverter(), notNullValue() );
// assertThat( assembler.getValueConverter(), instanceOf( OrdinalEnumValueConverter.class ) );
assertThat( assembler.getValueConverter(), nullValue() );
final NavigablePath expectedSelectedPath = new NavigablePath(
org.hibernate.orm.test.metamodel.mapping.SmokeTests.SimpleEntity.class.getName(),
"e"
@ -202,9 +213,10 @@ public class SmokeTests {
);
assertThat( resultAssembler, instanceOf( BasicResultAssembler.class ) );
final BasicValueConverter valueConverter = ( (BasicResultAssembler) resultAssembler ).getValueConverter();
assertThat( valueConverter, notNullValue() );
assertThat( valueConverter, instanceOf( OrdinalEnumValueConverter.class ) );
// final BasicValueConverter valueConverter = ( (BasicResultAssembler) resultAssembler ).getValueConverter();
// assertThat( valueConverter, notNullValue() );
// assertThat( valueConverter, instanceOf( OrdinalEnumValueConverter.class ) );
assertThat( ( (BasicResultAssembler) resultAssembler ).getValueConverter(), nullValue() );
final JdbcSelect jdbcSelectOperation = new StandardSqlAstSelectTranslator( session.getSessionFactory() )
.interpret( sqlAst );

View File

@ -0,0 +1,196 @@
/*
* 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.sql.exec;
import java.sql.Statement;
import org.hibernate.Hibernate;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.orm.test.metamodel.mapping.PluralAttributeTests.Component;
import org.hibernate.orm.test.metamodel.mapping.PluralAttributeTests.EntityContainingLists;
import org.hibernate.orm.test.metamodel.mapping.PluralAttributeTests.EntityContainingSets;
import org.hibernate.orm.test.metamodel.mapping.PluralAttributeTests.EnumValue;
import org.hibernate.orm.test.metamodel.mapping.PluralAttributeTests.SimpleEntity;
import org.hibernate.query.spi.QueryImplementor;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.hamcrest.CoreMatchers;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* @author Steve Ebersole
*/
@DomainModel(
annotatedClasses = {
SimpleEntity.class,
EntityContainingLists.class,
EntityContainingSets.class,
Component.class
}
)
@ServiceRegistry
@SessionFactory
@SuppressWarnings("WeakerAccess")
public class PluralAttributeSmokeTests {
@Test
public void listBaselineTest(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final QueryImplementor<EntityContainingLists> query = session.createQuery(
"select e from EntityContainingLists e",
EntityContainingLists.class
);
final EntityContainingLists result = query.uniqueResult();
assertThat( result, notNullValue() );
assertThat( result.getListOfBasics(), notNullValue() );
assertThat( Hibernate.isInitialized( result.getListOfBasics() ), is( false ) );
}
);
}
@Test
public void listEagerBasicTest(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final QueryImplementor<EntityContainingLists> query = session.createQuery(
"select e from EntityContainingLists e join fetch e.listOfBasics",
EntityContainingLists.class
);
final EntityContainingLists result = query.uniqueResult();
assertThat( result, notNullValue() );
assertThat( result.getListOfBasics(), notNullValue() );
assertThat( Hibernate.isInitialized( result.getListOfBasics() ), is( true ) );
assertTrue( session.getPersistenceContext().containsCollection( (PersistentCollection) result.getListOfBasics() ) );
assertThat( result.getListOfBasics().size(), is( 3 ) );
assertThat( result.getListOfConvertedBasics(), notNullValue() );
assertThat( Hibernate.isInitialized( result.getListOfConvertedBasics() ), is( false ) );
assertTrue( session.getPersistenceContext().containsCollection( (PersistentCollection) result.getListOfConvertedBasics() ) );
assertThat( result.getListOfEnums(), notNullValue() );
assertThat( Hibernate.isInitialized( result.getListOfEnums() ), is( false ) );
assertTrue( session.getPersistenceContext().containsCollection( (PersistentCollection) result.getListOfEnums() ) );
assertThat( result.getListOfComponents(), notNullValue() );
assertThat( Hibernate.isInitialized( result.getListOfComponents() ), is( false ) );
assertTrue( session.getPersistenceContext().containsCollection( (PersistentCollection) result.getListOfComponents() ) );
assertThat( result.getListOfEntities(), notNullValue() );
assertThat( Hibernate.isInitialized( result.getListOfEntities() ), is( false ) );
assertTrue( session.getPersistenceContext().containsCollection( (PersistentCollection) result.getListOfEntities() ) );
}
);
}
@Test
public void setBaselineTest(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final QueryImplementor<EntityContainingSets> query = session.createQuery(
"select e from EntityContainingSets e",
EntityContainingSets.class
);
final EntityContainingSets result = query.uniqueResult();
assertThat( result, notNullValue() );
assertThat( result.getSetOfBasics(), notNullValue() );
assertThat( Hibernate.isInitialized( result.getSetOfBasics() ), is( false ) );
}
);
}
@BeforeAll
public void createTestData(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final SimpleEntity simpleEntity1 = new SimpleEntity( 1, "simple-1" );
final SimpleEntity simpleEntity2 = new SimpleEntity( 2, "simple-2" );
session.save( simpleEntity1 );
session.save( simpleEntity2 );
{
final EntityContainingLists entityContainingLists = new EntityContainingLists( 1, "first" );
entityContainingLists.addBasic( "abc" );
entityContainingLists.addBasic( "def" );
entityContainingLists.addBasic( "ghi" );
entityContainingLists.addConvertedBasic( EnumValue.TWO );
entityContainingLists.addEnum( EnumValue.ONE );
entityContainingLists.addEnum( EnumValue.THREE );
entityContainingLists.addComponent( new Component( "first-a1", "first-another-a1" ) );
entityContainingLists.addComponent( new Component( "first-a2", "first-another-a2" ) );
entityContainingLists.addSimpleEntity( simpleEntity1 );
entityContainingLists.addSimpleEntity( simpleEntity2 );
session.save( entityContainingLists );
}
{
final EntityContainingSets entity = new EntityContainingSets( 1, "first" );
entity.addBasic( "abc" );
entity.addBasic( "def" );
entity.addBasic( "ghi" );
entity.addConvertedBasic( EnumValue.TWO );
entity.addEnum( EnumValue.ONE );
entity.addEnum( EnumValue.THREE );
entity.addComponent( new Component( "first-a1", "first-another-a1" ) );
entity.addComponent( new Component( "first-a2", "first-another-a2" ) );
entity.addSimpleEntity( simpleEntity1 );
entity.addSimpleEntity( simpleEntity2 );
session.save( entity );
}
}
);
}
@AfterAll
public void deleteTestData(SessionFactoryScope scope) {
scope.inTransaction(
session -> session.doWork(
conn -> {
try ( Statement stmnt = conn.createStatement() ) {
stmnt.execute( "delete from EntityContainingLists_listOfEnums" );
stmnt.execute( "delete from EntityContainingLists_listOfConvertedBasics" );
stmnt.execute( "delete from EntityContainingLists_listOfComponents" );
stmnt.execute( "delete from EntityContainingLists_listOfBasics" );
stmnt.execute( "delete from entity_containing_lists_simple_entity" );
stmnt.execute( "delete from entity_containing_lists" );
}
}
)
);
}
}

View File

@ -12,7 +12,6 @@ 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;

View File

@ -20,6 +20,7 @@ import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.MappingException;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
import org.hibernate.cache.spi.access.CollectionDataAccess;
import org.hibernate.cache.spi.access.EntityDataAccess;
@ -58,6 +59,11 @@ import org.hibernate.persister.walking.spi.AttributeDefinition;
import org.hibernate.persister.walking.spi.CollectionElementDefinition;
import org.hibernate.persister.walking.spi.CollectionIndexDefinition;
import org.hibernate.persister.walking.spi.EntityIdentifierDefinition;
import org.hibernate.query.sqm.sql.SqlExpressionResolver;
import org.hibernate.sql.ast.JoinType;
import org.hibernate.sql.ast.spi.SqlAliasBase;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.tree.from.TableReferenceCollector;
import org.hibernate.tuple.entity.BytecodeEnhancementMetadataNonPojoImpl;
import org.hibernate.tuple.entity.EntityMetamodel;
import org.hibernate.tuple.entity.EntityTuplizer;
@ -703,6 +709,16 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver {
public JavaTypeDescriptor getMappedJavaTypeDescriptor() {
return null;
}
@Override
public void applyTableReferences(
SqlAliasBase sqlAliasBase,
JoinType baseJoinType,
TableReferenceCollector collector,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
throw new NotYetImplementedFor6Exception( getClass() );
}
}
public static class NoopCollectionPersister implements CollectionPersister {

View File

@ -21,6 +21,7 @@ import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.MappingException;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
import org.hibernate.cache.spi.access.EntityDataAccess;
import org.hibernate.cache.spi.access.NaturalIdDataAccess;
@ -59,6 +60,11 @@ import org.hibernate.persister.entity.MultiLoadOptions;
import org.hibernate.persister.spi.PersisterCreationContext;
import org.hibernate.persister.walking.spi.AttributeDefinition;
import org.hibernate.persister.walking.spi.EntityIdentifierDefinition;
import org.hibernate.query.sqm.sql.SqlExpressionResolver;
import org.hibernate.sql.ast.JoinType;
import org.hibernate.sql.ast.spi.SqlAliasBase;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.tree.from.TableReferenceCollector;
import org.hibernate.tuple.entity.BytecodeEnhancementMetadataNonPojoImpl;
import org.hibernate.tuple.entity.EntityMetamodel;
import org.hibernate.tuple.entity.EntityTuplizer;
@ -815,4 +821,14 @@ public class CustomPersister implements EntityPersister {
public JavaTypeDescriptor getMappedJavaTypeDescriptor() {
return null;
}
@Override
public void applyTableReferences(
SqlAliasBase sqlAliasBase,
JoinType baseJoinType,
TableReferenceCollector collector,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
throw new NotYetImplementedFor6Exception( getClass() );
}
}