diff --git a/hibernate-core/src/main/java/org/hibernate/loader/entity/EntityLoader.java b/hibernate-core/src/main/java/org/hibernate/loader/entity/EntityLoader.java index 074f975994..d7be98e426 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/entity/EntityLoader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/entity/EntityLoader.java @@ -6,28 +6,15 @@ */ package org.hibernate.loader.entity; -import org.hibernate.HibernateException; import org.hibernate.LockMode; import org.hibernate.LockOptions; import org.hibernate.MappingException; -import org.hibernate.engine.jdbc.Size; import org.hibernate.engine.spi.LoadQueryInfluencers; -import org.hibernate.engine.spi.Mapping; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.internal.util.collections.ArrayHelper; import org.hibernate.persister.entity.OuterJoinLoadable; -import org.hibernate.type.AbstractType; import org.hibernate.type.Type; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; - /** * Loads an entity instance using outerjoin fetching to fetch associated entities. *
@@ -162,23 +149,14 @@ public class EntityLoader extends AbstractEntityLoader { LoadQueryInfluencers loadQueryInfluencers) throws MappingException { super( persister, new NaturalIdType( persister, valueNullness ), factory, loadQueryInfluencers ); - EntityJoinWalker walker = new EntityJoinWalker( + EntityJoinWalker walker = new NaturalIdEntityJoinWalker( persister, - naturalIdColumns( valueNullness ), + valueNullness, batchSize, lockOptions, factory, loadQueryInfluencers - ) { - @Override - protected StringBuilder whereString(String alias, String[] columnNames, int batchSize) { - StringBuilder sql = super.whereString(alias, columnNames, batchSize); - for (String nullCol : naturalIdColumns( ArrayHelper.negate( valueNullness ) ) ) { - sql.append(" and ").append( getAlias() ).append('.').append(nullCol).append(" is null"); - } - return sql; - } - }; + ); initFromWalker( walker ); compositeKeyManyToOneTargetIndices = walker.getCompositeKeyManyToOneTargetIndices(); postInstantiate(); @@ -194,17 +172,6 @@ public class EntityLoader extends AbstractEntityLoader { } } - private String[] naturalIdColumns(boolean[] valueNullness) { - int i = 0; - List columns = new ArrayList<>(); - for ( int p : persister.getNaturalIdentifierProperties() ) { - if ( !valueNullness[i++] ) { - columns.addAll( Arrays.asList( persister.getPropertyColumnNames(p) ) ); - } - } - return columns.toArray(ArrayHelper.EMPTY_STRING_ARRAY); - } - public Object loadByUniqueKey(SharedSessionContractImplementor session, Object key) { return loadByUniqueKey( session, key, null ); } @@ -223,117 +190,4 @@ public class EntityLoader extends AbstractEntityLoader { return compositeKeyManyToOneTargetIndices; } - static class NaturalIdType extends AbstractType { - private OuterJoinLoadable persister; - private boolean[] valueNullness; - - NaturalIdType(OuterJoinLoadable persister, boolean[] valueNullness) { - this.persister = persister; - this.valueNullness = valueNullness; - } - - @Override - public int getColumnSpan(Mapping mapping) throws MappingException { - int span = 0; - int i = 0; - for ( int p : persister.getNaturalIdentifierProperties() ) { - if ( !valueNullness[i++] ) { - span += persister.getPropertyColumnNames(p).length; - } - } - return span; - } - - @Override - public int[] sqlTypes(Mapping mapping) throws MappingException { - throw new UnsupportedOperationException(); - } - - @Override - public Size[] dictatedSizes(Mapping mapping) throws MappingException { - throw new UnsupportedOperationException(); - } - - @Override - public Size[] defaultSizes(Mapping mapping) throws MappingException { - throw new UnsupportedOperationException(); - } - - @Override - public Class getReturnedClass() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isDirty(Object oldState, Object currentState, boolean[] checkable, SharedSessionContractImplementor session) - throws HibernateException { - throw new UnsupportedOperationException(); - } - - @Override - public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) - throws HibernateException, SQLException { - throw new UnsupportedOperationException(); - } - - @Override - public Object nullSafeGet(ResultSet rs, String name, SharedSessionContractImplementor session, Object owner) - throws HibernateException, SQLException { - throw new UnsupportedOperationException(); - } - - @Override - public void nullSafeSet(PreparedStatement st, Object value, int index, boolean[] settable, SharedSessionContractImplementor session) - throws HibernateException, SQLException { - throw new UnsupportedOperationException(); - } - - @Override - public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) - throws HibernateException, SQLException { - Object[] keys = (Object[]) value; - int i = 0; - for ( int p : persister.getNaturalIdentifierProperties() ) { - if ( !valueNullness[i] ) { - persister.getPropertyTypes()[p].nullSafeSet( st, keys[i], index++, session ); - } - i++; - } - } - - @Override - public String toLoggableString(Object value, SessionFactoryImplementor factory) { - return "natural id"; - } - - @Override - public String getName() { - throw new UnsupportedOperationException(); - } - - @Override - public Object deepCopy(Object value, SessionFactoryImplementor factory) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isMutable() { - throw new UnsupportedOperationException(); - } - - @Override - public Object resolve(Object value, SharedSessionContractImplementor session, Object owner, Boolean overridingEager) { - throw new UnsupportedOperationException(); - } - - @Override - public Object replace(Object original, Object target, SharedSessionContractImplementor session, Object owner, Map copyCache) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean[] toColumnNullness(Object value, Mapping mapping) { - throw new UnsupportedOperationException(); - } - } } diff --git a/hibernate-core/src/main/java/org/hibernate/loader/entity/NaturalIdEntityJoinWalker.java b/hibernate-core/src/main/java/org/hibernate/loader/entity/NaturalIdEntityJoinWalker.java new file mode 100644 index 0000000000..46ea96e9e5 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/loader/entity/NaturalIdEntityJoinWalker.java @@ -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 . + */ +package org.hibernate.loader.entity; + +import org.hibernate.LockOptions; +import org.hibernate.MappingException; +import org.hibernate.engine.spi.LoadQueryInfluencers; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.persister.entity.Loadable; +import org.hibernate.persister.entity.OuterJoinLoadable; + +import java.util.ArrayList; +import java.util.List; + +import static java.util.Arrays.asList; +import static org.hibernate.internal.util.collections.ArrayHelper.EMPTY_STRING_ARRAY; +import static org.hibernate.internal.util.collections.ArrayHelper.negate; + +/** + * An {@link EntityJoinWalker} that uses 'is null' predicates to match + * null {@link org.hibernate.annotations.NaturalId} properties. + * + * @author Gavin King + */ +public class NaturalIdEntityJoinWalker extends EntityJoinWalker { + + private static String[] naturalIdColumns(Loadable persister, boolean[] valueNullness) { + int i = 0; + List columns = new ArrayList<>(); + for ( int p : persister.getNaturalIdentifierProperties() ) { + if ( !valueNullness[i++] ) { + columns.addAll( asList( persister.getPropertyColumnNames(p) ) ); + } + } + return columns.toArray(EMPTY_STRING_ARRAY); + } + + public NaturalIdEntityJoinWalker( + OuterJoinLoadable persister, + boolean[] valueNullness, + int batchSize, + LockOptions lockOptions, + SessionFactoryImplementor factory, + LoadQueryInfluencers loadQueryInfluencers) throws MappingException { + super(persister, naturalIdColumns( persister, valueNullness ), batchSize, lockOptions, factory, loadQueryInfluencers); + StringBuilder sql = new StringBuilder( getSQLString() ); + for ( String nullCol : naturalIdColumns( getPersister(), negate( valueNullness ) ) ) { + sql.append(" and ").append( getAlias() ).append('.').append( nullCol ).append(" is null"); + } + setSql( sql.toString() ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/loader/entity/NaturalIdType.java b/hibernate-core/src/main/java/org/hibernate/loader/entity/NaturalIdType.java new file mode 100644 index 0000000000..c515660d5c --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/loader/entity/NaturalIdType.java @@ -0,0 +1,142 @@ +/* + * 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 . + */ +package org.hibernate.loader.entity; + +import org.hibernate.HibernateException; +import org.hibernate.MappingException; +import org.hibernate.engine.jdbc.Size; +import org.hibernate.engine.spi.Mapping; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.persister.entity.OuterJoinLoadable; +import org.hibernate.type.AbstractType; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Map; + +/** + * Workaround for the fact that we don't have a well-defined Hibernate + * type when loading by multiple {@link org.hibernate.annotations.NaturalId} + * properties. + * + * @author Gavin King + */ +public class NaturalIdType extends AbstractType { + private OuterJoinLoadable persister; + private boolean[] valueNullness; + + public NaturalIdType(OuterJoinLoadable persister, boolean[] valueNullness) { + this.persister = persister; + this.valueNullness = valueNullness; + } + + @Override + public int getColumnSpan(Mapping mapping) throws MappingException { + int span = 0; + int i = 0; + for (int p : persister.getNaturalIdentifierProperties() ) { + if ( !valueNullness[i++] ) { + span += persister.getPropertyColumnNames(p).length; + } + } + return span; + } + + @Override + public int[] sqlTypes(Mapping mapping) throws MappingException { + throw new UnsupportedOperationException(); + } + + @Override + public Size[] dictatedSizes(Mapping mapping) throws MappingException { + throw new UnsupportedOperationException(); + } + + @Override + public Size[] defaultSizes(Mapping mapping) throws MappingException { + throw new UnsupportedOperationException(); + } + + @Override + public Class getReturnedClass() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isDirty(Object oldState, Object currentState, boolean[] checkable, SharedSessionContractImplementor session) + throws HibernateException { + throw new UnsupportedOperationException(); + } + + @Override + public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) + throws HibernateException, SQLException { + throw new UnsupportedOperationException(); + } + + @Override + public Object nullSafeGet(ResultSet rs, String name, SharedSessionContractImplementor session, Object owner) + throws HibernateException, SQLException { + throw new UnsupportedOperationException(); + } + + @Override + public void nullSafeSet(PreparedStatement st, Object value, int index, boolean[] settable, SharedSessionContractImplementor session) + throws HibernateException, SQLException { + throw new UnsupportedOperationException(); + } + + @Override + public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) + throws HibernateException, SQLException { + Object[] keys = (Object[]) value; + int i = 0; + for ( int p : persister.getNaturalIdentifierProperties() ) { + if ( !valueNullness[i] ) { + persister.getPropertyTypes()[p].nullSafeSet( st, keys[i], index++, session ); + } + i++; + } + } + + @Override + public String toLoggableString(Object value, SessionFactoryImplementor factory) { + return "natural id"; + } + + @Override + public String getName() { + throw new UnsupportedOperationException(); + } + + @Override + public Object deepCopy(Object value, SessionFactoryImplementor factory) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isMutable() { + throw new UnsupportedOperationException(); + } + + @Override + public Object resolve(Object value, SharedSessionContractImplementor session, Object owner, Boolean overridingEager) { + throw new UnsupportedOperationException(); + } + + @Override + public Object replace(Object original, Object target, SharedSessionContractImplementor session, Object owner, Map copyCache) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean[] toColumnNullness(Object value, Mapping mapping) { + throw new UnsupportedOperationException(); + } +}