diff --git a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/DatabaseSnapshotExecutor.java b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/DatabaseSnapshotExecutor.java index 308c39dc7c..03ff801874 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/DatabaseSnapshotExecutor.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/DatabaseSnapshotExecutor.java @@ -133,14 +133,15 @@ class DatabaseSnapshotExecutor { entityDescriptor.forEachAttributeMapping( attributeMapping -> { final NavigablePath navigablePath = rootPath.append( attributeMapping.getAttributeName() ); - domainResults.add( - attributeMapping.createSnapshotDomainResult( - navigablePath, - rootTableGroup, - null, - state - ) + final DomainResult snapshotDomainResult = attributeMapping.createSnapshotDomainResult( + navigablePath, + rootTableGroup, + null, + state ); + if ( snapshotDomainResult != null ) { + domainResults.add( snapshotDomainResult ); + } } ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ToOneAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ToOneAttributeMapping.java index 7579b607a6..f62e87fc69 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ToOneAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ToOneAttributeMapping.java @@ -88,12 +88,9 @@ import org.hibernate.sql.results.graph.entity.EntityFetch; import org.hibernate.sql.results.graph.entity.EntityValuedFetchable; import org.hibernate.sql.results.graph.entity.internal.EntityDelayedFetchImpl; -import org.hibernate.sql.results.graph.entity.internal.EntityDelayedResultImpl; import org.hibernate.sql.results.graph.entity.internal.EntityFetchJoinedImpl; import org.hibernate.sql.results.graph.entity.internal.EntityFetchSelectImpl; -import org.hibernate.sql.results.graph.entity.internal.EntityResultImpl; import org.hibernate.sql.results.graph.entity.internal.EntityResultJoinedSubclassImpl; -import org.hibernate.sql.results.graph.entity.internal.NotFoundSnapshotResult; import org.hibernate.sql.results.internal.domain.CircularBiDirectionalFetchImpl; import org.hibernate.sql.results.internal.domain.CircularFetchImpl; import org.hibernate.type.ComponentType; @@ -1709,73 +1706,17 @@ public DomainResult createSnapshotDomainResult( TableGroup parentTableGroup, String resultVariable, DomainResultCreationState creationState) { - // We need a join if either - // - the association is mapped with `@NotFound` - // - the key is on the referring side i.e. this is an inverse to-one - // and if the FK refers to a non-PK - final boolean forceJoin = hasNotFoundAction() - || sideNature == ForeignKeyDescriptor.Nature.TARGET - || referencedPropertyName != null; - final TableGroup tableGroupToUse; - if ( forceJoin ) { - tableGroupToUse = creationState.getSqlAstCreationState().getFromClauseAccess().resolveTableGroup( - navigablePath, - np -> { - final TableGroupJoin tableGroupJoin = createTableGroupJoin( - navigablePath, - parentTableGroup, - null, - null, - getDefaultSqlAstJoinType( parentTableGroup ), - true, - false, - creationState.getSqlAstCreationState() - ); - parentTableGroup.addTableGroupJoin( tableGroupJoin ); - return tableGroupJoin.getJoinedGroup(); - } - ); - } - else { - tableGroupToUse = createTableGroupForDelayedFetch( + // it's a Snapshot then we just need the value of the FK when it belongs to the parentTableGroup + if ( sideNature == ForeignKeyDescriptor.Nature.KEY ) { + return foreignKeyDescriptor.getKeyPart().createDomainResult( navigablePath, parentTableGroup, resultVariable, creationState ); } - - if ( hasNotFoundAction() ) { - assert tableGroupToUse != parentTableGroup; - //noinspection unchecked - return new NotFoundSnapshotResult( - navigablePath, - this, - parentTableGroup, - tableGroupToUse, - creationState - ); - } - if ( referencedPropertyName == null ) { - //noinspection unchecked - return new EntityDelayedResultImpl( - navigablePath.append( EntityIdentifierMapping.ROLE_LOCAL_NAME ), - this, - tableGroupToUse, - creationState - ); - } else { - // We don't support proxies based on a non-PK yet, so we must fetch the whole entity - final EntityResultImpl entityResult = new EntityResultImpl( - navigablePath, - this, - tableGroupToUse, - null - ); - entityResult.afterInitialize( entityResult, creationState ); - //noinspection unchecked - return entityResult; + return null; } } @@ -2360,7 +2301,20 @@ public Object disassemble(Object value, SharedSessionContractImplementor session @Override public void addToCacheKey(MutableCacheKeyBuilder cacheKey, Object value, SharedSessionContractImplementor session) { - foreignKeyDescriptor.addToCacheKey( cacheKey, foreignKeyDescriptor.getAssociationKeyFromSide( value, sideNature.inverse(), session ), session ); + final Object cacheValue; + // the value may come from a database snapshot, in this case it corresponds to the value of the key and can be + // added to the cache key + if ( value != null && foreignKeyDescriptor.getJavaType().getJavaTypeClass() == value.getClass() ) { + cacheValue = value; + } + else { + cacheValue = foreignKeyDescriptor.getAssociationKeyFromSide( + value, + sideNature.inverse(), + session + ); + } + foreignKeyDescriptor.addToCacheKey( cacheKey, cacheValue, session ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/NotFoundSnapshotAssembler.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/NotFoundSnapshotAssembler.java deleted file mode 100644 index a83fd7663f..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/NotFoundSnapshotAssembler.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later - * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html - */ -package org.hibernate.sql.results.graph.entity.internal; - -import org.hibernate.FetchNotFoundException; -import org.hibernate.annotations.NotFoundAction; -import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping; -import org.hibernate.spi.NavigablePath; -import org.hibernate.sql.results.graph.DomainResultAssembler; -import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions; -import org.hibernate.sql.results.jdbc.spi.RowProcessingState; -import org.hibernate.type.descriptor.java.JavaType; - -/** - * Specialized DomainResultAssembler for {@link org.hibernate.annotations.NotFound} associations - * - * @author Steve Ebersole - */ -public class NotFoundSnapshotAssembler implements DomainResultAssembler { - private final NavigablePath navigablePath; - private final ToOneAttributeMapping toOneMapping; - private final DomainResultAssembler keyValueAssembler; - private final DomainResultAssembler targetValueAssembler; - - public NotFoundSnapshotAssembler( - NavigablePath navigablePath, - ToOneAttributeMapping toOneMapping, - DomainResultAssembler keyValueAssembler, - DomainResultAssembler targetValueAssembler) { - assert toOneMapping.hasNotFoundAction(); - - this.navigablePath = navigablePath; - this.toOneMapping = toOneMapping; - this.keyValueAssembler = keyValueAssembler; - this.targetValueAssembler = targetValueAssembler; - } - - @Override - public Object assemble(RowProcessingState rowProcessingState, JdbcValuesSourceProcessingOptions options) { - final Object keyValue = keyValueAssembler.assemble( rowProcessingState ); - final Object targetValue = targetValueAssembler.assemble( rowProcessingState ); - - // because of `@NotFound` these could be mismatched - if ( keyValue != null ) { - if ( targetValue != null ) { - if ( toOneMapping.getNotFoundAction() == NotFoundAction.IGNORE ) { - return null; - } - else { - throw new FetchNotFoundException( - toOneMapping.getAssociatedEntityMappingType().getEntityName(), - keyValue - ); - } - } - } - - return targetValue; - } - - @Override - public JavaType getAssembledJavaType() { - return toOneMapping.getJavaType(); - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/NotFoundSnapshotResult.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/NotFoundSnapshotResult.java deleted file mode 100644 index 8491cf0ef8..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/NotFoundSnapshotResult.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later - * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html - */ -package org.hibernate.sql.results.graph.entity.internal; - -import org.hibernate.metamodel.mapping.ForeignKeyDescriptor; -import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping; -import org.hibernate.spi.NavigablePath; -import org.hibernate.sql.ast.tree.from.TableGroup; -import org.hibernate.sql.results.graph.AssemblerCreationState; -import org.hibernate.sql.results.graph.DomainResult; -import org.hibernate.sql.results.graph.DomainResultAssembler; -import org.hibernate.sql.results.graph.DomainResultCreationState; -import org.hibernate.sql.results.graph.FetchParentAccess; -import org.hibernate.type.descriptor.java.JavaType; - -/** - * @author Steve Ebersole - */ -public class NotFoundSnapshotResult implements DomainResult { - private final NavigablePath navigablePath; - private final ToOneAttributeMapping toOneMapping; - - private final DomainResult keyResult; - private final DomainResult targetResult; - - public NotFoundSnapshotResult( - NavigablePath navigablePath, - ToOneAttributeMapping toOneMapping, - TableGroup keyTableGroup, - TableGroup targetTableGroup, - DomainResultCreationState creationState) { - this.navigablePath = navigablePath; - this.toOneMapping = toOneMapping; - - // NOTE: this currently assumes that only the key side can be - // defined with `@NotFound`. That feels like a reasonable - // assumption, though there is sme question whether to support - // this for the inverse side also when a join table is used. - // - // however, that would mean a 1-1 with a join-table which - // is pretty odd mapping - final ForeignKeyDescriptor fkDescriptor = toOneMapping.getForeignKeyDescriptor(); - this.keyResult = fkDescriptor.createKeyDomainResult( - navigablePath, - targetTableGroup, - null, - creationState - ); - this.targetResult = fkDescriptor.createTargetDomainResult( - navigablePath, - targetTableGroup, - null, - creationState - ); - } - - @Override - public NavigablePath getNavigablePath() { - return navigablePath; - } - - @Override - public JavaType getResultJavaType() { - return toOneMapping.getJavaType(); - } - - @Override - public String getResultVariable() { - return null; - } - - @Override - public DomainResultAssembler createResultAssembler( - FetchParentAccess parentAccess, - AssemblerCreationState creationState) { - return new NotFoundSnapshotAssembler( - navigablePath, - toOneMapping, - keyResult.createResultAssembler( parentAccess, creationState ), - targetResult.createResultAssembler( parentAccess, creationState ) - ); - } - -} diff --git a/hibernate-core/src/main/java/org/hibernate/type/ManyToOneType.java b/hibernate-core/src/main/java/org/hibernate/type/ManyToOneType.java index 664a2044a9..dfd595e955 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/ManyToOneType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/ManyToOneType.java @@ -149,11 +149,10 @@ public boolean isModified( return true; } - assert current.getClass().isAssignableFrom( old.getClass() ); // the ids are fully resolved, so compare them with isDirty(), not isModified() return getIdentifierOrUniqueKeyType( session.getFactory() ) - .isDirty( getIdentifier( old, session ), getIdentifier( current, session ), session ); + .isDirty( old, getIdentifier( current, session ), session ); } @Override diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/version/VersionedBidirectionalOneToOneMergeTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/version/VersionedBidirectionalOneToOneMergeTest.java index fd3b9fe6ee..a142d1f870 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/version/VersionedBidirectionalOneToOneMergeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/version/VersionedBidirectionalOneToOneMergeTest.java @@ -29,7 +29,7 @@ public void testMerge(SessionFactoryScope scope) { AnotherTestEntity anotherTestEntity = new AnotherTestEntity(); scope.inTransaction( session -> { - session.persist( anotherTestEntity ); + session.merge( anotherTestEntity ); } ); @@ -66,6 +66,8 @@ public static class AnotherTestEntity { @Id UUID uuid = UUID.randomUUID(); + String name; + @OneToOne(mappedBy = "anotherTestEntity") TestEntity testEntity;