diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/TwoPhaseLoad.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/TwoPhaseLoad.java index 3a6316cdf7..6406dde383 100755 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/TwoPhaseLoad.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/TwoPhaseLoad.java @@ -34,6 +34,7 @@ import org.hibernate.persister.entity.EntityPersister; import org.hibernate.pretty.MessageHelper; import org.hibernate.property.access.internal.PropertyAccessStrategyBackRefImpl; import org.hibernate.proxy.HibernateProxy; +import org.hibernate.type.CollectionType; import org.hibernate.type.Type; import org.hibernate.type.TypeHelper; @@ -150,6 +151,11 @@ public final class TwoPhaseLoad { if ( value!=LazyPropertyInitializer.UNFETCHED_PROPERTY && value!= PropertyAccessStrategyBackRefImpl.UNKNOWN ) { hydratedState[i] = types[i].resolve( value, session, entity ); } + else if ( types[i].isCollectionType() ) { + // HHH-10989 Even if not fetched, resolve a collection so that a CollectionReference is added to StatefulPersistentContext + // No assignment to the hydratedState, that would trigger the load of the collection (below, on setPropertyValues) + types[i].resolve( value, session, entity ); + } } //Must occur afterQuery resolving identifiers! diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/EnhancerTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/EnhancerTest.java index 42b2a110de..174aa1c6cc 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/EnhancerTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/EnhancerTest.java @@ -9,6 +9,7 @@ package org.hibernate.test.bytecode.enhancement; import org.hibernate.bytecode.enhance.spi.UnloadedClass; import org.hibernate.test.bytecode.enhancement.detached.DetachedGetIdentifierTestTask; +import org.hibernate.test.bytecode.enhancement.cascade.CascadeWithFkConstraintTestTask; import org.hibernate.testing.FailureExpected; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.EnhancerTestContext; @@ -140,6 +141,12 @@ public class EnhancerTest extends BaseUnitTestCase { EnhancerTestUtils.runEnhancerTestTask( CascadeDeleteTestTask.class ); } + @Test + @TestForIssue( jiraKey = "HHH-10252" ) + public void testCascadeFkDelete() { + EnhancerTestUtils.runEnhancerTestTask( CascadeWithFkConstraintTestTask.class ); + } + @Test @TestForIssue( jiraKey = "HHH-10055" ) public void testLazyCollectionHandling() { diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/cascade/CascadeWithFkConstraintTestTask.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/cascade/CascadeWithFkConstraintTestTask.java new file mode 100644 index 0000000000..8cb6467f44 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/cascade/CascadeWithFkConstraintTestTask.java @@ -0,0 +1,135 @@ +/* + * 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.test.bytecode.enhancement.cascade; + +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.test.bytecode.enhancement.AbstractEnhancerTestTask; +import org.junit.Assert; + +import javax.persistence.Entity; +import javax.persistence.EntityManager; +import javax.persistence.EntityTransaction; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.OneToMany; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +/** + * @author Luis Barreiro + */ +public class CascadeWithFkConstraintTestTask extends AbstractEnhancerTestTask { + + private String garageId, car1Id, car2Id; + + public Class[] getAnnotatedClasses() { + return new Class[]{Garage.class, Car.class}; + } + + public void prepare() { + Configuration cfg = new Configuration(); + cfg.setProperty( Environment.ENABLE_LAZY_LOAD_NO_TRANS, "true" ); + cfg.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "false" ); + super.prepare( cfg ); + + // Create garage, add 2 cars to garage + EntityManager em = getFactory().createEntityManager(); + EntityTransaction tx = em.getTransaction(); + tx.begin(); + + Garage garage = new Garage(); + Car car1 = new Car(); + Car car2 = new Car(); + garage.insert( car1 ); + garage.insert( car2 ); + + em.persist( garage ); + em.persist( car1 ); + em.persist( car2 ); + + tx.commit(); + em.close(); + + garageId = garage.id; + car1Id = car1.id; + car2Id = car2.id; + } + + public void execute() { + + // Remove garage + + EntityManager em = getFactory().createEntityManager(); + EntityTransaction tx = em.getTransaction(); + tx.begin(); + + Garage toRemoveGarage = em.find( Garage.class, garageId ); + em.remove( toRemoveGarage ); + + tx.commit(); + em.close(); + + // Check if there is no garage but cars are still present + + EntityManager testEm = getFactory().createEntityManager(); + tx = testEm.getTransaction(); + tx.begin(); + + Garage foundGarage = testEm.find( Garage.class, garageId ); + Assert.assertNull( foundGarage ); + + Car foundCar1 = testEm.find( Car.class, car1Id ); + Assert.assertEquals( car1Id, foundCar1.id ); + + Car foundCar2 = testEm.find( Car.class, car2Id ); + Assert.assertEquals( car2Id, foundCar2.id ); + + tx.commit(); + testEm.close(); + + } + + protected void cleanup() { + } + + // --- // + + @Entity + public static class Garage { + + @Id + String id; + + @OneToMany + @JoinColumn( name = "GARAGE_ID" ) + Set cars = new HashSet<>(); + + public Garage() { + this.id = UUID.randomUUID().toString(); + } + + public boolean insert(Car aCar) { + return cars.add( aCar ); + } + + } + + @Entity + public static class Car { + + @Id + String id; + + public Car() { + id = UUID.randomUUID().toString(); + } + + } + +}