diff --git a/documentation/src/test/java/org/hibernate/userguide/envers/QueryAuditAdressCountryTest.java b/documentation/src/test/java/org/hibernate/userguide/envers/QueryAuditAdressCountryTest.java
index ed76e1dffa..a5fe91b869 100644
--- a/documentation/src/test/java/org/hibernate/userguide/envers/QueryAuditAdressCountryTest.java
+++ b/documentation/src/test/java/org/hibernate/userguide/envers/QueryAuditAdressCountryTest.java
@@ -26,7 +26,6 @@ import org.hibernate.envers.query.AuditEntity;
import org.hibernate.envers.strategy.ValidityAuditStrategy;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
-import org.hibernate.orm.test.legacy.Custom;
import org.junit.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
diff --git a/hibernate-core/src/test/java/org/hibernate/event/service/internal/EventListenerDuplicationStrategyTest.java b/hibernate-core/src/test/java/org/hibernate/event/service/internal/EventListenerDuplicationStrategyTest.java
index b423363dc7..aa687df31f 100644
--- a/hibernate-core/src/test/java/org/hibernate/event/service/internal/EventListenerDuplicationStrategyTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/event/service/internal/EventListenerDuplicationStrategyTest.java
@@ -11,24 +11,20 @@ import org.hibernate.event.spi.ClearEventListener;
import org.hibernate.event.spi.EventType;
import org.hibernate.testing.TestForIssue;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
+import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
/**
* Test that a listener replacing the original one is actually called when the event is fired for each listener.
*
- * Note: I'm using ClearEvent for the tests because it's the simpler one I've found.
+ * Note: I'm using ClearEvent for the tests because it's the simpler one I've found.
*
*/
@TestForIssue(jiraKey = "HHH-13831")
public class EventListenerDuplicationStrategyTest {
- @Rule
- public ExpectedException thrown = ExpectedException.none();
-
Tracker tracker = new Tracker();
ClearEvent event = new ClearEvent( null );
EventListenerGroup listenerGroup = new EventListenerGroupImpl( EventType.CLEAR, null, false );
@@ -85,7 +81,11 @@ public class EventListenerDuplicationStrategyTest {
listenerGroup.appendListener( new ExtraListener( tracker ) );
listenerGroup.listeners().forEach( listener -> listener.onClear( event ) );
- assertThat( tracker.callers ).containsExactly( OriginalListener.class, ExpectedListener.class, ExtraListener.class );
+ assertThat( tracker.callers ).containsExactly(
+ OriginalListener.class,
+ ExpectedListener.class,
+ ExtraListener.class
+ );
}
@Test
@@ -95,7 +95,11 @@ public class EventListenerDuplicationStrategyTest {
listenerGroup.appendListener( new ExtraListener( tracker ) );
listenerGroup.fireLazyEventOnEachListener( () -> event, ClearEventListener::onClear );
- assertThat( tracker.callers ).containsExactly( OriginalListener.class, ExpectedListener.class, ExtraListener.class );
+ assertThat( tracker.callers ).containsExactly(
+ OriginalListener.class,
+ ExpectedListener.class,
+ ExtraListener.class
+ );
}
@Test
@@ -105,7 +109,11 @@ public class EventListenerDuplicationStrategyTest {
listenerGroup.appendListener( new ExtraListener( tracker ) );
listenerGroup.fireEventOnEachListener( event, ClearEventListener::onClear );
- assertThat( tracker.callers ).containsExactly( OriginalListener.class, ExpectedListener.class, ExtraListener.class );
+ assertThat( tracker.callers ).containsExactly(
+ OriginalListener.class,
+ ExpectedListener.class,
+ ExtraListener.class
+ );
}
@Test
@@ -176,12 +184,15 @@ public class EventListenerDuplicationStrategyTest {
@Test
public void testErrorStrategyOnAppend() {
- thrown.expect( EventListenerRegistrationException.class );
- thrown.expectMessage( "Duplicate event listener found" );
-
- listenerGroup.addDuplicationStrategy( ErrorStrategy.INSTANCE );
- listenerGroup.appendListener( new OriginalListener( tracker ) );
- listenerGroup.appendListener( new ExpectedListener( tracker ) );
+ final EventListenerRegistrationException expectedException = assertThrows(
+ EventListenerRegistrationException.class,
+ () -> {
+ listenerGroup.addDuplicationStrategy( ErrorStrategy.INSTANCE );
+ listenerGroup.appendListener( new OriginalListener( tracker ) );
+ listenerGroup.appendListener( new ExpectedListener( tracker ) );
+ }
+ );
+ assertThat( expectedException.getMessage() ).isEqualTo( "Duplicate event listener found" );
}
@Test
@@ -194,10 +205,13 @@ public class EventListenerDuplicationStrategyTest {
@Test
public void testDefaultDuplicationStrategy() {
- thrown.expect( EventListenerRegistrationException.class );
- //By default, it's not allowed to register the same type of listener twice:
- listenerGroup.appendListener( new OriginalListener( tracker ) );
- listenerGroup.appendListener( new OriginalListener( tracker ) );
+ assertThrows(
+ EventListenerRegistrationException.class, () -> {
+ //By default, it's not allowed to register the same type of listener twice:
+ listenerGroup.appendListener( new OriginalListener( tracker ) );
+ listenerGroup.appendListener( new OriginalListener( tracker ) );
+ }
+ );
}
/**
diff --git a/hibernate-core/src/test/java/org/hibernate/event/service/internal/EventListenerGroupAppendListenerTest.java b/hibernate-core/src/test/java/org/hibernate/event/service/internal/EventListenerGroupAppendListenerTest.java
index f6d1d21a38..aee79fae0b 100644
--- a/hibernate-core/src/test/java/org/hibernate/event/service/internal/EventListenerGroupAppendListenerTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/event/service/internal/EventListenerGroupAppendListenerTest.java
@@ -6,11 +6,6 @@
*/
package org.hibernate.event.service.internal;
-import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
import java.lang.reflect.Field;
import org.hibernate.event.internal.DefaultMergeEventListener;
@@ -21,15 +16,20 @@ import org.hibernate.event.spi.EventType;
import org.hibernate.event.spi.MergeEventListener;
import org.hibernate.jpa.event.spi.CallbackRegistry;
import org.hibernate.service.spi.ServiceRegistryImplementor;
+
import org.hibernate.testing.TestForIssue;
-import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
-import org.junit.Test;
+import org.hibernate.testing.orm.junit.BaseSessionFactoryFunctionalTest;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
/**
* @author Frank Doherty
*/
@TestForIssue(jiraKey = "HHH-13070")
-public class EventListenerGroupAppendListenerTest extends BaseCoreFunctionalTestCase {
+public class EventListenerGroupAppendListenerTest extends BaseSessionFactoryFunctionalTest {
private static final DuplicationStrategy DUPLICATION_STRATEGY_REPLACE_ORIGINAL = new DuplicationStrategy() {
@@ -40,7 +40,7 @@ public class EventListenerGroupAppendListenerTest extends BaseCoreFunctionalTest
}
@Override
- public DuplicationStrategy.Action getAction() {
+ public Action getAction() {
return Action.REPLACE_ORIGINAL;
}
};
@@ -60,8 +60,9 @@ public class EventListenerGroupAppendListenerTest extends BaseCoreFunctionalTest
}
private void runAppendListenerTest(
- DuplicationStrategy duplicationStrategy, DefaultMergeEventListener mergeEventListener) {
- doInHibernate( this::sessionFactory, session -> {
+ DuplicationStrategy duplicationStrategy,
+ DefaultMergeEventListener mergeEventListener) {
+ inTransaction( session -> {
ServiceRegistryImplementor serviceRegistry = sessionFactory().getServiceRegistry();
EventListenerRegistry listenerRegistry = serviceRegistry.getService( EventListenerRegistry.class );
@@ -72,7 +73,7 @@ public class EventListenerGroupAppendListenerTest extends BaseCoreFunctionalTest
group.appendListener( mergeEventListener );
Iterable listeners = group.listeners();
- assertTrue( "Should have at least one listener", listeners.iterator().hasNext() );
+ assertTrue( listeners.iterator().hasNext(), "Should have at least one listener" );
listeners.forEach( this::assertCallbackRegistry );
} );
}
@@ -80,7 +81,7 @@ public class EventListenerGroupAppendListenerTest extends BaseCoreFunctionalTest
private void assertCallbackRegistry(
MergeEventListener listener) {
try {
- assertNotNull( "callbackRegistry should not be null", getCallbackRegistry( listener ) );
+ assertNotNull( getCallbackRegistry( listener ), "callbackRegistry should not be null" );
}
catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {
fail( "Unable to get callbackRegistry field on listener" );
diff --git a/hibernate-core/src/test/java/org/hibernate/event/service/internal/NewlyInstantiatdCollectionSkipDeleteOrphanTest.java b/hibernate-core/src/test/java/org/hibernate/event/service/internal/NewlyInstantiatdCollectionSkipDeleteOrphanTest.java
index c27d7fe3f3..547c5a55c2 100644
--- a/hibernate-core/src/test/java/org/hibernate/event/service/internal/NewlyInstantiatdCollectionSkipDeleteOrphanTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/event/service/internal/NewlyInstantiatdCollectionSkipDeleteOrphanTest.java
@@ -27,22 +27,36 @@ import org.hibernate.Transaction;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.DynamicUpdate;
-import org.hibernate.testing.DialectChecks;
-import org.hibernate.testing.RequiresDialectFeature;
import org.hibernate.testing.TestForIssue;
-import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
+import org.hibernate.testing.orm.junit.DialectFeatureChecks;
+import org.hibernate.testing.orm.junit.DomainModel;
+import org.hibernate.testing.orm.junit.RequiresDialectFeature;
+import org.hibernate.testing.orm.junit.SessionFactory;
+import org.hibernate.testing.orm.junit.SessionFactoryScope;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
/**
* @author Artem K.
* @author Nathan Xu
*/
-@TestForIssue( jiraKey = "HHH-14178" )
-@RequiresDialectFeature(DialectChecks.SupportsIdentityColumns.class)
-public class NewlyInstantiatdCollectionSkipDeleteOrphanTest extends BaseCoreFunctionalTestCase {
+@TestForIssue(jiraKey = "HHH-14178")
+@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsIdentityColumns.class)
+@DomainModel(
+ annotatedClasses = {
+ NewlyInstantiatdCollectionSkipDeleteOrphanTest.VersionedParent.class,
+ NewlyInstantiatdCollectionSkipDeleteOrphanTest.UnversionedParent.class,
+ NewlyInstantiatdCollectionSkipDeleteOrphanTest.Child.class,
+ NewlyInstantiatdCollectionSkipDeleteOrphanTest.VersionedMappingUnversionedParent.class,
+ NewlyInstantiatdCollectionSkipDeleteOrphanTest.VersionedMappingVersionedParent.class
+ }
+)
+@SessionFactory
+public class NewlyInstantiatdCollectionSkipDeleteOrphanTest {
private UnversionedParent up;
private VersionedParent vp;
@@ -50,18 +64,7 @@ public class NewlyInstantiatdCollectionSkipDeleteOrphanTest extends BaseCoreFunc
private VersionedMappingUnversionedParent vmup;
private VersionedMappingVersionedParent vmvp;
- @Override
- protected Class>[] getAnnotatedClasses() {
- return new Class>[] {
- VersionedParent.class,
- UnversionedParent.class,
- Child.class,
- VersionedMappingUnversionedParent.class,
- VersionedMappingVersionedParent.class
- };
- }
-
- @Before
+ @BeforeEach
public void setup() {
up = new UnversionedParent();
@@ -78,24 +81,24 @@ public class NewlyInstantiatdCollectionSkipDeleteOrphanTest extends BaseCoreFunc
}
- @After
- public void cleanup() {
- inTransaction( s -> {
- if (up.getId() != null) {
+ @AfterEach
+ public void cleanup(SessionFactoryScope scope) {
+ scope.inTransaction( s -> {
+ if ( up.getId() != null ) {
s.delete( up );
}
- if (vp.getId() != null) {
+ if ( vp.getId() != null ) {
s.delete( vp );
}
- if (c.getId() != null) {
+ if ( c.getId() != null ) {
s.delete( c );
}
} );
}
@Test
- public void VersionedMappingVersionedParentSaveUpdate() {
- inSession( s -> {
+ public void VersionedMappingVersionedParentSaveUpdate(SessionFactoryScope scope) {
+ scope.inSession( s -> {
s.setHibernateFlushMode( FlushMode.MANUAL );
Transaction trx = s.beginTransaction();
@@ -105,27 +108,28 @@ public class NewlyInstantiatdCollectionSkipDeleteOrphanTest extends BaseCoreFunc
// Persist Child associated with versioned parent
s.saveOrUpdate( c );
- Assert.assertNotEquals( Integer.valueOf(0), c.getId() );
+ assertNotEquals( Integer.valueOf( 0 ), c.getId() );
// Persist VersionParent
s.saveOrUpdate( vp );
- Assert.assertNotEquals( Integer.valueOf(0), vp.getId() );
+ assertNotEquals( Integer.valueOf( 0 ), vp.getId() );
// Persist versioned mapping now that parent id is generated
s.saveOrUpdate( vmvp );
- Assert.assertNotNull( vmvp.getId() );
- Assert.assertNotEquals( Integer.valueOf(0), vmvp.getId().getParentId() );
- Assert.assertNotEquals( Integer.valueOf(0), vmvp.getId().getChildId() );
+ assertNotNull( vmvp.getId() );
+ assertNotEquals( Integer.valueOf( 0 ), vmvp.getId().getParentId() );
+ assertNotEquals( Integer.valueOf( 0 ), vmvp.getId().getChildId() );
s.flush();
trx.commit();
- } catch (RuntimeException e) {
+ }
+ catch (RuntimeException e) {
// Transaction is rolled back so we do not want delete code in cleanup to execute.
// Reset any possible ID assignments
vp.setId( null );
c.setId( null );
- if (trx.isActive()) {
+ if ( trx.isActive() ) {
trx.rollback();
}
throw e;
@@ -134,8 +138,8 @@ public class NewlyInstantiatdCollectionSkipDeleteOrphanTest extends BaseCoreFunc
}
@Test
- public void VersionedMappingUnversionedParentSaveUpdate() {
- inSession( s -> {
+ public void VersionedMappingUnversionedParentSaveUpdate(SessionFactoryScope scope) {
+ scope.inSession( s -> {
s.setHibernateFlushMode( FlushMode.MANUAL );
Transaction trx = s.beginTransaction();
@@ -145,27 +149,28 @@ public class NewlyInstantiatdCollectionSkipDeleteOrphanTest extends BaseCoreFunc
// Persist child associated with versioned mapping of unversioned parent
s.saveOrUpdate( c );
- Assert.assertNotEquals( Integer.valueOf(0), c.getId() );
+ assertNotEquals( Integer.valueOf( 0 ), c.getId() );
// Persist unversioned parent
s.saveOrUpdate( up );
- Assert.assertNotEquals( Integer.valueOf(0), up.getId() );
+ assertNotEquals( Integer.valueOf( 0 ), up.getId() );
// Persist versioned mapping
s.saveOrUpdate( vmup );
- Assert.assertNotNull( vmup.getId() );
- Assert.assertNotEquals( Integer.valueOf(0), vmup.getId().getParentId() );
- Assert.assertNotEquals( Integer.valueOf(0), vmup.getId().getChildId() );
+ assertNotNull( vmup.getId() );
+ assertNotEquals( Integer.valueOf( 0 ), vmup.getId().getParentId() );
+ assertNotEquals( Integer.valueOf( 0 ), vmup.getId().getChildId() );
s.flush();
trx.commit();
- } catch (RuntimeException e) {
+ }
+ catch (RuntimeException e) {
// Transaction is rolled back so we do not want delete code in cleanup to execute.
// Reset any possible ID assignments
up.setId( null );
c.setId( null );
- if (trx.isActive()) {
+ if ( trx.isActive() ) {
trx.rollback();
}
throw e;
@@ -236,7 +241,7 @@ public class NewlyInstantiatdCollectionSkipDeleteOrphanTest extends BaseCoreFunc
private Integer parentId;
private Integer childId;
- @Column(name="ParentId", nullable=false)
+ @Column(name = "ParentId", nullable = false)
public Integer getParentId() {
return parentId;
}
@@ -245,7 +250,7 @@ public class NewlyInstantiatdCollectionSkipDeleteOrphanTest extends BaseCoreFunc
this.parentId = parentId;
}
- @Column(name="ChildId", nullable=false)
+ @Column(name = "ChildId", nullable = false)
public Integer getChildId() {
return childId;
}
@@ -256,19 +261,22 @@ public class NewlyInstantiatdCollectionSkipDeleteOrphanTest extends BaseCoreFunc
@Override
public int hashCode() {
- return Objects.hash(getParentId(), getChildId());
+ return Objects.hash( getParentId(), getChildId() );
}
@Override
public boolean equals(Object obj) {
- if (this == obj) {
+ if ( this == obj ) {
return true;
}
- if (!(obj instanceof MappingId)) {
+ if ( !( obj instanceof MappingId ) ) {
return false;
}
MappingId other = (MappingId) obj;
- return Objects.equals(getParentId(), other.getParentId()) && Objects.equals(getChildId(), other.getChildId());
+ return Objects.equals( getParentId(), other.getParentId() ) && Objects.equals(
+ getChildId(),
+ other.getChildId()
+ );
}
@Override
@@ -288,21 +296,21 @@ public class NewlyInstantiatdCollectionSkipDeleteOrphanTest extends BaseCoreFunc
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
- @Column(name="Id", nullable=false)
+ @Column(name = "Id", nullable = false)
public Integer getId() {
return id;
}
public void setId(Integer id) {
- if (!Objects.equals(id, getId())) {
+ if ( !Objects.equals( id, getId() ) ) {
this.id = id;
- getVersionedMappings().forEach(c -> {
- if (c.getId() == null) {
- c.setId(new MappingId());
+ getVersionedMappings().forEach( c -> {
+ if ( c.getId() == null ) {
+ c.setId( new MappingId() );
}
- c.getId().setParentId(id);
- });
+ c.getId().setParentId( id );
+ } );
}
}
@@ -314,38 +322,48 @@ public class NewlyInstantiatdCollectionSkipDeleteOrphanTest extends BaseCoreFunc
this.name = name;
}
- @OneToMany(mappedBy="parent", cascade={ javax.persistence.CascadeType.DETACH, javax.persistence.CascadeType.MERGE, javax.persistence.CascadeType.REFRESH, javax.persistence.CascadeType.REMOVE }, orphanRemoval=true)
- @Cascade({ org.hibernate.annotations.CascadeType.DELETE, org.hibernate.annotations.CascadeType.LOCK, org.hibernate.annotations.CascadeType.REPLICATE })
+ @OneToMany(mappedBy = "parent", cascade = {
+ javax.persistence.CascadeType.DETACH,
+ javax.persistence.CascadeType.MERGE,
+ javax.persistence.CascadeType.REFRESH,
+ javax.persistence.CascadeType.REMOVE
+ }, orphanRemoval = true)
+ @Cascade({
+ org.hibernate.annotations.CascadeType.DELETE,
+ org.hibernate.annotations.CascadeType.LOCK,
+ org.hibernate.annotations.CascadeType.REPLICATE
+ })
protected Set getVersionedMappings() {
- if (versionedMappings == null) {
+ if ( versionedMappings == null ) {
versionedMappings = new HashSet<>();
}
return this.versionedMappings;
}
protected void setVersionedMappings(Set value) {
- if (value == null && this.versionedMappings != null) {
+ if ( value == null && this.versionedMappings != null ) {
this.versionedMappings.clear();
- } else {
+ }
+ else {
this.versionedMappings = value;
}
}
@Transient
public Collection getVersionedMappingsCollection() {
- return new ArrayList<>(getVersionedMappings());
+ return new ArrayList<>( getVersionedMappings() );
}
public void addVersionedMappings(VersionedMappingUnversionedParent addValue) {
- if (addValue != null && !this.getVersionedMappings().contains(addValue)) {
- this.versionedMappings.add(addValue);
- addValue.addParent(this);
+ if ( addValue != null && !this.getVersionedMappings().contains( addValue ) ) {
+ this.versionedMappings.add( addValue );
+ addValue.addParent( this );
}
}
public void removeVersionedMappings(VersionedMappingUnversionedParent removeValue) {
- if (this.versionedMappings != null && this.versionedMappings.contains(removeValue)) {
- this.versionedMappings.remove(removeValue);
+ if ( this.versionedMappings != null && this.versionedMappings.contains( removeValue ) ) {
+ this.versionedMappings.remove( removeValue );
removeValue.removeParent();
}
}
@@ -357,14 +375,14 @@ public class NewlyInstantiatdCollectionSkipDeleteOrphanTest extends BaseCoreFunc
@Override
public boolean equals(Object obj) {
- if (this == obj) {
+ if ( this == obj ) {
return true;
}
- if (!(obj instanceof UnversionedParent)) {
+ if ( !( obj instanceof UnversionedParent ) ) {
return false;
}
UnversionedParent other = (UnversionedParent) obj;
- return Objects.equals(getId(), other.getId());
+ return Objects.equals( getId(), other.getId() );
}
}
@@ -379,21 +397,21 @@ public class NewlyInstantiatdCollectionSkipDeleteOrphanTest extends BaseCoreFunc
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
- @Column(name="Id", nullable=false)
+ @Column(name = "Id", nullable = false)
public Integer getId() {
return id;
}
public void setId(Integer id) {
- if (!Objects.equals(id, getId())) {
+ if ( !Objects.equals( id, getId() ) ) {
this.id = id;
- getChildren().forEach(c -> {
- if (c.getId() == null) {
- c.setId(new MappingId());
+ getChildren().forEach( c -> {
+ if ( c.getId() == null ) {
+ c.setId( new MappingId() );
}
- c.getId().setParentId(id);
- });
+ c.getId().setParentId( id );
+ } );
}
}
@@ -406,7 +424,7 @@ public class NewlyInstantiatdCollectionSkipDeleteOrphanTest extends BaseCoreFunc
}
@Version
- @Column(name="Version", nullable=false)
+ @Column(name = "Version", nullable = false)
public Long getVersion() {
return version;
}
@@ -415,38 +433,48 @@ public class NewlyInstantiatdCollectionSkipDeleteOrphanTest extends BaseCoreFunc
this.version = version;
}
- @OneToMany(mappedBy="parent", cascade={ javax.persistence.CascadeType.DETACH, javax.persistence.CascadeType.MERGE, javax.persistence.CascadeType.REFRESH, javax.persistence.CascadeType.REMOVE }, orphanRemoval=true)
- @Cascade({ org.hibernate.annotations.CascadeType.DELETE, org.hibernate.annotations.CascadeType.LOCK, org.hibernate.annotations.CascadeType.REPLICATE })
+ @OneToMany(mappedBy = "parent", cascade = {
+ javax.persistence.CascadeType.DETACH,
+ javax.persistence.CascadeType.MERGE,
+ javax.persistence.CascadeType.REFRESH,
+ javax.persistence.CascadeType.REMOVE
+ }, orphanRemoval = true)
+ @Cascade({
+ org.hibernate.annotations.CascadeType.DELETE,
+ org.hibernate.annotations.CascadeType.LOCK,
+ org.hibernate.annotations.CascadeType.REPLICATE
+ })
protected Set getChildren() {
- if (children == null) {
+ if ( children == null ) {
children = new HashSet<>();
}
return this.children;
}
protected void setChildren(Set value) {
- if (value == null && this.children != null) {
+ if ( value == null && this.children != null ) {
this.children.clear();
- } else {
+ }
+ else {
this.children = value;
}
}
@Transient
public Collection getChildrenCollection() {
- return new ArrayList<>(getChildren());
+ return new ArrayList<>( getChildren() );
}
public void addChild(VersionedMappingVersionedParent addValue) {
- if (addValue != null && !this.getChildren().contains(addValue)) {
- this.children.add(addValue);
- addValue.addParent(this);
+ if ( addValue != null && !this.getChildren().contains( addValue ) ) {
+ this.children.add( addValue );
+ addValue.addParent( this );
}
}
public void removeChild(VersionedMappingVersionedParent removeValue) {
- if (this.children != null && this.children.contains(removeValue)) {
- this.children.remove(removeValue);
+ if ( this.children != null && this.children.contains( removeValue ) ) {
+ this.children.remove( removeValue );
removeValue.removeParent();
}
}
@@ -458,14 +486,14 @@ public class NewlyInstantiatdCollectionSkipDeleteOrphanTest extends BaseCoreFunc
@Override
public boolean equals(Object obj) {
- if (this == obj) {
+ if ( this == obj ) {
return true;
}
- if (!(obj instanceof VersionedParent)) {
+ if ( !( obj instanceof VersionedParent ) ) {
return false;
}
VersionedParent other = (VersionedParent) obj;
- return Objects.equals(getId(), other.getId());
+ return Objects.equals( getId(), other.getId() );
}
}
@@ -488,7 +516,7 @@ public class NewlyInstantiatdCollectionSkipDeleteOrphanTest extends BaseCoreFunc
}
@Version
- @Column(name="Version", nullable=false)
+ @Column(name = "Version", nullable = false)
public Long getVersion() {
return version;
}
@@ -507,9 +535,9 @@ public class NewlyInstantiatdCollectionSkipDeleteOrphanTest extends BaseCoreFunc
protected UnversionedParent parent;
- @ManyToOne(optional=false, fetch=FetchType.LAZY)
+ @ManyToOne(optional = false, fetch = FetchType.LAZY)
@MapsId("parentId")
- @JoinColumn(name="ParentId", nullable=false)
+ @JoinColumn(name = "ParentId", nullable = false)
public UnversionedParent getParent() {
return this.parent;
}
@@ -520,30 +548,30 @@ public class NewlyInstantiatdCollectionSkipDeleteOrphanTest extends BaseCoreFunc
public void addParent(UnversionedParent value) {
UnversionedParent oldParent = getParent();
- if (!Objects.equals(value, oldParent)) {
- if (oldParent != null) {
- setParent(null);
- oldParent.removeVersionedMappings(this);
+ if ( !Objects.equals( value, oldParent ) ) {
+ if ( oldParent != null ) {
+ setParent( null );
+ oldParent.removeVersionedMappings( this );
}
- if (value != null) {
- setParent(value);
- if (getId() == null) {
- setId(new MappingId());
+ if ( value != null ) {
+ setParent( value );
+ if ( getId() == null ) {
+ setId( new MappingId() );
}
- getId().setParentId(value.getId());
- value.addVersionedMappings(this);
+ getId().setParentId( value.getId() );
+ value.addVersionedMappings( this );
}
}
}
public void removeParent() {
- addParent(null);
+ addParent( null );
}
- @ManyToOne(optional=false, fetch=FetchType.LAZY)
+ @ManyToOne(optional = false, fetch = FetchType.LAZY)
@MapsId("childId")
- @JoinColumn(name="ChildId", nullable=false)
+ @JoinColumn(name = "ChildId", nullable = false)
public Child getChild() {
return child;
}
@@ -554,23 +582,23 @@ public class NewlyInstantiatdCollectionSkipDeleteOrphanTest extends BaseCoreFunc
public void addChild(Child value) {
Child oldChild = getChild();
- if (!Objects.equals(value, oldChild)) {
- if (oldChild != null) {
- setChild(null);
+ if ( !Objects.equals( value, oldChild ) ) {
+ if ( oldChild != null ) {
+ setChild( null );
}
- if (value != null) {
- setChild(value);
- if (getId() == null) {
- setId(new MappingId());
+ if ( value != null ) {
+ setChild( value );
+ if ( getId() == null ) {
+ setId( new MappingId() );
}
- getId().setChildId(value.getId());
+ getId().setChildId( value.getId() );
}
}
}
public void removeChild() {
- addChild(null);
+ addChild( null );
}
@Override
@@ -580,14 +608,14 @@ public class NewlyInstantiatdCollectionSkipDeleteOrphanTest extends BaseCoreFunc
@Override
public boolean equals(Object obj) {
- if (this == obj) {
+ if ( this == obj ) {
return true;
}
- if (!(obj instanceof VersionedMappingUnversionedParent)) {
+ if ( !( obj instanceof VersionedMappingUnversionedParent ) ) {
return false;
}
VersionedMappingUnversionedParent other = (VersionedMappingUnversionedParent) obj;
- return Objects.equals(getId(), other.getId());
+ return Objects.equals( getId(), other.getId() );
}
}
@@ -610,7 +638,7 @@ public class NewlyInstantiatdCollectionSkipDeleteOrphanTest extends BaseCoreFunc
}
@Version
- @Column(name="Version", nullable=false)
+ @Column(name = "Version", nullable = false)
public Long getVersion() {
return version;
}
@@ -629,9 +657,9 @@ public class NewlyInstantiatdCollectionSkipDeleteOrphanTest extends BaseCoreFunc
protected VersionedParent parent;
- @ManyToOne(optional=false, fetch=FetchType.LAZY)
+ @ManyToOne(optional = false, fetch = FetchType.LAZY)
@MapsId("parentId")
- @JoinColumn(name="ParentId", nullable=false)
+ @JoinColumn(name = "ParentId", nullable = false)
public VersionedParent getParent() {
return this.parent;
}
@@ -642,30 +670,30 @@ public class NewlyInstantiatdCollectionSkipDeleteOrphanTest extends BaseCoreFunc
public void addParent(VersionedParent value) {
VersionedParent oldParent = getParent();
- if (!Objects.equals(value, oldParent)) {
- if (oldParent != null) {
- setParent(null);
- oldParent.removeChild(this);
+ if ( !Objects.equals( value, oldParent ) ) {
+ if ( oldParent != null ) {
+ setParent( null );
+ oldParent.removeChild( this );
}
- if (value != null) {
- setParent(value);
- if (getId() == null) {
- setId(new MappingId());
+ if ( value != null ) {
+ setParent( value );
+ if ( getId() == null ) {
+ setId( new MappingId() );
}
- getId().setParentId(value.getId());
- value.addChild(this);
+ getId().setParentId( value.getId() );
+ value.addChild( this );
}
}
}
public void removeParent() {
- addParent(null);
+ addParent( null );
}
- @ManyToOne(optional=false, fetch=FetchType.LAZY)
+ @ManyToOne(optional = false, fetch = FetchType.LAZY)
@MapsId("childId")
- @JoinColumn(name="ChildId", nullable=false)
+ @JoinColumn(name = "ChildId", nullable = false)
public Child getChild() {
return child;
}
@@ -676,23 +704,23 @@ public class NewlyInstantiatdCollectionSkipDeleteOrphanTest extends BaseCoreFunc
public void addChild(Child value) {
Child oldChild = getChild();
- if (!Objects.equals(value, oldChild)) {
- if (oldChild != null) {
- setChild(null);
+ if ( !Objects.equals( value, oldChild ) ) {
+ if ( oldChild != null ) {
+ setChild( null );
}
- if (value != null) {
- setChild(value);
- if (getId() == null) {
- setId(new MappingId());
+ if ( value != null ) {
+ setChild( value );
+ if ( getId() == null ) {
+ setId( new MappingId() );
}
- getId().setChildId(value.getId());
+ getId().setChildId( value.getId() );
}
}
}
public void removeChild() {
- addChild(null);
+ addChild( null );
}
@Override
@@ -702,14 +730,14 @@ public class NewlyInstantiatdCollectionSkipDeleteOrphanTest extends BaseCoreFunc
@Override
public boolean equals(Object obj) {
- if (this == obj) {
+ if ( this == obj ) {
return true;
}
- if (!(obj instanceof VersionedMappingVersionedParent)) {
+ if ( !( obj instanceof VersionedMappingVersionedParent ) ) {
return false;
}
VersionedMappingVersionedParent other = (VersionedMappingVersionedParent) obj;
- return Objects.equals(getId(), other.getId());
+ return Objects.equals( getId(), other.getId() );
}
}
}
diff --git a/hibernate-core/src/test/java/org/hibernate/test/common/JournalingBatchObserver.java b/hibernate-core/src/test/java/org/hibernate/orm/test/common/JournalingBatchObserver.java
similarity index 95%
rename from hibernate-core/src/test/java/org/hibernate/test/common/JournalingBatchObserver.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/common/JournalingBatchObserver.java
index 92bbf3b0fd..5ee2d9ea05 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/common/JournalingBatchObserver.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/common/JournalingBatchObserver.java
@@ -4,7 +4,7 @@
* 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.common;
+package org.hibernate.orm.test.common;
import org.hibernate.engine.jdbc.batch.spi.BatchObserver;
diff --git a/hibernate-core/src/test/java/org/hibernate/test/common/JournalingConnectionObserver.java b/hibernate-core/src/test/java/org/hibernate/orm/test/common/JournalingConnectionObserver.java
similarity index 97%
rename from hibernate-core/src/test/java/org/hibernate/test/common/JournalingConnectionObserver.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/common/JournalingConnectionObserver.java
index 009c98b393..809c8f4c41 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/common/JournalingConnectionObserver.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/common/JournalingConnectionObserver.java
@@ -4,7 +4,7 @@
* 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.common;
+package org.hibernate.orm.test.common;
import java.sql.Connection;
diff --git a/hibernate-core/src/test/java/org/hibernate/test/common/JournalingTransactionObserver.java b/hibernate-core/src/test/java/org/hibernate/orm/test/common/JournalingTransactionObserver.java
similarity index 95%
rename from hibernate-core/src/test/java/org/hibernate/test/common/JournalingTransactionObserver.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/common/JournalingTransactionObserver.java
index 93f7cf4751..6b653dcbd0 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/common/JournalingTransactionObserver.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/common/JournalingTransactionObserver.java
@@ -4,7 +4,7 @@
* 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.common;
+package org.hibernate.orm.test.common;
import org.hibernate.engine.transaction.spi.TransactionObserver;
diff --git a/hibernate-core/src/test/java/org/hibernate/event/EmbeddableCallbackTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/event/EmbeddableCallbackTest.java
similarity index 54%
rename from hibernate-core/src/test/java/org/hibernate/event/EmbeddableCallbackTest.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/event/EmbeddableCallbackTest.java
index ad2be1ffac..b801a40ed3 100644
--- a/hibernate-core/src/test/java/org/hibernate/event/EmbeddableCallbackTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/event/EmbeddableCallbackTest.java
@@ -4,36 +4,43 @@
* 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.event;
+package org.hibernate.orm.test.event;
import javax.persistence.Embeddable;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.PrePersist;
-import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
-
import org.hibernate.testing.TestForIssue;
-import org.junit.Test;
+import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
+import org.hibernate.testing.orm.junit.Jpa;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
-import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertNull;
/**
* @author Vlad Mihalcea
*/
-public class EmbeddableCallbackTest extends BaseEntityManagerFunctionalTestCase {
+@Jpa(
+ annotatedClasses = EmbeddableCallbackTest.Employee.class
+)
+public class EmbeddableCallbackTest {
- @Override
- protected Class>[] getAnnotatedClasses() {
- return new Class>[] { Employee.class };
+ @AfterEach
+ public void tearDown(EntityManagerFactoryScope scope) {
+ scope.inTransaction(
+ entityManager ->
+ entityManager.createQuery( "delete from Employee" ).executeUpdate()
+ );
}
@Test
@TestForIssue(jiraKey = "HHH-12326")
- public void test() {
- doInJPA( this::entityManagerFactory, entityManager -> {
+ public void test(EntityManagerFactoryScope scope) {
+ scope.inTransaction( entityManager -> {
Employee employee = new Employee();
employee.details = new EmployeeDetails();
employee.id = 1;
@@ -41,28 +48,28 @@ public class EmbeddableCallbackTest extends BaseEntityManagerFunctionalTestCase
entityManager.persist( employee );
} );
- doInJPA( this::entityManagerFactory, entityManager -> {
+ scope.inTransaction( entityManager -> {
Employee employee = entityManager.find( Employee.class, 1 );
- assertEquals( "Vlad", employee.name );
- assertEquals( "Developer Advocate", employee.details.jobTitle );
+ assertThat( employee.name, is( "Vlad" ) );
+ assertThat( employee.details.jobTitle, is( "Developer Advocate" ) );
} );
}
@Test
@TestForIssue(jiraKey = "HHH-13110")
- public void testNullEmbeddable() {
- doInJPA( this::entityManagerFactory, entityManager -> {
+ public void testNullEmbeddable(EntityManagerFactoryScope scope) {
+ scope.inTransaction( entityManager -> {
Employee employee = new Employee();
employee.id = 1;
entityManager.persist( employee );
} );
- doInJPA( this::entityManagerFactory, entityManager -> {
+ scope.inTransaction( entityManager -> {
Employee employee = entityManager.find( Employee.class, 1 );
- assertEquals( "Vlad", employee.name );
+ assertThat( employee.name, is( "Vlad" ) );
assertNull( employee.details );
} );
}
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jdbc/internal/BatchingTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jdbc/internal/BatchingTest.java
index 46ea00a993..5ed52f044d 100644
--- a/hibernate-core/src/test/java/org/hibernate/orm/test/jdbc/internal/BatchingTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jdbc/internal/BatchingTest.java
@@ -25,7 +25,7 @@ import org.hibernate.jdbc.Expectations;
import org.hibernate.resource.jdbc.spi.LogicalConnectionImplementor;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
-import org.hibernate.test.common.JournalingBatchObserver;
+import org.hibernate.orm.test.common.JournalingBatchObserver;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
diff --git a/hibernate-core/src/test/java/org/hibernate/test/lazydetachedpersist/LazyPersistWithDetachedAssociationTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/lazydetachedpersist/LazyPersistWithDetachedAssociationTest.java
similarity index 57%
rename from hibernate-core/src/test/java/org/hibernate/test/lazydetachedpersist/LazyPersistWithDetachedAssociationTest.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/lazydetachedpersist/LazyPersistWithDetachedAssociationTest.java
index 23639cd9c6..f68bcd17af 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/lazydetachedpersist/LazyPersistWithDetachedAssociationTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/lazydetachedpersist/LazyPersistWithDetachedAssociationTest.java
@@ -4,7 +4,7 @@
* 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.lazydetachedpersist;
+package org.hibernate.orm.test.lazydetachedpersist;
import javax.persistence.Basic;
import javax.persistence.Entity;
@@ -13,39 +13,35 @@ import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
-import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.testing.TestForIssue;
-import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
-import org.junit.Before;
-import org.junit.Test;
+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.hibernate.testing.orm.junit.Setting;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
-import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
-import static org.junit.Assert.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
-public class LazyPersistWithDetachedAssociationTest
- extends BaseCoreFunctionalTestCase {
+@DomainModel(
+ annotatedClasses = {
+ LazyPersistWithDetachedAssociationTest.Address.class,
+ LazyPersistWithDetachedAssociationTest.Person.class,
+ }
+)
+@SessionFactory
+@ServiceRegistry(
+ settings = { @Setting(name = Environment.ENABLE_LAZY_LOAD_NO_TRANS, value = "false") }
+)
+public class LazyPersistWithDetachedAssociationTest {
-
- @Override
- protected void configure(Configuration cfg) {
- super.configure( cfg );
- cfg.setProperty( Environment.ENABLE_LAZY_LOAD_NO_TRANS, "false" );
- cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
- }
-
- @Override
- protected Class[] getAnnotatedClasses() {
- return new Class[] {
- Address.class,
- Person.class,
- };
- }
-
- @Before
- public void setUpData() {
- doInHibernate( this::sessionFactory, session -> {
+ @BeforeEach
+ public void setUpData(SessionFactoryScope scope) {
+ scope.inTransaction( session -> {
Address address = new Address();
address.setId( 1L );
address.setContent( "21 Jump St" );
@@ -53,18 +49,20 @@ public class LazyPersistWithDetachedAssociationTest
} );
}
- @Override
- protected boolean isCleanupTestDataRequired() {
- return true;
+ @AfterEach
+ public void tearDown(SessionFactoryScope scope) {
+ scope.inTransaction(
+ session -> {
+ session.createQuery( "delete from Person" ).executeUpdate();
+ session.createQuery( "delete from Address" ).executeUpdate();
+ }
+ );
}
@Test
@TestForIssue(jiraKey = "HHH-3846")
- public void testDetachedAssociationOnPersisting() {
- sessionFactory().getStatistics().clear();
-
- Address loadedAddress = doInHibernate(
- this::sessionFactory,
+ public void testDetachedAssociationOnPersisting(SessionFactoryScope scope) {
+ Address loadedAddress = scope.fromTransaction(
session -> {
// first load the address
Address _loadedAddress = session.load(
@@ -76,7 +74,7 @@ public class LazyPersistWithDetachedAssociationTest
}
);
- doInHibernate( this::sessionFactory, session -> {
+ scope.inTransaction( session -> {
session.get( Address.class, 1L );
Person person = new Person();
@@ -88,7 +86,7 @@ public class LazyPersistWithDetachedAssociationTest
} );
}
- @Entity
+ @Entity(name = "Address")
@Table(name = "eg_sbt_address")
public static class Address {
@@ -114,7 +112,7 @@ public class LazyPersistWithDetachedAssociationTest
}
}
- @Entity
+ @Entity(name = "Person")
@Table(name = "eg_sbt_person")
public static class Person {
@@ -131,7 +129,7 @@ public class LazyPersistWithDetachedAssociationTest
this.id = id;
}
- @ManyToOne(fetch = FetchType.LAZY, cascade = {})
+ @ManyToOne(fetch = FetchType.LAZY)
public Address getAddress() {
return address;
}
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/AbstractManyToManyAssociationClassTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/AbstractManyToManyAssociationClassTest.java
new file mode 100644
index 0000000000..5e39becaa5
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/AbstractManyToManyAssociationClassTest.java
@@ -0,0 +1,255 @@
+/*
+ * 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.orm.test.manytomanyassociationclass;
+
+import java.util.HashSet;
+
+import org.hibernate.testing.orm.junit.SessionFactory;
+import org.hibernate.testing.orm.junit.SessionFactoryScope;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
+
+/**
+ * Abstract class for tests on many-to-many association using an association class.
+ *
+ * @author Gail Badner
+ */
+@SessionFactory
+public abstract class AbstractManyToManyAssociationClassTest {
+ private User user;
+ private Group group;
+ private Membership membership;
+
+ public abstract Membership createMembership(String name);
+
+ @BeforeEach
+ protected void prepareTest(SessionFactoryScope scope) {
+ scope.inTransaction(
+ session -> {
+ user = new User( "user" );
+ group = new Group( "group" );
+ session.save( user );
+ session.save( group );
+ membership = createMembership( "membership" );
+ addMembership( user, group, membership );
+ }
+ );
+ }
+
+ @AfterEach
+ protected void cleanupTest(SessionFactoryScope scope) {
+ scope.inTransaction(
+ session -> {
+ session.createQuery( "delete from " + membership.getClass().getName() );
+ session.createQuery( "delete from User" );
+ session.createQuery( "delete from Group" );
+ }
+ );
+ }
+
+ public User getUser() {
+ return user;
+ }
+
+ public Group getGroup() {
+ return group;
+ }
+
+ public Membership getMembership() {
+ return membership;
+ }
+
+ @Test
+ public void testRemoveAndAddSameElement(SessionFactoryScope scope) {
+ deleteMembership( user, group, membership );
+ addMembership( user, group, membership );
+
+ scope.inTransaction(
+ session ->
+ session.merge( user )
+ );
+
+ scope.inTransaction(
+ session -> {
+ user = session.get( User.class, user.getId() );
+ group = session.get( Group.class, group.getId() );
+ membership = session.get( membership.getClass(), membership.getId() );
+ assertEquals( "user", user.getName() );
+ assertEquals( "group", group.getName() );
+ assertEquals( "membership", membership.getName() );
+ assertEquals( 1, user.getMemberships().size() );
+ assertEquals( 1, group.getMemberships().size() );
+ assertSame( membership, user.getMemberships().iterator().next() );
+ assertSame( membership, group.getMemberships().iterator().next() );
+ assertSame( user, membership.getUser() );
+ assertSame( group, membership.getGroup() );
+ }
+ );
+ }
+
+ @Test
+ public void testRemoveAndAddEqualElement(SessionFactoryScope scope) {
+ deleteMembership( user, group, membership );
+ membership = createMembership( "membership" );
+ addMembership( user, group, membership );
+
+ scope.inTransaction(
+ session ->
+ session.merge( user )
+ );
+
+ scope.inTransaction(
+ session -> {
+ user = session.get( User.class, user.getId() );
+ group = session.get( Group.class, group.getId() );
+ membership = session.get( membership.getClass(), membership.getId() );
+ assertEquals( "user", user.getName() );
+ assertEquals( "group", group.getName() );
+ assertEquals( "membership", membership.getName() );
+ assertEquals( 1, user.getMemberships().size() );
+ assertEquals( 1, group.getMemberships().size() );
+ assertSame( membership, user.getMemberships().iterator().next() );
+ assertSame( membership, group.getMemberships().iterator().next() );
+ assertSame( user, membership.getUser() );
+ assertSame( group, membership.getGroup() );
+ }
+ );
+ }
+
+ @Test
+ public void testRemoveAndAddEqualCollection(SessionFactoryScope scope) {
+ deleteMembership( user, group, membership );
+ membership = createMembership( "membership" );
+ user.setMemberships( new HashSet() );
+ group.setMemberships( new HashSet() );
+ addMembership( user, group, membership );
+
+ scope.inTransaction(
+ session ->
+ session.merge( user )
+ );
+
+ scope.inTransaction(
+ session -> {
+ user = session.get( User.class, user.getId() );
+ group = session.get( Group.class, group.getId() );
+ membership = session.get( membership.getClass(), membership.getId() );
+ assertEquals( "user", user.getName() );
+ assertEquals( "group", group.getName() );
+ assertEquals( "membership", membership.getName() );
+ assertEquals( 1, user.getMemberships().size() );
+ assertEquals( 1, group.getMemberships().size() );
+ assertSame( membership, user.getMemberships().iterator().next() );
+ assertSame( membership, group.getMemberships().iterator().next() );
+ assertSame( user, membership.getUser() );
+ assertSame( group, membership.getGroup() );
+ }
+ );
+ }
+
+ @Test
+ public void testRemoveAndAddSameElementNonKeyModified(SessionFactoryScope scope) {
+ deleteMembership( user, group, membership );
+ addMembership( user, group, membership );
+ membership.setName( "membership1" );
+
+ scope.inTransaction(
+ session ->
+ session.merge( user )
+ );
+
+ scope.inTransaction(
+ session -> {
+ user = session.get( User.class, user.getId() );
+ group = session.get( Group.class, group.getId() );
+ membership = session.get( membership.getClass(), membership.getId() );
+ assertEquals( "user", user.getName() );
+ assertEquals( "group", group.getName() );
+ assertEquals( "membership1", membership.getName() );
+ assertEquals( 1, user.getMemberships().size() );
+ assertEquals( 1, group.getMemberships().size() );
+ assertSame( membership, user.getMemberships().iterator().next() );
+ assertSame( membership, group.getMemberships().iterator().next() );
+ assertSame( user, membership.getUser() );
+ assertSame( group, membership.getGroup() );
+ }
+ );
+ }
+
+ @Test
+ public void testRemoveAndAddEqualElementNonKeyModified(SessionFactoryScope scope) {
+ deleteMembership( user, group, membership );
+ membership = createMembership( "membership" );
+ addMembership( user, group, membership );
+ membership.setName( "membership1" );
+
+ scope.inTransaction(
+ session ->
+ session.merge( user )
+ );
+
+ scope.inTransaction(
+ session -> {
+ user = session.get( User.class, user.getId() );
+ group = session.get( Group.class, group.getId() );
+ membership = session.get( membership.getClass(), membership.getId() );
+ assertEquals( "user", user.getName() );
+ assertEquals( "group", group.getName() );
+ assertEquals( "membership1", membership.getName() );
+ assertEquals( 1, user.getMemberships().size() );
+ assertEquals( 1, group.getMemberships().size() );
+ assertSame( membership, user.getMemberships().iterator().next() );
+ assertSame( membership, group.getMemberships().iterator().next() );
+ assertSame( user, membership.getUser() );
+ assertSame( group, membership.getGroup() );
+ }
+ );
+ }
+
+ @Test
+ public void testDeleteDetached(SessionFactoryScope scope) {
+ scope.inTransaction(
+ session -> {
+ session.delete( user );
+ session.delete( group );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ assertNull( session.get( User.class, user.getId() ) );
+ assertNull( session.get( Group.class, group.getId() ) );
+ assertNull( session.get( membership.getClass(), membership.getId() ) );
+ }
+ );
+ }
+
+ public void deleteMembership(User u, Group g, Membership ug) {
+ if ( u == null || g == null ) {
+ throw new IllegalArgumentException();
+ }
+ u.getMemberships().remove( ug );
+ g.getMemberships().remove( ug );
+ ug.setUser( null );
+ ug.setGroup( null );
+ }
+
+ public void addMembership(User u, Group g, Membership ug) {
+ if ( u == null || g == null ) {
+ throw new IllegalArgumentException();
+ }
+ ug.setUser( u );
+ ug.setGroup( g );
+ u.getMemberships().add( ug );
+ g.getMemberships().add( ug );
+ }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/test/manytomanyassociationclass/Group.java b/hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/Group.java
similarity index 95%
rename from hibernate-core/src/test/java/org/hibernate/test/manytomanyassociationclass/Group.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/Group.java
index fb2a2a342b..cb2765db4d 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/manytomanyassociationclass/Group.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/Group.java
@@ -4,7 +4,7 @@
* 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.manytomanyassociationclass;
+package org.hibernate.orm.test.manytomanyassociationclass;
import java.util.HashSet;
import java.util.Set;
diff --git a/hibernate-core/src/test/java/org/hibernate/test/manytomanyassociationclass/Membership.java b/hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/Membership.java
similarity index 96%
rename from hibernate-core/src/test/java/org/hibernate/test/manytomanyassociationclass/Membership.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/Membership.java
index 0b737fc730..66cc057588 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/manytomanyassociationclass/Membership.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/Membership.java
@@ -4,7 +4,7 @@
* 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.manytomanyassociationclass;
+package org.hibernate.orm.test.manytomanyassociationclass;
import java.io.Serializable;
/**
diff --git a/hibernate-core/src/test/java/org/hibernate/test/manytomanyassociationclass/User.java b/hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/User.java
similarity index 95%
rename from hibernate-core/src/test/java/org/hibernate/test/manytomanyassociationclass/User.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/User.java
index 0b698f8065..0e48b2d726 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/manytomanyassociationclass/User.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/User.java
@@ -4,7 +4,7 @@
* 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.manytomanyassociationclass;
+package org.hibernate.orm.test.manytomanyassociationclass;
import java.util.HashSet;
import java.util.Set;
diff --git a/hibernate-core/src/test/java/org/hibernate/test/manytomanyassociationclass/compositeid/ManyToManyAssociationClassCompositeIdTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/compositeid/ManyToManyAssociationClassCompositeIdTest.java
similarity index 55%
rename from hibernate-core/src/test/java/org/hibernate/test/manytomanyassociationclass/compositeid/ManyToManyAssociationClassCompositeIdTest.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/compositeid/ManyToManyAssociationClassCompositeIdTest.java
index df6c9fc355..64ec368266 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/manytomanyassociationclass/compositeid/ManyToManyAssociationClassCompositeIdTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/compositeid/ManyToManyAssociationClassCompositeIdTest.java
@@ -4,12 +4,13 @@
* 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.manytomanyassociationclass.compositeid;
+package org.hibernate.orm.test.manytomanyassociationclass.compositeid;
-import org.hibernate.test.manytomanyassociationclass.AbstractManyToManyAssociationClassTest;
-import org.hibernate.test.manytomanyassociationclass.Group;
-import org.hibernate.test.manytomanyassociationclass.Membership;
-import org.hibernate.test.manytomanyassociationclass.User;
+import org.hibernate.testing.orm.junit.DomainModel;
+import org.hibernate.orm.test.manytomanyassociationclass.AbstractManyToManyAssociationClassTest;
+import org.hibernate.orm.test.manytomanyassociationclass.Group;
+import org.hibernate.orm.test.manytomanyassociationclass.Membership;
+import org.hibernate.orm.test.manytomanyassociationclass.User;
/**
* Tests on many-to-many association using an association class with a composite ID containing
@@ -17,17 +18,16 @@ import org.hibernate.test.manytomanyassociationclass.User;
*
* @author Gail Badner
*/
+@DomainModel(
+ xmlMappings = "org/hibernate/orm/test/manytomanyassociationclass/compositeid/Mappings.hbm.xml"
+)
public class ManyToManyAssociationClassCompositeIdTest extends AbstractManyToManyAssociationClassTest {
- @Override
- public String[] getMappings() {
- return new String[] { "manytomanyassociationclass/compositeid/Mappings.hbm.xml" };
- }
@Override
- public Membership createMembership( String name ) {
+ public Membership createMembership(String name) {
return new MembershipWithCompositeId( name );
}
-
+
@Override
public void deleteMembership(User u, Group g, Membership ug) {
if ( u == null || g == null ) {
@@ -35,7 +35,7 @@ public class ManyToManyAssociationClassCompositeIdTest extends AbstractManyToMan
}
u.getMemberships().remove( ug );
g.getMemberships().remove( ug );
- ug.setId(null);
+ ug.setId( null );
}
}
diff --git a/hibernate-core/src/test/java/org/hibernate/test/manytomanyassociationclass/compositeid/Mappings.hbm.xml b/hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/compositeid/Mappings.hbm.xml
similarity index 83%
rename from hibernate-core/src/test/java/org/hibernate/test/manytomanyassociationclass/compositeid/Mappings.hbm.xml
rename to hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/compositeid/Mappings.hbm.xml
index 28a17ffd4e..9683be01af 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/manytomanyassociationclass/compositeid/Mappings.hbm.xml
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/compositeid/Mappings.hbm.xml
@@ -7,9 +7,9 @@
-->
-
+
-
+
@@ -20,7 +20,7 @@
-
+
@@ -38,9 +38,9 @@
-
-
diff --git a/hibernate-core/src/test/java/org/hibernate/test/manytomanyassociationclass/compositeid/MembershipWithCompositeId.java b/hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/compositeid/MembershipWithCompositeId.java
similarity index 88%
rename from hibernate-core/src/test/java/org/hibernate/test/manytomanyassociationclass/compositeid/MembershipWithCompositeId.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/compositeid/MembershipWithCompositeId.java
index efbb4a46db..a7c35a188e 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/manytomanyassociationclass/compositeid/MembershipWithCompositeId.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/compositeid/MembershipWithCompositeId.java
@@ -4,12 +4,12 @@
* 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.manytomanyassociationclass.compositeid;
+package org.hibernate.orm.test.manytomanyassociationclass.compositeid;
import java.io.Serializable;
-import org.hibernate.test.manytomanyassociationclass.Group;
-import org.hibernate.test.manytomanyassociationclass.Membership;
-import org.hibernate.test.manytomanyassociationclass.User;
+import org.hibernate.orm.test.manytomanyassociationclass.Group;
+import org.hibernate.orm.test.manytomanyassociationclass.Membership;
+import org.hibernate.orm.test.manytomanyassociationclass.User;
/**
* Models a user's membership in a group.
diff --git a/hibernate-core/src/test/java/org/hibernate/test/manytomanyassociationclass/surrogateid/assigned/ManyToManyAssociationClassAssignedIdTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/surrogateid/assigned/ManyToManyAssociationClassAssignedIdTest.java
similarity index 58%
rename from hibernate-core/src/test/java/org/hibernate/test/manytomanyassociationclass/surrogateid/assigned/ManyToManyAssociationClassAssignedIdTest.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/surrogateid/assigned/ManyToManyAssociationClassAssignedIdTest.java
index 1c4c2d374d..96d71ddf37 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/manytomanyassociationclass/surrogateid/assigned/ManyToManyAssociationClassAssignedIdTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/surrogateid/assigned/ManyToManyAssociationClassAssignedIdTest.java
@@ -4,22 +4,21 @@
* 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.manytomanyassociationclass.surrogateid.assigned;
+package org.hibernate.orm.test.manytomanyassociationclass.surrogateid.assigned;
-import org.hibernate.test.manytomanyassociationclass.AbstractManyToManyAssociationClassTest;
-import org.hibernate.test.manytomanyassociationclass.Membership;
+import org.hibernate.testing.orm.junit.DomainModel;
+import org.hibernate.orm.test.manytomanyassociationclass.AbstractManyToManyAssociationClassTest;
+import org.hibernate.orm.test.manytomanyassociationclass.Membership;
/**
* Tests on many-to-many association using an association class with a surrogate ID that is assigned.
*
* @author Gail Badner
*/
+@DomainModel(
+ xmlMappings = "org/hibernate/orm/test/manytomanyassociationclass/surrogateid/assigned/Mappings.hbm.xml"
+)
public class ManyToManyAssociationClassAssignedIdTest extends AbstractManyToManyAssociationClassTest {
- @Override
- public String[] getMappings() {
- return new String[] { "manytomanyassociationclass/surrogateid/assigned/Mappings.hbm.xml" };
- }
-
@Override
public Membership createMembership(String name) {
return new Membership( Long.valueOf( 1000 ), name );
diff --git a/hibernate-core/src/test/java/org/hibernate/test/manytomanyassociationclass/surrogateid/assigned/Mappings.hbm.xml b/hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/surrogateid/assigned/Mappings.hbm.xml
similarity index 95%
rename from hibernate-core/src/test/java/org/hibernate/test/manytomanyassociationclass/surrogateid/assigned/Mappings.hbm.xml
rename to hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/surrogateid/assigned/Mappings.hbm.xml
index 6210ce6a84..8d69ff1c7c 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/manytomanyassociationclass/surrogateid/assigned/Mappings.hbm.xml
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/surrogateid/assigned/Mappings.hbm.xml
@@ -7,7 +7,7 @@
-->
-
+
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/surrogateid/generated/ManyToManyAssociationClassGeneratedIdTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/surrogateid/generated/ManyToManyAssociationClassGeneratedIdTest.java
new file mode 100644
index 0000000000..740033fc3d
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/surrogateid/generated/ManyToManyAssociationClassGeneratedIdTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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.orm.test.manytomanyassociationclass.surrogateid.generated;
+
+import java.util.HashSet;
+import javax.persistence.PersistenceException;
+
+import org.hibernate.exception.ConstraintViolationException;
+
+import org.hibernate.testing.orm.junit.DomainModel;
+import org.hibernate.testing.orm.junit.SessionFactoryScope;
+import org.hibernate.orm.test.manytomanyassociationclass.AbstractManyToManyAssociationClassTest;
+import org.hibernate.orm.test.manytomanyassociationclass.Membership;
+import org.junit.jupiter.api.Test;
+
+import static org.hibernate.testing.orm.junit.ExtraAssertions.assertTyping;
+import static org.junit.jupiter.api.Assertions.fail;
+
+/**
+ * Tests on many-to-many association using an association class with a surrogate ID that is generated.
+ *
+ * @author Gail Badner
+ */
+@DomainModel(
+ xmlMappings = "org/hibernate/orm/test/manytomanyassociationclass/surrogateid/generated/Mappings.hbm.xml"
+)
+public class ManyToManyAssociationClassGeneratedIdTest extends AbstractManyToManyAssociationClassTest {
+ @Override
+ public Membership createMembership(String name) {
+ return new Membership( name );
+ }
+
+ @Test
+ public void testRemoveAndAddEqualElement(SessionFactoryScope scope) {
+ deleteMembership( getUser(), getGroup(), getMembership() );
+ addMembership( getUser(), getGroup(), createMembership( "membership" ) );
+
+ scope.inSession(
+ session -> {
+ try {
+ session.getTransaction().begin();
+ // The new membership is transient (it has a null surrogate ID), so
+ // Hibernate assumes that it should be added to the collection.
+ // Inserts are done before deletes, so a ConstraintViolationException
+ // will be thrown on the insert because the unique constraint on the
+ // user and group IDs in the join table is violated. See HHH-2801.
+ session.merge( getUser() );
+ session.getTransaction().commit();
+ fail( "should have failed because inserts are before deletes" );
+ }
+ catch (Exception e) {
+ session.getTransaction().rollback();
+ // expected
+ assertTyping( ConstraintViolationException.class, e.getCause() );
+ }
+ }
+ );
+ }
+
+ @Test
+ public void testRemoveAndAddEqualCollection(SessionFactoryScope scope) {
+ deleteMembership( getUser(), getGroup(), getMembership() );
+ getUser().setMemberships( new HashSet() );
+ getGroup().setMemberships( new HashSet() );
+ addMembership( getUser(), getGroup(), createMembership( "membership" ) );
+
+ scope.inSession(
+ session -> {
+ try {
+ session.getTransaction().begin();
+ // The new membership is transient (it has a null surrogate ID), so
+ // Hibernate assumes that it should be added to the collection.
+ // Inserts are done before deletes, so a ConstraintViolationException
+ // will be thrown on the insert because the unique constraint on the
+ // user and group IDs in the join table is violated. See HHH-2801.
+ session.merge( getUser() );
+ session.getTransaction().commit();
+ fail( "should have failed because inserts are before deletes" );
+ }
+ catch (PersistenceException e) {
+ session.getTransaction().rollback();
+ // expected
+ assertTyping( ConstraintViolationException.class, e.getCause() );
+ }
+ }
+ );
+ }
+
+ @Test
+ public void testRemoveAndAddEqualElementNonKeyModified(SessionFactoryScope scope) {
+ deleteMembership( getUser(), getGroup(), getMembership() );
+ Membership membershipNew = createMembership( "membership" );
+ addMembership( getUser(), getGroup(), membershipNew );
+ membershipNew.setName( "membership1" );
+
+ scope.inSession(
+ session -> {
+ try {
+ session.getTransaction().begin();
+ // The new membership is transient (it has a null surrogate ID), so
+ // Hibernate assumes that it should be added to the collection.
+ // Inserts are done before deletes, so a ConstraintViolationException
+ // will be thrown on the insert because the unique constraint on the
+ // user and group IDs in the join table is violated. See HHH-2801.
+ session.merge( getUser() );
+ session.getTransaction().commit();
+ fail( "should have failed because inserts are before deletes" );
+ }
+ catch (PersistenceException e) {
+ session.getTransaction().rollback();
+ // expected
+ assertTyping( ConstraintViolationException.class, e.getCause() );
+ }
+ }
+ );
+ }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/test/manytomanyassociationclass/surrogateid/generated/Mappings.hbm.xml b/hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/surrogateid/generated/Mappings.hbm.xml
similarity index 95%
rename from hibernate-core/src/test/java/org/hibernate/test/manytomanyassociationclass/surrogateid/generated/Mappings.hbm.xml
rename to hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/surrogateid/generated/Mappings.hbm.xml
index d37bfd1cab..e50d61c740 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/manytomanyassociationclass/surrogateid/generated/Mappings.hbm.xml
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/manytomanyassociationclass/surrogateid/generated/Mappings.hbm.xml
@@ -7,7 +7,7 @@
-->
-
+
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ondelete/Address.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/Address.java
similarity index 91%
rename from hibernate-core/src/test/java/org/hibernate/test/ondelete/Address.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/Address.java
index fb3b6c7b26..5924076ea3 100755
--- a/hibernate-core/src/test/java/org/hibernate/test/ondelete/Address.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/Address.java
@@ -6,7 +6,7 @@
*/
//$Id: Address.java 7119 2005-06-12 22:03:30Z oneovthafew $
-package org.hibernate.test.ondelete;
+package org.hibernate.orm.test.ondelete;
/**
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ondelete/Employee.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/Employee.java
similarity index 96%
rename from hibernate-core/src/test/java/org/hibernate/test/ondelete/Employee.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/Employee.java
index 657a754e65..ae0471f54b 100755
--- a/hibernate-core/src/test/java/org/hibernate/test/ondelete/Employee.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/Employee.java
@@ -6,7 +6,7 @@
*/
//$Id: Employee.java 7119 2005-06-12 22:03:30Z oneovthafew $
-package org.hibernate.test.ondelete;
+package org.hibernate.orm.test.ondelete;
import java.math.BigDecimal;
/**
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/OnDeleteTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/OnDeleteTest.java
new file mode 100755
index 0000000000..6b9cf13af1
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/OnDeleteTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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.orm.test.ondelete;
+
+import java.util.List;
+
+import org.hibernate.Transaction;
+import org.hibernate.stat.spi.StatisticsImplementor;
+
+import org.hibernate.testing.orm.junit.DialectFeatureChecks;
+import org.hibernate.testing.orm.junit.DomainModel;
+import org.hibernate.testing.orm.junit.RequiresDialectFeature;
+import org.hibernate.testing.orm.junit.SessionFactory;
+import org.hibernate.testing.orm.junit.SessionFactoryScope;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+
+/**
+ * @author Gavin King
+ */
+@DomainModel(
+ xmlMappings = "org/hibernate/orm/test/ondelete/Person.hbm.xml"
+)
+@SessionFactory(
+ generateStatistics = true
+)
+public class OnDeleteTest {
+
+ @AfterEach
+ public void tearDown(SessionFactoryScope scope){
+ scope.inTransaction(
+ session -> {
+ session.createQuery( "delete from Salesperson" ).executeUpdate();
+ session.createQuery( "delete from Employee" ).executeUpdate();
+ session.createQuery( "delete from Person" ).executeUpdate();
+ }
+ );
+ }
+
+ @Test
+ @RequiresDialectFeature(
+ feature = DialectFeatureChecks.SupportsCircularCascadeDeleteCheck.class,
+ comment = "db/dialect does not support circular cascade delete constraints"
+ )
+ public void testJoinedSubclass(SessionFactoryScope scope) {
+ scope.inTransaction(
+ session -> {
+ Salesperson mark = new Salesperson();
+ mark.setName( "Mark" );
+ mark.setTitle( "internal sales" );
+ mark.setSex( 'M' );
+ mark.setAddress( "buckhead" );
+ mark.setZip( "30305" );
+ mark.setCountry( "USA" );
+
+ Person joe = new Person();
+ joe.setName( "Joe" );
+ joe.setAddress( "San Francisco" );
+ joe.setZip( "XXXXX" );
+ joe.setCountry( "USA" );
+ joe.setSex( 'M' );
+ joe.setSalesperson( mark );
+ mark.getCustomers().add( joe );
+
+ session.save( mark );
+
+ session.getTransaction().commit();
+
+ final StatisticsImplementor statistics = scope.getSessionFactory().getStatistics();
+
+ assertThat( statistics.getEntityInsertCount(), is( 2L ) );
+ assertThat( statistics.getPrepareStatementCount(), is( 5L ) );
+
+ statistics.clear();
+
+ Transaction t = session.beginTransaction();
+ session.delete( mark );
+ t.commit();
+
+ assertThat( statistics.getEntityDeleteCount(), is( 2L ) );
+ if ( scope.getSessionFactory().getJdbcServices().getDialect().supportsCascadeDelete() ) {
+ assertThat( statistics.getPrepareStatementCount(), is( 1L ) );
+ }
+
+ session.beginTransaction();
+ List names = session.createQuery( "select name from Person" ).list();
+ assertTrue( names.isEmpty() );
+ }
+ );
+
+ }
+
+}
+
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ondelete/Person.hbm.xml b/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/Person.hbm.xml
similarity index 97%
rename from hibernate-core/src/test/java/org/hibernate/test/ondelete/Person.hbm.xml
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/Person.hbm.xml
index 6e127dfcb7..e7a65147b3 100755
--- a/hibernate-core/src/test/java/org/hibernate/test/ondelete/Person.hbm.xml
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/Person.hbm.xml
@@ -17,7 +17,7 @@
-->
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ondelete/Person.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/Person.java
similarity index 97%
rename from hibernate-core/src/test/java/org/hibernate/test/ondelete/Person.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/Person.java
index 4463bfb81c..bdd493a1c2 100755
--- a/hibernate-core/src/test/java/org/hibernate/test/ondelete/Person.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/Person.java
@@ -6,7 +6,7 @@
*/
//$Id: Person.java 7119 2005-06-12 22:03:30Z oneovthafew $
-package org.hibernate.test.ondelete;
+package org.hibernate.orm.test.ondelete;
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ondelete/Salesperson.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/Salesperson.java
similarity index 93%
rename from hibernate-core/src/test/java/org/hibernate/test/ondelete/Salesperson.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/Salesperson.java
index 13e828ecc8..d287e7580b 100755
--- a/hibernate-core/src/test/java/org/hibernate/test/ondelete/Salesperson.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/Salesperson.java
@@ -6,7 +6,7 @@
*/
//$Id: Salesperson.java 7119 2005-06-12 22:03:30Z oneovthafew $
-package org.hibernate.test.ondelete;
+package org.hibernate.orm.test.ondelete;
import java.util.HashSet;
import java.util.Set;
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/toone/ToOneOnDeleteTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/toone/ToOneOnDeleteTest.java
new file mode 100644
index 0000000000..8b208335b5
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/toone/ToOneOnDeleteTest.java
@@ -0,0 +1,127 @@
+package org.hibernate.orm.test.ondelete.toone;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToOne;
+
+import org.hibernate.annotations.OnDelete;
+import org.hibernate.annotations.OnDeleteAction;
+import org.hibernate.dialect.SybaseDialect;
+
+import org.hibernate.testing.orm.junit.DomainModel;
+import org.hibernate.testing.orm.junit.SessionFactory;
+import org.hibernate.testing.orm.junit.SessionFactoryScope;
+import org.hibernate.testing.orm.junit.SkipForDialect;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+
+
+/**
+ * @author Vlad Mihalcea
+ */
+@DomainModel(
+ annotatedClasses = {
+ ToOneOnDeleteTest.Parent.class,
+ ToOneOnDeleteTest.Child.class,
+ ToOneOnDeleteTest.GrandChild.class
+ }
+)
+@SessionFactory
+public class ToOneOnDeleteTest {
+
+ @AfterEach
+ public void tearDown(SessionFactoryScope scope){
+ scope.inTransaction(
+ session -> {
+ session.createQuery( "delete from Parent" ).executeUpdate();
+ session.createQuery( "delete from Child" ).executeUpdate();
+ session.createQuery( "delete from GrandChild" ).executeUpdate();
+ }
+ );
+ }
+
+ @Test
+ @SkipForDialect(
+ dialectClass = SybaseDialect.class,
+ matchSubTypes = true,
+ reason = "HHH-13559 on-delete=\"cascade\" is not supported for unidirectional to-one associations using Sybase"
+ )
+ public void testManyToOne(SessionFactoryScope scope) {
+ scope.inTransaction(
+ session -> {
+ Parent parent = new Parent();
+ parent.id = 1L;
+ session.persist( parent );
+
+ Child child1 = new Child();
+ child1.id = 1L;
+ child1.parent = parent;
+ session.persist( child1 );
+
+ GrandChild grandChild11 = new GrandChild();
+ grandChild11.id = 1L;
+ grandChild11.parent = child1;
+ session.persist( grandChild11 );
+
+ Child child2 = new Child();
+ child2.id = 2L;
+ child2.parent = parent;
+ session.persist( child2 );
+
+ GrandChild grandChild21 = new GrandChild();
+ grandChild21.id = 2L;
+ grandChild21.parent = child2;
+ session.persist( grandChild21 );
+
+ GrandChild grandChild22 = new GrandChild();
+ grandChild22.id = 3L;
+ grandChild22.parent = child2;
+ session.persist( grandChild22 );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Parent parent = session.get( Parent.class, 1L );
+ session.delete( parent );
+ }
+ );
+ }
+
+
+ @Entity(name = "Parent")
+ public static class Parent {
+
+ @Id
+ private Long id;
+
+ private String name;
+ }
+
+ @Entity(name = "Child")
+ public static class Child {
+
+ @Id
+ private Long id;
+
+ private String name;
+
+ @ManyToOne
+ @OnDelete(action = OnDeleteAction.CASCADE)
+ private Parent parent;
+ }
+
+ @Entity(name = "GrandChild")
+ public static class GrandChild {
+
+ @Id
+ private Long id;
+
+ private String name;
+
+ @OneToOne
+ @OnDelete(action = OnDeleteAction.CASCADE)
+ private Child parent;
+ }
+}
\ No newline at end of file
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ondelete/toone/hbm/Child.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/toone/hbm/Child.java
similarity index 91%
rename from hibernate-core/src/test/java/org/hibernate/test/ondelete/toone/hbm/Child.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/toone/hbm/Child.java
index 320a0cb391..4c45879048 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ondelete/toone/hbm/Child.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/toone/hbm/Child.java
@@ -4,7 +4,7 @@
* 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.ondelete.toone.hbm;
+package org.hibernate.orm.test.ondelete.toone.hbm;
/**
* @author Vlad Mihalcea
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ondelete/toone/hbm/GrandChild.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/toone/hbm/GrandChild.java
similarity index 91%
rename from hibernate-core/src/test/java/org/hibernate/test/ondelete/toone/hbm/GrandChild.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/toone/hbm/GrandChild.java
index 2bfab9373d..32555f4674 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ondelete/toone/hbm/GrandChild.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/toone/hbm/GrandChild.java
@@ -4,7 +4,7 @@
* 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.ondelete.toone.hbm;
+package org.hibernate.orm.test.ondelete.toone.hbm;
/**
* @author Vlad Mihalcea
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ondelete/toone/hbm/Parent.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/toone/hbm/Parent.java
similarity index 88%
rename from hibernate-core/src/test/java/org/hibernate/test/ondelete/toone/hbm/Parent.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/toone/hbm/Parent.java
index ada976a039..4f722f069a 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ondelete/toone/hbm/Parent.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/toone/hbm/Parent.java
@@ -4,7 +4,7 @@
* 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.ondelete.toone.hbm;
+package org.hibernate.orm.test.ondelete.toone.hbm;
/**
* @author Vlad Mihalcea
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ondelete/toone/hbm/ToOneOnDelete.hbm.xml b/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/toone/hbm/ToOneOnDelete.hbm.xml
similarity index 92%
rename from hibernate-core/src/test/java/org/hibernate/test/ondelete/toone/hbm/ToOneOnDelete.hbm.xml
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/toone/hbm/ToOneOnDelete.hbm.xml
index c15feb22ca..a6a4a3f7bb 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ondelete/toone/hbm/ToOneOnDelete.hbm.xml
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/toone/hbm/ToOneOnDelete.hbm.xml
@@ -5,7 +5,7 @@
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or .
-->
-
+
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/toone/hbm/ToOneOnDeleteHbmTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/toone/hbm/ToOneOnDeleteHbmTest.java
new file mode 100644
index 0000000000..e9d34fb905
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ondelete/toone/hbm/ToOneOnDeleteHbmTest.java
@@ -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 .
+ */
+package org.hibernate.orm.test.ondelete.toone.hbm;
+
+import org.hibernate.dialect.SybaseDialect;
+
+import org.hibernate.testing.orm.junit.DomainModel;
+import org.hibernate.testing.orm.junit.SessionFactory;
+import org.hibernate.testing.orm.junit.SessionFactoryScope;
+import org.hibernate.testing.orm.junit.SkipForDialect;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+
+
+/**
+ * @author Vlad Mihalcea
+ */
+@DomainModel(
+ xmlMappings = "org/hibernate/orm/test/ondelete/toone/hbm/ToOneOnDelete.hbm.xml"
+)
+@SessionFactory
+public class ToOneOnDeleteHbmTest {
+
+ @AfterEach
+ public void tearDown(SessionFactoryScope scope){
+ scope.inTransaction(
+ session -> {
+ session.createQuery( "delete from Parent" ).executeUpdate();
+ session.createQuery( "delete from Child" ).executeUpdate();
+ session.createQuery( "delete from GrandChild" ).executeUpdate();
+ }
+ );
+ }
+
+ @Test
+ @SkipForDialect(
+ dialectClass = SybaseDialect.class,
+ matchSubTypes = true,
+ reason = "HHH-13559 on-delete=\"cascade\" is not supported for unidirectional to-one associations using Sybase"
+ )
+ public void testManyToOne(SessionFactoryScope scope) {
+ scope.inTransaction(
+ session -> {
+ Parent parent = new Parent();
+ parent.setId( 1L );
+ session.persist( parent );
+
+ Child child1 = new Child();
+ child1.setId( 1L );
+ child1.setParent( parent );
+ session.persist( child1 );
+
+ GrandChild grandChild11 = new GrandChild();
+ grandChild11.setId( 1L );
+ grandChild11.setParent( child1 );
+ session.persist( grandChild11 );
+
+ Child child2 = new Child();
+ child2.setId( 2L );
+ child2.setParent( parent );
+ session.persist( child2 );
+
+ GrandChild grandChild21 = new GrandChild();
+ grandChild21.setId( 2L );
+ grandChild21.setParent( child2 );
+ session.persist( grandChild21 );
+
+ }
+ );
+
+
+ scope.inTransaction(
+ session -> {
+ Parent parent = session.get( Parent.class, 1L );
+ session.delete( parent );
+ }
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ondemandload/Inventory.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ondemandload/Inventory.java
similarity index 97%
rename from hibernate-core/src/test/java/org/hibernate/test/ondemandload/Inventory.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ondemandload/Inventory.java
index caeeaa654d..7487e8ce39 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ondemandload/Inventory.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ondemandload/Inventory.java
@@ -4,7 +4,7 @@
* 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.ondemandload;
+package org.hibernate.orm.test.ondemandload;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/ondemandload/LazyLoadingTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ondemandload/LazyLoadingTest.java
new file mode 100644
index 0000000000..36ded46a22
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ondemandload/LazyLoadingTest.java
@@ -0,0 +1,182 @@
+/*
+ * 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.orm.test.ondemandload;
+
+import java.math.BigDecimal;
+
+import org.hibernate.Hibernate;
+import org.hibernate.cfg.Environment;
+import org.hibernate.stat.spi.StatisticsImplementor;
+
+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.hibernate.testing.orm.junit.Setting;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+
+@DomainModel(
+ annotatedClasses = {
+ Store.class,
+ Inventory.class,
+ Product.class
+ }
+)
+@SessionFactory(
+ generateStatistics = true
+)
+@ServiceRegistry(
+ settings = {
+ @Setting(name = Environment.ENABLE_LAZY_LOAD_NO_TRANS, value = "true")
+ }
+)
+public class LazyLoadingTest {
+
+ @BeforeEach
+ public void setUpData(SessionFactoryScope scope) {
+ scope.inTransaction(
+ session -> {
+ Store store = new Store( 1 )
+ .setName( "Acme Super Outlet" );
+ session.persist( store );
+
+ Product product = new Product( "007" )
+ .setName( "widget" )
+ .setDescription( "FooBar" );
+ session.persist( product );
+
+ store.addInventoryProduct( product )
+ .setQuantity( 10L )
+ .setStorePrice( new BigDecimal( 500 ) );
+ }
+ );
+ }
+
+ @AfterEach
+ public void cleanUpData(SessionFactoryScope scope) {
+ scope.inTransaction(
+ session -> {
+ session.delete( session.get( Store.class, 1 ) );
+ session.delete( session.get( Product.class, "007" ) );
+ }
+ );
+ }
+
+ @Test
+ public void testLazyCollectionLoadingWithClearedSession(SessionFactoryScope scope) {
+ final StatisticsImplementor statistics = scope.getSessionFactory().getStatistics();
+ statistics.clear();
+
+ scope.inTransaction(
+ session -> {
+ // first load the store, making sure collection is not initialized
+ Store store = (Store) session.get( Store.class, 1 );
+ assertNotNull( store );
+ assertFalse( Hibernate.isInitialized( store.getInventories() ) );
+
+ assertThat( statistics.getSessionOpenCount(), is( 1l ) );
+ assertThat( statistics.getSessionCloseCount(), is( 0l ) );
+
+ // then clear session and try to initialize collection
+ session.clear();
+ store.getInventories().size();
+ assertTrue( Hibernate.isInitialized( store.getInventories() ) );
+
+ assertThat( statistics.getSessionOpenCount(), is( 2l ) );
+ assertThat( statistics.getSessionCloseCount(), is( 1l ) );
+
+ session.clear();
+ store = (Store) session.get( Store.class, 1 );
+ assertNotNull( store );
+ assertFalse( Hibernate.isInitialized( store.getInventories() ) );
+
+ assertThat( statistics.getSessionOpenCount(), is( 2l ) );
+ assertThat( statistics.getSessionCloseCount(), is( 1l ) );
+
+ session.clear();
+ store.getInventories().iterator();
+ assertTrue( Hibernate.isInitialized( store.getInventories() ) );
+
+ assertThat( statistics.getSessionOpenCount(), is( 3l ) );
+ assertThat( statistics.getSessionCloseCount(), is( 2l ) );
+ }
+ );
+ }
+
+ @Test
+ public void testLazyCollectionLoadingWithClosedSession(SessionFactoryScope scope) {
+ final StatisticsImplementor statistics = scope.getSessionFactory().getStatistics();
+ statistics.clear();
+
+ Store s = scope.fromTransaction(
+ session -> {
+ // first load the store, making sure collection is not initialized
+ Store store = session.get( Store.class, 1 );
+ assertNotNull( store );
+ assertFalse( Hibernate.isInitialized( store.getInventories() ) );
+
+ assertThat( statistics.getSessionOpenCount(), is( 1l ) );
+ assertThat( statistics.getSessionCloseCount(), is( 0l ) );
+ return store;
+ }
+ );
+
+
+ // close the session and try to initialize collection
+
+ assertThat( statistics.getSessionOpenCount(), is( 1l ) );
+ assertThat( statistics.getSessionCloseCount(), is( 1l ) );
+
+ s.getInventories().size();
+ assertTrue( Hibernate.isInitialized( s.getInventories() ) );
+
+ assertThat( statistics.getSessionOpenCount(), is( 2l ) );
+ assertThat( statistics.getSessionCloseCount(), is( 2l ) );
+ }
+
+ @Test
+ public void testLazyEntityLoadingWithClosedSession(SessionFactoryScope scope) {
+ final StatisticsImplementor statistics = scope.getSessionFactory().getStatistics();
+ statistics.clear();
+
+ Store s = scope.fromTransaction(
+ session -> {
+ // first load the store, making sure it is not initialized
+ Store store = session.load( Store.class, 1 );
+ assertNotNull( store );
+ assertFalse( Hibernate.isInitialized( store ) );
+
+ assertThat( statistics.getSessionOpenCount(), is( 1l ) );
+ assertThat( statistics.getSessionCloseCount(), is( 0l ) );
+ return store;
+ }
+ );
+
+
+ // close the session and try to initialize store
+
+ assertThat( statistics.getSessionOpenCount(), is( 1l ) );
+ assertThat( statistics.getSessionCloseCount(), is( 1l ) );
+
+ s.getName();
+ assertTrue( Hibernate.isInitialized( s ) );
+
+ assertThat( statistics.getSessionOpenCount(), is( 2l ) );
+ assertThat( statistics.getSessionCloseCount(), is( 2l ) );
+ }
+
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ondemandload/Product.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ondemandload/Product.java
similarity index 96%
rename from hibernate-core/src/test/java/org/hibernate/test/ondemandload/Product.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ondemandload/Product.java
index c31b665106..46cabbd064 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ondemandload/Product.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ondemandload/Product.java
@@ -4,7 +4,7 @@
* 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.ondemandload;
+package org.hibernate.orm.test.ondemandload;
import javax.persistence.Entity;
import javax.persistence.Id;
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ondemandload/Store.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ondemandload/Store.java
similarity index 97%
rename from hibernate-core/src/test/java/org/hibernate/test/ondemandload/Store.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ondemandload/Store.java
index 95df78e6ea..22148101dc 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ondemandload/Store.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ondemandload/Store.java
@@ -4,7 +4,7 @@
* 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.ondemandload;
+package org.hibernate.orm.test.ondemandload;
import javax.persistence.CascadeType;
import javax.persistence.Column;
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/ondemandload/cache/CacheLazyLoadNoTransTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ondemandload/cache/CacheLazyLoadNoTransTest.java
new file mode 100644
index 0000000000..8466b0d9d5
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ondemandload/cache/CacheLazyLoadNoTransTest.java
@@ -0,0 +1,227 @@
+/*
+ * 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.orm.test.ondemandload.cache;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import javax.persistence.Cacheable;
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToMany;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+
+import org.hibernate.Hibernate;
+import org.hibernate.annotations.Cache;
+import org.hibernate.annotations.CacheConcurrencyStrategy;
+import org.hibernate.cache.spi.access.CollectionDataAccess;
+import org.hibernate.cfg.AvailableSettings;
+import org.hibernate.cfg.Environment;
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.persister.collection.CollectionPersister;
+
+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.hibernate.testing.orm.junit.Setting;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+
+/**
+ * @author Janario Oliveira
+ */
+@DomainModel(
+ annotatedClasses = {
+ CacheLazyLoadNoTransTest.Application.class,
+ CacheLazyLoadNoTransTest.Customer.class,
+ CacheLazyLoadNoTransTest.Item.class
+ }
+)
+@SessionFactory
+@ServiceRegistry(
+ settings = {
+ @Setting(name = AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS, value = "true"),
+ @Setting(name = Environment.USE_SECOND_LEVEL_CACHE, value = "true"),
+ @Setting(name = Environment.USE_QUERY_CACHE, value = "true"),
+ @Setting(name = Environment.CACHE_PROVIDER_CONFIG, value = "true"),
+ }
+)
+public class CacheLazyLoadNoTransTest {
+
+ @AfterEach
+ public void tearDown(SessionFactoryScope scope){
+ scope.inTransaction(
+ session -> {
+ session.createQuery( "delete from Application" ).executeUpdate();
+ session.createQuery( "delete from Item" ).executeUpdate();
+ session.createQuery( "delete from Customer" ).executeUpdate();
+ }
+ );
+ }
+
+ @Test
+ public void hibernateInitialize(SessionFactoryScope scope) {
+ Customer customer = new Customer();
+ Item item1 = new Item( customer );
+ Item item2 = new Item( customer );
+ customer.boughtItems.add( item1 );
+ customer.boughtItems.add( item2 );
+ persist( customer, scope );
+
+ customer = find( Customer.class, customer.id, scope );
+ assertFalse( Hibernate.isInitialized( customer.boughtItems ) );
+ Hibernate.initialize( customer.boughtItems );
+ assertTrue( Hibernate.isInitialized( customer.boughtItems ) );
+ }
+
+ @Test
+ public void testOneToMany(SessionFactoryScope scope) {
+ Customer customer = new Customer();
+ Item item1 = new Item( customer );
+ Item item2 = new Item( customer );
+ customer.boughtItems.add( item1 );
+ customer.boughtItems.add( item2 );
+ persist( customer, scope );
+
+ //init cache
+ assertFalse( isCached( customer.id, Customer.class, "boughtItems", scope ) );
+ customer = find( Customer.class, customer.id, scope );
+ assertThat( customer.boughtItems.size(), is( 2 ) );
+
+ //read from cache
+ assertTrue( isCached( customer.id, Customer.class, "boughtItems", scope ) );
+ customer = find( Customer.class, customer.id, scope );
+ assertThat( customer.boughtItems.size(), is( 2 ) );
+ }
+
+ @Test
+ public void testManyToMany(SessionFactoryScope scope) {
+ Application application = new Application();
+ persist( application, scope );
+ Customer customer = new Customer();
+ customer.applications.add( application );
+ application.customers.add( customer );
+ persist( customer, scope );
+
+ //init cache
+ assertFalse( isCached( customer.id, Customer.class, "applications", scope ) );
+ assertFalse( isCached( application.id, Application.class, "customers", scope ) );
+
+ customer = find( Customer.class, customer.id, scope );
+ assertThat( customer.applications.size(), is( 1 ) );
+ application = find( Application.class, application.id, scope );
+ assertThat( application.customers.size(), is( 1 ) );
+
+ assertTrue( isCached( customer.id, Customer.class, "applications", scope ) );
+ assertTrue( isCached( application.id, Application.class, "customers", scope ) );
+
+ //read from cache
+ customer = find( Customer.class, customer.id, scope );
+ assertThat( customer.applications.size(), is( 1 ) );
+ application = find( Application.class, application.id, scope );
+ assertThat( application.customers.size(), is( 1 ) );
+ }
+
+ private void persist(Object entity, SessionFactoryScope scope) {
+ scope.inTransaction(
+ session ->
+ session.persist( entity )
+ );
+ }
+
+ private E find(Class entityClass, int id, SessionFactoryScope scope) {
+ return scope.fromSession(
+ session ->
+ session.get( entityClass, id )
+ );
+ }
+
+ private boolean isCached(Serializable id, Class> entityClass, String attr, SessionFactoryScope scope) {
+ Object value = scope.fromSession(
+ session -> {
+ final SessionFactoryImplementor sessionFactory = scope.getSessionFactory();
+ CollectionPersister persister = sessionFactory.getCollectionPersister( entityClass.getName() + "." + attr );
+ CollectionDataAccess cache = persister.getCacheAccessStrategy();
+ Object key = cache.generateCacheKey( id, persister, sessionFactory, session.getTenantIdentifier() );
+ Object cachedValue = cache.get( session, key );
+ return cachedValue;
+ }
+ );
+
+ return value != null;
+ }
+
+
+ @Entity(name = "Application")
+ @Table(name = "application")
+ @Cacheable
+ public static class Application {
+ @Id
+ @GeneratedValue
+ private Integer id;
+
+ private String name;
+
+ @ManyToMany(mappedBy = "applications")
+ @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
+ private List customers = new ArrayList<>();
+ }
+
+ @Entity(name = "Customer")
+ @Table(name = "customer")
+ @Cacheable
+ @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
+ public static class Customer {
+ @Id
+ @GeneratedValue
+ private Integer id;
+
+ private String name;
+
+ @ManyToMany
+ @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
+ private List applications = new ArrayList<>();
+
+ @OneToMany(mappedBy = "customer", cascade = CascadeType.ALL)
+ @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
+ private List boughtItems = new ArrayList<>();
+ }
+
+ @Entity(name = "Item")
+ @Table(name = "item")
+ @Cacheable
+ @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
+ public static class Item {
+ @Id
+ @GeneratedValue
+ private Integer id;
+ @ManyToOne
+ @JoinColumn(name = "customer_id")
+ private Customer customer;
+
+ private String name;
+
+ protected Item() {
+ }
+
+ public Item(Customer customer) {
+ this.customer = customer;
+ }
+ }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/ops/AbstractOperationTestCase.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/AbstractOperationTestCase.java
new file mode 100644
index 0000000000..b287460546
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/AbstractOperationTestCase.java
@@ -0,0 +1,65 @@
+/*
+ * 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.orm.test.ops;
+
+import org.hibernate.cfg.Environment;
+import org.hibernate.stat.spi.StatisticsImplementor;
+
+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.hibernate.testing.orm.junit.Setting;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+/**
+ * @author Steve Ebersole
+ */
+@SessionFactory(generateStatistics = true)
+@DomainModel(
+ xmlMappings = {
+ "org/hibernate/orm/test/ops/Node.hbm.xml",
+ "org/hibernate/orm/test/ops/Employer.hbm.xml",
+ "org/hibernate/orm/test/ops/OptLockEntity.hbm.xml",
+ "org/hibernate/orm/test/ops/OneToOne.hbm.xml",
+ "org/hibernate/orm/test/ops/Competition.hbm.xml"
+ }
+)
+@ServiceRegistry(
+ settings = @Setting(name = Environment.STATEMENT_BATCH_SIZE, value = "0")
+)
+public abstract class AbstractOperationTestCase {
+
+ public String getCacheConcurrencyStrategy() {
+ return null;
+ }
+
+ protected void clearCounts(SessionFactoryScope scope) {
+ getStatistics( scope ).clear();
+ }
+
+ protected void assertInsertCount(int expected, SessionFactoryScope scope) {
+ int inserts = (int) getStatistics( scope ).getEntityInsertCount();
+ assertThat( "unexpected insert count", inserts, is( expected ) );
+ }
+
+ protected void assertUpdateCount(int expected, SessionFactoryScope scope) {
+ int updates = (int) getStatistics( scope ).getEntityUpdateCount();
+ assertThat( "unexpected update counts", updates, is( expected ) );
+ }
+
+ protected void assertDeleteCount(int expected, SessionFactoryScope scope) {
+ int deletes = (int) getStatistics( scope ).getEntityDeleteCount();
+ assertThat( "unexpected delete counts", deletes, is( expected ) );
+ }
+
+ private StatisticsImplementor getStatistics(SessionFactoryScope scope) {
+ return scope.getSessionFactory().getStatistics();
+ }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/Address.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/Address.java
similarity index 97%
rename from hibernate-core/src/test/java/org/hibernate/test/ops/Address.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ops/Address.java
index f25da937ac..24827c15e8 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ops/Address.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/Address.java
@@ -4,7 +4,7 @@
* 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.ops;
+package org.hibernate.orm.test.ops;
/**
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/Category.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/Category.java
similarity index 97%
rename from hibernate-core/src/test/java/org/hibernate/test/ops/Category.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ops/Category.java
index 765ca24c32..b814474d0c 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ops/Category.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/Category.java
@@ -4,7 +4,7 @@
* 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.ops;
+package org.hibernate.orm.test.ops;
import java.util.HashSet;
import java.util.Set;
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/Competition.hbm.xml b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/Competition.hbm.xml
similarity index 93%
rename from hibernate-core/src/test/java/org/hibernate/test/ops/Competition.hbm.xml
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ops/Competition.hbm.xml
index b8dff6914e..971e8623bc 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ops/Competition.hbm.xml
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/Competition.hbm.xml
@@ -13,7 +13,7 @@
-->
-
+
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/Competition.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/Competition.java
similarity index 94%
rename from hibernate-core/src/test/java/org/hibernate/test/ops/Competition.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ops/Competition.java
index e3a138cd7b..67337ba51b 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ops/Competition.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/Competition.java
@@ -6,7 +6,7 @@
*/
//$Id: $
-package org.hibernate.test.ops;
+package org.hibernate.orm.test.ops;
import java.util.ArrayList;
import java.util.List;
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/Competitor.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/Competitor.java
similarity index 94%
rename from hibernate-core/src/test/java/org/hibernate/test/ops/Competitor.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ops/Competitor.java
index 3d44e6290b..343ff08173 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ops/Competitor.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/Competitor.java
@@ -6,7 +6,7 @@
*/
//$Id: $
-package org.hibernate.test.ops;
+package org.hibernate.orm.test.ops;
/**
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/ops/CreateTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/CreateTest.java
new file mode 100755
index 0000000000..13aa71af62
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/CreateTest.java
@@ -0,0 +1,244 @@
+/*
+ * 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.orm.test.ops;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import javax.persistence.PersistenceException;
+
+import org.hibernate.PersistentObjectException;
+import org.hibernate.dialect.AbstractHANADialect;
+import org.hibernate.exception.ConstraintViolationException;
+
+import org.hibernate.testing.orm.junit.DialectFeatureChecks;
+import org.hibernate.testing.orm.junit.RequiresDialectFeature;
+import org.hibernate.testing.orm.junit.SessionFactoryScope;
+import org.hibernate.testing.orm.junit.SkipForDialect;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hibernate.testing.orm.junit.ExtraAssertions.assertTyping;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.fail;
+
+/**
+ * @author Gavin King
+ */
+@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsNoColumnInsert.class)
+public class CreateTest extends AbstractOperationTestCase {
+
+ @Test
+ @SuppressWarnings({ "unchecked" })
+ public void testNoUpdatesOnCreateVersionedWithCollection(SessionFactoryScope scope) {
+ clearCounts( scope );
+
+ VersionedEntity root = new VersionedEntity( "root", "root" );
+ scope.inTransaction(
+ session -> {
+ VersionedEntity child = new VersionedEntity( "c1", "child-1" );
+ root.getChildren().add( child );
+ child.setParent( root );
+ session.save( root );
+ }
+ );
+
+ assertInsertCount( 2, scope );
+ assertUpdateCount( 0, scope );
+ assertDeleteCount( 0, scope );
+
+ scope.inTransaction(
+ session ->
+ session.delete( root )
+ );
+
+ assertUpdateCount( 0, scope );
+ assertDeleteCount( 2, scope );
+ }
+
+ @Test
+ public void testCreateTree(SessionFactoryScope scope) {
+ clearCounts( scope );
+
+ scope.inTransaction(
+ session -> {
+ Node root = new Node( "root" );
+ Node child = new Node( "child" );
+ root.addChild( child );
+ session.persist( root );
+ }
+ );
+
+ assertInsertCount( 2, scope );
+ assertUpdateCount( 0, scope );
+
+ scope.inTransaction(
+ session -> {
+ Node root = session.get( Node.class, "root" );
+ Node child2 = new Node( "child2" );
+ root.addChild( child2 );
+ }
+ );
+
+ assertInsertCount( 3, scope );
+ assertUpdateCount( 0, scope );
+ }
+
+ @Test
+ public void testCreateTreeWithGeneratedId(SessionFactoryScope scope) {
+ clearCounts( scope );
+
+ NumberedNode root = new NumberedNode( "root" );
+ scope.inTransaction(
+ session -> {
+ NumberedNode child = new NumberedNode( "child" );
+ root.addChild( child );
+ session.persist( root );
+ }
+ );
+
+ assertInsertCount( 2, scope );
+ assertUpdateCount( 0, scope );
+
+ scope.inTransaction(
+ session -> {
+ NumberedNode r = session.get( NumberedNode.class, root.getId() );
+ NumberedNode child2 = new NumberedNode( "child2" );
+ r.addChild( child2 );
+ }
+ );
+
+ assertInsertCount( 3, scope );
+ assertUpdateCount( 0, scope );
+ }
+
+ @Test
+ public void testCreateException(SessionFactoryScope scope) {
+ Node dupe = new Node( "dupe" );
+ scope.inTransaction(
+ session -> {
+ session.persist( dupe );
+ session.persist( dupe );
+ }
+ );
+
+ scope.inSession(
+ session -> {
+ try {
+ session.beginTransaction();
+ session.persist( dupe );
+ session.getTransaction().commit();
+ fail( "Expecting constraint failure" );
+ }
+ catch (PersistenceException e) {
+
+ //verify that an exception is thrown!
+ assertTyping( ConstraintViolationException.class, e.getCause() );
+ }
+ finally {
+ if(session.getTransaction().isActive()){
+ session.getTransaction().rollback();
+ }
+ }
+ }
+ );
+
+ Node nondupe = new Node( "nondupe" );
+ nondupe.addChild( dupe );
+
+ scope.inSession(
+ session -> {
+ try {
+ session.beginTransaction();
+ session.persist( nondupe );
+ session.getTransaction().commit();
+ fail( "Expecting constraint failure" );
+ }
+ catch (PersistenceException e) {
+ //verify that an exception is thrown!
+ assertTyping( ConstraintViolationException.class, e.getCause() );
+ }
+ finally {
+ if(session.getTransaction().isActive()){
+ session.getTransaction().rollback();
+ }
+ }
+ }
+ );
+ }
+
+ @Test
+ public void testCreateExceptionWithGeneratedId(SessionFactoryScope scope) {
+ NumberedNode dupe = new NumberedNode( "dupe" );
+ scope.inTransaction(
+ session -> {
+ session.persist( dupe );
+ session.persist( dupe );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ try {
+ session.persist( dupe );
+ fail( "Expecting failure" );
+ }
+ catch (PersistenceException e) {
+ //verify that an exception is thrown!
+ assertTyping( PersistentObjectException.class, e.getCause() );
+ }
+ }
+ );
+
+ NumberedNode nondupe = new NumberedNode( "nondupe" );
+ nondupe.addChild( dupe );
+
+ scope.inTransaction(
+ session -> {
+ try {
+ session.persist( nondupe );
+ fail( "Expecting failure" );
+ }
+ catch (PersistenceException e) {
+ //verify that an exception is thrown!
+ assertTyping( PersistentObjectException.class, e.getCause() );
+ }
+ }
+ );
+ }
+
+ @Test
+ @SuppressWarnings({ "unchecked" })
+ @SkipForDialect(dialectClass = AbstractHANADialect.class, reason = " HANA doesn't support tables consisting of only a single auto-generated column")
+ public void testBasic(SessionFactoryScope scope) throws Exception {
+ Employer er = new Employer();
+ Employee ee = new Employee();
+ scope.inTransaction(
+ session -> {
+ session.persist( ee );
+ Collection erColl = new ArrayList();
+ Collection eeColl = new ArrayList();
+ erColl.add( ee );
+ eeColl.add( er );
+ er.setEmployees( erColl );
+ ee.setEmployers( eeColl );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Employer er1 = session.load( Employer.class, er.getId() );
+ assertNotNull( er1 );
+ assertNotNull( er1.getEmployees() );
+ assertThat( er1.getEmployees().size(), is( 1 ) );
+ Employee eeFromDb = (Employee) er1.getEmployees().iterator().next();
+ assertThat( eeFromDb.getId(), is( ee.getId() ) );
+ }
+ );
+ }
+}
+
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/ops/CustomEntityCopyObserver.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/CustomEntityCopyObserver.java
new file mode 100644
index 0000000000..823378d445
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/CustomEntityCopyObserver.java
@@ -0,0 +1,28 @@
+package org.hibernate.orm.test.ops;
+
+import org.hibernate.event.spi.EntityCopyObserver;
+import org.hibernate.event.spi.EventSource;
+
+public class CustomEntityCopyObserver implements EntityCopyObserver {
+
+ @Override
+ public void entityCopyDetected(
+ Object managedEntity,
+ Object mergeEntity1,
+ Object mergeEntity2,
+ EventSource session) {
+ if ( Category.class.isInstance( managedEntity ) ) {
+ throw new IllegalStateException(
+ String.format( "Entity copies of type [%s] not allowed", Category.class.getName() )
+ );
+ }
+ }
+
+ @Override
+ public void topLevelMergeComplete(EventSource session) {
+ }
+
+ @Override
+ public void clear() {
+ }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/ops/DeleteTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/DeleteTest.java
new file mode 100644
index 0000000000..29d55097f4
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/DeleteTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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.orm.test.ops;
+
+
+import org.hibernate.testing.orm.junit.DialectFeatureChecks;
+import org.hibernate.testing.orm.junit.RequiresDialectFeature;
+import org.hibernate.testing.orm.junit.SessionFactoryScope;
+import org.junit.jupiter.api.Test;
+
+/**
+ * @author Steve Ebersole
+ */
+@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsNoColumnInsert.class)
+public class DeleteTest extends AbstractOperationTestCase {
+
+ @Test
+ @SuppressWarnings({ "unchecked" })
+ public void testDeleteVersionedWithCollectionNoUpdate(SessionFactoryScope scope) {
+ // test adapted from HHH-1564...
+ scope.inTransaction(
+ session -> {
+ VersionedEntity c = new VersionedEntity( "c1", "child-1" );
+ VersionedEntity p = new VersionedEntity( "root", "root" );
+ p.getChildren().add( c );
+ c.setParent( p );
+ session.save( p );
+ }
+ );
+
+ clearCounts( scope );
+
+ scope.inTransaction(
+ session -> {
+ VersionedEntity loadedParent = session.get( VersionedEntity.class, "root" );
+ session.delete( loadedParent );
+ }
+ );
+
+ assertInsertCount( 0, scope );
+ assertUpdateCount( 0, scope );
+ assertDeleteCount( 2, scope );
+ }
+
+ @Test
+ public void testNoUpdateOnDelete(SessionFactoryScope scope) {
+ Node node = new Node( "test" );
+ scope.inTransaction(
+ session ->
+ session.persist( node )
+ );
+
+ clearCounts( scope );
+
+ scope.inTransaction(
+ session ->
+ session.delete( node )
+ );
+
+ assertUpdateCount( 0, scope );
+ assertInsertCount( 0, scope );
+ }
+
+ @Test
+ @SuppressWarnings({ "unchecked" })
+ public void testNoUpdateOnDeleteWithCollection(SessionFactoryScope scope) {
+ scope.inTransaction(
+ session -> {
+ Node parent = new Node( "parent" );
+ Node child = new Node( "child" );
+ parent.getCascadingChildren().add( child );
+ session.persist( parent );
+ }
+ );
+
+
+ clearCounts( scope );
+
+ scope.inTransaction(
+ session -> {
+ Node parent = session.get( Node.class, "parent" );
+ session.delete( parent );
+ }
+ );
+
+ assertUpdateCount( 0, scope );
+ assertInsertCount( 0, scope );
+ assertDeleteCount( 2, scope );
+ }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/Employee.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/Employee.java
similarity index 95%
rename from hibernate-core/src/test/java/org/hibernate/test/ops/Employee.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ops/Employee.java
index 6d020672d9..b2d53982bf 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ops/Employee.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/Employee.java
@@ -6,7 +6,7 @@
*/
//$Id: Employee.java 5686 2005-02-12 07:27:32Z steveebersole $
-package org.hibernate.test.ops;
+package org.hibernate.orm.test.ops;
import java.io.Serializable;
import java.util.Collection;
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/Employer.hbm.xml b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/Employer.hbm.xml
similarity index 95%
rename from hibernate-core/src/test/java/org/hibernate/test/ops/Employer.hbm.xml
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ops/Employer.hbm.xml
index 64d600065b..3e196ef16a 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ops/Employer.hbm.xml
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/Employer.hbm.xml
@@ -13,7 +13,7 @@
-->
-
+
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/Employer.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/Employer.java
similarity index 96%
rename from hibernate-core/src/test/java/org/hibernate/test/ops/Employer.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ops/Employer.java
index d7226ab56b..b21cc73b8c 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ops/Employer.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/Employer.java
@@ -6,7 +6,7 @@
*/
//$Id: Employer.java 8670 2005-11-25 17:36:29Z epbernard $
-package org.hibernate.test.ops;
+package org.hibernate.orm.test.ops;
import java.io.Serializable;
import java.util.Collection;
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/ops/GetLoadTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/GetLoadTest.java
new file mode 100644
index 0000000000..e1b9a19542
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/GetLoadTest.java
@@ -0,0 +1,141 @@
+/*
+ * 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.orm.test.ops;
+
+import org.hibernate.Hibernate;
+import org.hibernate.cfg.Environment;
+
+import org.hibernate.testing.orm.junit.DialectFeatureChecks;
+import org.hibernate.testing.orm.junit.DomainModel;
+import org.hibernate.testing.orm.junit.RequiresDialectFeature;
+import org.hibernate.testing.orm.junit.ServiceRegistry;
+import org.hibernate.testing.orm.junit.SessionFactory;
+import org.hibernate.testing.orm.junit.SessionFactoryScope;
+import org.hibernate.testing.orm.junit.Setting;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+
+/**
+ * @author Gavin King
+ */
+@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsNoColumnInsert.class)
+@DomainModel(
+ xmlMappings = {
+ "org/hibernate/orm/test/ops/Node.hbm.xml",
+ "org/hibernate/orm/test/ops/Employer.hbm.xml"
+ }
+)
+@SessionFactory(
+ generateStatistics = true
+)
+@ServiceRegistry(
+ settings = {
+ @Setting(name = Environment.STATEMENT_BATCH_SIZE, value = "0")
+ }
+)
+public class GetLoadTest {
+
+ @Test
+ public void testGetLoad(SessionFactoryScope scope) {
+ clearCounts( scope );
+
+ Employer emp = new Employer();
+ Node node = new Node( "foo" );
+ Node parent = new Node( "bar" );
+ scope.inTransaction(
+ session -> {
+ session.persist( emp );
+ parent.addChild( node );
+ session.persist( parent );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Employer e = session.get( Employer.class, emp.getId() );
+ assertTrue( Hibernate.isInitialized( e ) );
+ assertFalse( Hibernate.isInitialized( e.getEmployees() ) );
+ Node n = session.get( Node.class, node.getName() );
+ assertTrue( Hibernate.isInitialized( n ) );
+ assertFalse( Hibernate.isInitialized( n.getChildren() ) );
+ assertFalse( Hibernate.isInitialized( n.getParent() ) );
+ assertNull( session.get( Node.class, "xyz" ) );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Employer e = session.load( Employer.class, emp.getId() );
+ e.getId();
+ assertFalse( Hibernate.isInitialized( e ) );
+ Node n = session.load( Node.class, node.getName() );
+ assertThat( n.getName(), is( "foo" ) );
+ assertFalse( Hibernate.isInitialized( n ) );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Employer e = (Employer) session.get( "org.hibernate.orm.test.ops.Employer", emp.getId() );
+ assertTrue( Hibernate.isInitialized( e ) );
+ Node n = (Node) session.get( "org.hibernate.orm.test.ops.Node", node.getName() );
+ assertTrue( Hibernate.isInitialized( n ) );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Employer e = (Employer) session.load( "org.hibernate.orm.test.ops.Employer", emp.getId() );
+ e.getId();
+ assertFalse( Hibernate.isInitialized( e ) );
+ Node n = (Node) session.load( "org.hibernate.orm.test.ops.Node", node.getName() );
+ assertThat( n.getName(), is( "foo" ) );
+ assertFalse( Hibernate.isInitialized( n ) );
+ }
+ );
+
+ assertFetchCount( 0, scope );
+ }
+
+ @Test
+ public void testGetAfterDelete(SessionFactoryScope scope) {
+ clearCounts( scope );
+
+ Employer emp = new Employer();
+
+ scope.inTransaction(
+ session ->
+ session.persist( emp )
+ );
+
+ Employer e = scope.fromTransaction(
+ session -> {
+ session.delete( emp );
+ return session.get( Employer.class, emp.getId() );
+ }
+ );
+
+ assertNull( e, "get did not return null after delete" );
+ }
+
+ private void clearCounts(SessionFactoryScope scope) {
+ scope.getSessionFactory().getStatistics().clear();
+ }
+
+ private void assertFetchCount(int count, SessionFactoryScope scope) {
+ int fetches = (int) scope.getSessionFactory().getStatistics().getEntityFetchCount();
+ assertThat( fetches, is( count ) );
+ }
+
+}
+
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/ops/HANANoColumnInsertTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/HANANoColumnInsertTest.java
new file mode 100644
index 0000000000..43835026ed
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/HANANoColumnInsertTest.java
@@ -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 .
+ */
+package org.hibernate.orm.test.ops;
+
+import org.hibernate.MappingException;
+import org.hibernate.boot.spi.MetadataImplementor;
+import org.hibernate.dialect.AbstractHANADialect;
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+
+import org.hibernate.testing.orm.junit.BaseSessionFactoryFunctionalTest;
+import org.hibernate.testing.orm.junit.RequiresDialect;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.Is.is;
+import static org.junit.jupiter.api.Assertions.fail;
+
+
+/**
+ * @author Vlad Mihalcea
+ */
+@RequiresDialect(value = AbstractHANADialect.class)
+public class HANANoColumnInsertTest extends BaseSessionFactoryFunctionalTest {
+
+ @Override
+ protected String[] getOrmXmlFiles() {
+ return new String[] {
+ "org/hibernate/orm/test/ops/Competition.hbm.xml"
+ };
+ }
+
+ @Override
+ public SessionFactoryImplementor produceSessionFactory(MetadataImplementor model) {
+ SessionFactoryImplementor sessionFactoryImplementor = null;
+ try {
+ sessionFactoryImplementor = produceSessionFactory( model );
+
+ fail( "Should have thrown MappingException!" );
+ return sessionFactoryImplementor;
+ }
+ catch (MappingException e) {
+ assertThat(
+
+ e.getMessage(),
+ is( "The INSERT statement for table [Competition] contains no column, and this is not supported by [" + getDialect()
+ .getClass()
+ .getName() + "]" )
+ );
+ }
+ return sessionFactoryImplementor;
+ }
+
+ @Test
+ public void test() {
+ inTransaction(
+ session -> {
+ }
+ );
+ }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/Hoarder.hbm.xml b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/Hoarder.hbm.xml
similarity index 97%
rename from hibernate-core/src/test/java/org/hibernate/test/ops/Hoarder.hbm.xml
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ops/Hoarder.hbm.xml
index d18693998d..82ecb830b8 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ops/Hoarder.hbm.xml
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/Hoarder.hbm.xml
@@ -13,7 +13,7 @@
-->
-
+
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/Hoarder.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/Hoarder.java
similarity index 96%
rename from hibernate-core/src/test/java/org/hibernate/test/ops/Hoarder.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ops/Hoarder.java
index ae01aa7a7e..182ce97b77 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ops/Hoarder.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/Hoarder.java
@@ -4,7 +4,7 @@
* 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.ops;
+package org.hibernate.orm.test.ops;
import java.util.HashSet;
import java.util.Set;
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/HoarderOrphanDelete.hbm.xml b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/HoarderOrphanDelete.hbm.xml
similarity index 97%
rename from hibernate-core/src/test/java/org/hibernate/test/ops/HoarderOrphanDelete.hbm.xml
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ops/HoarderOrphanDelete.hbm.xml
index f490251bbb..3f92bce677 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ops/HoarderOrphanDelete.hbm.xml
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/HoarderOrphanDelete.hbm.xml
@@ -13,7 +13,7 @@
-->
-
+
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/Item.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/Item.java
similarity index 98%
rename from hibernate-core/src/test/java/org/hibernate/test/ops/Item.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ops/Item.java
index 37c44a1820..632d4e18b2 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ops/Item.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/Item.java
@@ -4,7 +4,7 @@
* 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.ops;
+package org.hibernate.orm.test.ops;
import java.util.ArrayList;
import java.util.HashSet;
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/MergeManagedAndCopiesAllowedTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/MergeManagedAndCopiesAllowedTest.java
similarity index 56%
rename from hibernate-core/src/test/java/org/hibernate/test/ops/MergeManagedAndCopiesAllowedTest.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ops/MergeManagedAndCopiesAllowedTest.java
index 1f6ceb5926..ecb5bd2bb5 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ops/MergeManagedAndCopiesAllowedTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/MergeManagedAndCopiesAllowedTest.java
@@ -4,7 +4,7 @@
* 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.ops;
+package org.hibernate.orm.test.ops;
import java.util.HashSet;
import java.util.Set;
@@ -17,76 +17,74 @@ import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
-import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.AvailableSettings;
-import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
-import org.junit.Test;
+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.hibernate.testing.orm.junit.Setting;
+import org.junit.jupiter.api.Test;
-import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertSame;
+import static junit.framework.TestCase.assertSame;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
/**
* A 1 ------------> 1 B 1 ----------> 1 C
- * 1 1
- * | |
- * | |
- * V V
- * 1 N
- * D 1------------>N E
- *
+ * 1 1
+ * | |
+ * | |
+ * V V
+ * 1 N
+ * D 1------------>N E
*
* @author Gail Badner
*/
-public class MergeManagedAndCopiesAllowedTest extends BaseCoreFunctionalTestCase {
-
- protected Class[] getAnnotatedClasses() {
- return new Class[]{
- A.class,
- B.class,
- C.class,
- D.class,
- E.class
- };
- }
-
- protected void configure(Configuration cfg) {
- super.configure( cfg );
- cfg.setProperty( "hibernate.event.merge.entity_copy_observer", "allow" );
- }
+@DomainModel(
+ annotatedClasses = {
+ MergeManagedAndCopiesAllowedTest.A.class,
+ MergeManagedAndCopiesAllowedTest.B.class,
+ MergeManagedAndCopiesAllowedTest.C.class,
+ MergeManagedAndCopiesAllowedTest.D.class,
+ MergeManagedAndCopiesAllowedTest.E.class
+ }
+)
+@SessionFactory
+@ServiceRegistry(settings = @Setting(name = AvailableSettings.MERGE_ENTITY_COPY_OBSERVER, value = "allow"))
+public class MergeManagedAndCopiesAllowedTest {
@Test
- public void testIt() {
+ public void testIt(SessionFactoryScope scope) {
A a = new A();
a.b = new B();
a.b.d = new D();
a.b.d.dEs.add( new E() );
- doInHibernate(
- this::sessionFactory, session -> {
- session.persist( a );
- }
+ scope.inTransaction(
+ session ->
+ session.persist( a )
);
- doInHibernate(
- this::sessionFactory, session -> {
- A aGet= session.get( A.class, a.id );
+ scope.inTransaction(
+ session -> {
+ A aGet = session.get( A.class, a.id );
aGet.b.c = new C();
Set copies = new HashSet<>();
for ( E e : aGet.b.d.dEs ) {
- copies.add ( new E( e.id, "description" ) );
+ copies.add( new E( e.id, "description" ) );
}
aGet.b.c.cEs.addAll( copies );
session.merge( aGet );
}
);
- doInHibernate(
- this::sessionFactory, session -> {
- A aGet= session.get( A.class, a.id );
+ scope.inTransaction(
+ session -> {
+ A aGet = session.get( A.class, a.id );
E e = aGet.b.c.cEs.iterator().next();
assertSame( e, aGet.b.d.dEs.iterator().next() );
- assertEquals( "description", e.description );
+ assertThat( e.description, is( "description" ) );
}
);
}
@@ -97,7 +95,7 @@ public class MergeManagedAndCopiesAllowedTest extends BaseCoreFunctionalTestCase
@GeneratedValue
private int id;
- @OneToOne(fetch=FetchType.EAGER, cascade = CascadeType.ALL)
+ @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private B b;
}
@@ -145,7 +143,8 @@ public class MergeManagedAndCopiesAllowedTest extends BaseCoreFunctionalTestCase
private String description;
- E() {}
+ E() {
+ }
E(int id, String description) {
this.id = id;
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/MergeMultipleEntityCopiesAllowedLoggedTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/MergeMultipleEntityCopiesAllowedLoggedTest.java
similarity index 62%
rename from hibernate-core/src/test/java/org/hibernate/test/ops/MergeMultipleEntityCopiesAllowedLoggedTest.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ops/MergeMultipleEntityCopiesAllowedLoggedTest.java
index e9fe60434b..59ea76b215 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ops/MergeMultipleEntityCopiesAllowedLoggedTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/MergeMultipleEntityCopiesAllowedLoggedTest.java
@@ -4,21 +4,20 @@
* 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.ops;
+package org.hibernate.orm.test.ops;
-import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.AvailableSettings;
+
+import org.hibernate.testing.orm.junit.ServiceRegistry;
+import org.hibernate.testing.orm.junit.Setting;
/**
* Tests merging multiple detached representations of the same entity when explicitly allowed and logged.
*
* @author Gail Badner
*/
+@ServiceRegistry(
+ settings = @Setting(name = AvailableSettings.MERGE_ENTITY_COPY_OBSERVER, value = "log")
+)
public class MergeMultipleEntityCopiesAllowedLoggedTest extends MergeMultipleEntityCopiesAllowedTest {
- public void configure(Configuration cfg) {
- super.configure( cfg );
- cfg.setProperty(
- "hibernate.event.merge.entity_copy_observer",
- "log"
- );
- }
}
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/ops/MergeMultipleEntityCopiesAllowedOrphanDeleteTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/MergeMultipleEntityCopiesAllowedOrphanDeleteTest.java
new file mode 100644
index 0000000000..26df800164
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/MergeMultipleEntityCopiesAllowedOrphanDeleteTest.java
@@ -0,0 +1,495 @@
+/*
+ * 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.orm.test.ops;
+
+import java.util.List;
+
+import org.hibernate.Hibernate;
+import org.hibernate.cfg.AvailableSettings;
+
+import org.hibernate.testing.orm.junit.DomainModel;
+import org.hibernate.testing.orm.junit.FailureExpected;
+import org.hibernate.testing.orm.junit.ServiceRegistry;
+import org.hibernate.testing.orm.junit.SessionFactory;
+import org.hibernate.testing.orm.junit.SessionFactoryScope;
+import org.hibernate.testing.orm.junit.Setting;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Tests merging multiple detached representations of the same entity (allowed)
+ * where some associations include cascade="delete-orphan"
+ *
+ * @author Gail Badner
+ */
+@DomainModel(
+ xmlMappings = "org/hibernate/orm/test/ops/HoarderOrphanDelete.hbm.xml"
+)
+@SessionFactory
+@ServiceRegistry(
+ settings = @Setting(name = AvailableSettings.MERGE_ENTITY_COPY_OBSERVER, value = "allow")
+)
+public class MergeMultipleEntityCopiesAllowedOrphanDeleteTest {
+
+ @Test
+ @FailureExpected(jiraKey = "HHH-9240")
+ public void testTopLevelUnidirOneToManyBackrefWithNewElement(SessionFactoryScope scope) {
+ Item item1 = new Item();
+ item1.setName( "item1 name" );
+ SubItem subItem1 = new SubItem();
+ subItem1.setName( "subItem1 name" );
+ item1.getSubItemsBackref().add( subItem1 );
+
+ scope.inTransaction(
+ session ->
+ session.persist( item1 )
+ );
+
+ // get another representation of item1
+ Item item1_1 = scope.fromTransaction(
+ session ->
+ session.get( Item.class, item1.getId() )
+
+ );
+
+ assertFalse( Hibernate.isInitialized( item1_1.getSubItemsBackref() ) );
+
+ Category category = new Category();
+ category.setName( "category" );
+
+ SubItem subItem2 = new SubItem();
+ subItem2.setName( "subItem2 name" );
+ item1.getSubItemsBackref().add( subItem2 );
+
+ item1.setCategory( category );
+ category.setExampleItem( item1_1 );
+
+ scope.inTransaction(
+ session -> {
+ // The following will fail due to PropertyValueException because item1 will
+ // be removed from the inverted merge map when the operation cascades to item1_1.
+ Item item1Merged = (Item) session.merge( item1 );
+ // top-level collection should win
+ assertThat( item1Merged.getSubItemsBackref().size(), is( 2 ) );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Item item = session.get( Item.class, item1.getId() );
+ assertThat( item.getSubItemsBackref().size(), is( 2 ) );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @Test
+ @FailureExpected(jiraKey = "HHH-9239")
+ public void testNestedUnidirOneToManyBackrefWithNewElement(SessionFactoryScope scope) {
+ Item item1 = new Item();
+ item1.setName( "item1 name" );
+ SubItem subItem1 = new SubItem();
+ subItem1.setName( "subItem1 name" );
+ item1.getSubItemsBackref().add( subItem1 );
+
+ scope.inTransaction(
+ session ->
+ session.persist( item1 )
+ );
+
+ // get another representation of item1
+ Item item1_1 = scope.fromTransaction(
+ session -> {
+ Item item = session.get( Item.class, item1.getId() );
+ Hibernate.initialize( item.getSubItemsBackref() );
+ return item;
+ }
+ );
+
+ Category category = new Category();
+ category.setName( "category" );
+ item1.setCategory( category );
+
+ // Add a new SubItem to the Item representation that will be in a nested association.
+ SubItem subItem2 = new SubItem();
+ subItem2.setName( "subItem2 name" );
+ item1_1.getSubItemsBackref().add( subItem2 );
+
+ category.setExampleItem( item1_1 );
+
+ scope.inTransaction(
+ session -> {
+ Item item1Merged = (Item) session.merge( item1 );
+ // The resulting collection should contain the added element
+ assertThat( item1Merged.getSubItemsBackref().size(), is( 2 ) );
+ assertThat( item1Merged.getSubItemsBackref().get( 0 ).getName(), is( "subItem1 name" ) );
+ assertThat( item1Merged.getSubItemsBackref().get( 1 ).getName(), is( "subItem2 name" ) );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Item item = session.get( Item.class, item1.getId() );
+ assertThat( item.getSubItemsBackref().size(), is( 2 ) );
+ assertThat( item.getSubItemsBackref().get( 0 ).getName(), is( "subItem1 name" ) );
+ assertThat( item.getSubItemsBackref().get( 1 ).getName(), is( "subItem2 name" ) );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @Test
+ //@FailureExpected( jiraKey = "HHH-9106" )
+ public void testTopLevelUnidirOneToManyBackrefWithRemovedElement(SessionFactoryScope scope) {
+ Item item1 = new Item();
+ item1.setName( "item1 name" );
+ SubItem subItem1 = new SubItem();
+ subItem1.setName( "subItem1 name" );
+ item1.getSubItemsBackref().add( subItem1 );
+ SubItem subItem2 = new SubItem();
+ subItem2.setName( "subItem2 name" );
+ item1.getSubItemsBackref().add( subItem2 );
+
+ scope.inTransaction(
+ session ->
+ session.persist( item1 )
+ );
+
+ // get another representation of item1
+ Item item1_1 = scope.fromTransaction(
+ session ->
+ session.get( Item.class, item1.getId() )
+ );
+
+ assertFalse( Hibernate.isInitialized( item1_1.getSubItemsBackref() ) );
+
+ Category category = new Category();
+ category.setName( "category" );
+
+ item1.setCategory( category );
+ category.setExampleItem( item1_1 );
+
+ // remove subItem1 from top-level Item
+ item1.getSubItemsBackref().remove( subItem1 );
+
+ scope.inTransaction(
+ session -> {
+ Item item1Merged = (Item) session.merge( item1 );
+ // element should be removed
+ assertThat( item1Merged.getSubItemsBackref().size(), is( 1 ) );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Item item = session.get( Item.class, item1.getId() );
+ assertThat( item.getSubItemsBackref().size(), is( 1 ) );
+ // because cascade includes "delete-orphan" the removed SubItem should have been deleted.
+ SubItem subItem = session.get( SubItem.class, subItem1.getId() );
+ assertNull( subItem );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @Test
+ @FailureExpected(jiraKey = "HHH-9239")
+ public void testNestedUnidirOneToManyBackrefWithRemovedElement(SessionFactoryScope scope) {
+ Item item1 = new Item();
+ item1.setName( "item1 name" );
+ SubItem subItem1 = new SubItem();
+ subItem1.setName( "subItem1 name" );
+ item1.getSubItemsBackref().add( subItem1 );
+ SubItem subItem2 = new SubItem();
+ subItem2.setName( "subItem2 name" );
+ item1.getSubItemsBackref().add( subItem2 );
+
+ scope.inTransaction(
+ session ->
+ session.persist( item1 )
+ );
+
+ // get another representation of item1
+ Item item1_1 = scope.fromTransaction(
+ session -> {
+ Item item = session.get( Item.class, item1.getId() );
+ Hibernate.initialize( item.getSubItemsBackref() );
+ return item;
+ }
+ );
+
+ // remove subItem1 from the nested Item
+ item1_1.getSubItemsBackref().remove( subItem1 );
+
+ Category category = new Category();
+ category.setName( "category" );
+ item1.setCategory( category );
+ category.setExampleItem( item1_1 );
+
+ scope.inTransaction(
+ session -> {
+ Item item1Merged = (Item) session.merge( item1 );
+ // the element should have been removed
+ assertThat( item1Merged.getSubItemsBackref().size(), is( 1 ) );
+ assertTrue( item1Merged.getSubItemsBackref().contains( subItem2 ) );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Item item = session.get( Item.class, item1.getId() );
+ assertThat( item.getSubItemsBackref().size(), is( 1 ) );
+ assertTrue( item.getSubItemsBackref().contains( subItem2 ) );
+ // because cascade includes "delete-orphan" the removed SubItem should have been deleted.
+ SubItem subItem = session.get( SubItem.class, subItem1.getId() );
+ assertNull( subItem );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @Test
+ //@FailureExpected( jiraKey = "HHH-9106" )
+ public void testTopLevelUnidirOneToManyNoBackrefWithNewElement(SessionFactoryScope scope) {
+ Category category1 = new Category();
+ category1.setName( "category1 name" );
+ SubCategory subCategory1 = new SubCategory();
+ subCategory1.setName( "subCategory1 name" );
+ category1.getSubCategories().add( subCategory1 );
+
+ scope.inTransaction(
+ session ->
+ session.persist( category1 )
+ );
+
+ // get another representation of category1
+ Category category1_1 = scope.fromTransaction(
+ session ->
+ session.get( Category.class, category1.getId() )
+ );
+
+ assertFalse( Hibernate.isInitialized( category1_1.getSubCategories() ) );
+
+ SubCategory subCategory2 = new SubCategory();
+ subCategory2.setName( "subCategory2 name" );
+ category1.getSubCategories().add( subCategory2 );
+
+ Item item = new Item();
+ item.setName( "item" );
+ category1.setExampleItem( item );
+ item.setCategory( category1_1 );
+
+ scope.inTransaction(
+ session -> {
+ Category category1Merged = (Category) session.merge( category1 );
+ assertThat( category1Merged.getSubCategories().size(), is( 2 ) );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Category category = session.get( Category.class, category1.getId() );
+ assertThat( category.getSubCategories().size(), is( 2 ) );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @Test
+ @FailureExpected(jiraKey = "HHH-9239")
+ public void testNestedUnidirOneToManyNoBackrefWithNewElement(SessionFactoryScope scope) {
+ Category category1 = new Category();
+ category1.setName( "category1 name" );
+ SubCategory subCategory1 = new SubCategory();
+ subCategory1.setName( "subCategory1 name" );
+ category1.getSubCategories().add( subCategory1 );
+
+ scope.inTransaction(
+ session ->
+ session.persist( category1 )
+ );
+
+ // get another representation of category1
+ Category category1_1 = scope.fromTransaction(
+ session -> {
+ Category category = session.get( Category.class, category1.getId() );
+ Hibernate.initialize( category.getSubCategories() );
+ return category;
+ }
+ );
+
+ SubCategory subCategory2 = new SubCategory();
+ subCategory2.setName( "subCategory2 name" );
+ category1_1.getSubCategories().add( subCategory2 );
+
+ Item item = new Item();
+ item.setName( "item" );
+ category1.setExampleItem( item );
+ item.setCategory( category1_1 );
+
+ scope.inTransaction(
+ session -> {
+ Category category1Merged = (Category) session.merge( category1 );
+ // new element should be there
+ assertThat( category1Merged.getSubCategories().size(), is( 2 ) );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Category category = session.get( Category.class, category1.getId() );
+ assertThat( category.getSubCategories().size(), is( 2 ) );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @Test
+ //@FailureExpected( jiraKey = "HHH-9106" )
+ public void testTopLevelUnidirOneToManyNoBackrefWithRemovedElement(SessionFactoryScope scope) {
+ Category category1 = new Category();
+ category1.setName( "category1 name" );
+ SubCategory subCategory1 = new SubCategory();
+ subCategory1.setName( "subCategory1 name" );
+ category1.getSubCategories().add( subCategory1 );
+ SubCategory subCategory2 = new SubCategory();
+ subCategory2.setName( "subCategory2 name" );
+ category1.getSubCategories().add( subCategory2 );
+
+ scope.inTransaction(
+ session ->
+ session.persist( category1 )
+ );
+
+ // get another representation of category1
+ Category category1_1 = scope.fromTransaction(
+ session ->
+ session.get( Category.class, category1.getId() )
+ );
+
+ assertFalse( Hibernate.isInitialized( category1_1.getSubCategories() ) );
+
+ Item item = new Item();
+ item.setName( "item" );
+ category1.setExampleItem( item );
+ item.setCategory( category1_1 );
+
+ category1.getSubCategories().remove( subCategory1 );
+
+ scope.inTransaction(
+ session -> {
+ Category category1Merged = (Category) session.merge( category1 );
+ assertThat( category1Merged.getSubCategories().size(), is( 1 ) );
+ assertTrue( category1Merged.getSubCategories().contains( subCategory2 ) );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Category category = session.get( Category.class, category1.getId() );
+ assertThat( category.getSubCategories().size(), is( 1 ) );
+ assertTrue( category.getSubCategories().contains( subCategory2 ) );
+ SubCategory subCategory = session.get( SubCategory.class, subCategory1.getId() );
+ assertNull( subCategory );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @Test
+ @FailureExpected(jiraKey = "HHH-9239")
+ public void testNestedUnidirOneToManyNoBackrefWithRemovedElement(SessionFactoryScope scope) {
+ Category category1 = new Category();
+ category1.setName( "category1 name" );
+ SubCategory subCategory1 = new SubCategory();
+ subCategory1.setName( "subCategory1 name" );
+ category1.getSubCategories().add( subCategory1 );
+ SubCategory subCategory2 = new SubCategory();
+ subCategory2.setName( "subCategory2 name" );
+ category1.getSubCategories().add( subCategory2 );
+
+ scope.inTransaction(
+ session ->
+ session.persist( category1 )
+ );
+
+ // get another representation of category1
+ Category category1_1 = scope.fromTransaction(
+ session -> {
+ Category category = session.get( Category.class, category1.getId() );
+ Hibernate.initialize( category.getSubCategories() );
+ return category;
+ }
+ );
+
+ category1_1.getSubCategories().remove( subCategory2 );
+
+ Item item = new Item();
+ item.setName( "item" );
+ category1.setExampleItem( item );
+ item.setCategory( category1_1 );
+
+ scope.inTransaction(
+ session -> {
+ Category category1Merged = (Category) session.merge( category1 );
+ assertThat( category1Merged.getSubCategories().size(), is( 1 ) );
+ assertTrue( category1Merged.getSubCategories().contains( subCategory2 ) );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Category category = session.get( Category.class, category1.getId() );
+ assertThat( category.getSubCategories().size(), is( 1 ) );
+ assertTrue( category1.getSubCategories().contains( subCategory2 ) );
+ SubCategory subCategory = session.get( SubCategory.class, subCategory1.getId() );
+ assertNull( subCategory );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @SuppressWarnings({ "unchecked" })
+ private void cleanup(SessionFactoryScope scope) {
+ scope.inTransaction(
+ session -> {
+ session.createQuery( "delete from SubItem" ).executeUpdate();
+ for ( Hoarder hoarder : (List) session.createQuery( "from Hoarder" ).list() ) {
+ hoarder.getItems().clear();
+ session.delete( hoarder );
+ }
+
+ for ( Category category : (List) session.createQuery( "from Category" ).list() ) {
+ if ( category.getExampleItem() != null ) {
+ category.setExampleItem( null );
+ session.delete( category );
+ }
+ }
+
+ for ( Item item : (List) session.createQuery( "from Item" ).list() ) {
+ item.setCategory( null );
+ session.delete( item );
+ }
+
+ session.createQuery( "delete from Item" ).executeUpdate();
+ }
+ );
+ }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/ops/MergeMultipleEntityCopiesAllowedTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/MergeMultipleEntityCopiesAllowedTest.java
new file mode 100644
index 0000000000..b0304498b0
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/MergeMultipleEntityCopiesAllowedTest.java
@@ -0,0 +1,1198 @@
+/*
+ * 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.orm.test.ops;
+
+import java.util.List;
+import javax.persistence.PersistenceException;
+
+import org.hibernate.Hibernate;
+import org.hibernate.StaleObjectStateException;
+import org.hibernate.cfg.AvailableSettings;
+
+import org.hibernate.testing.orm.junit.DomainModel;
+import org.hibernate.testing.orm.junit.FailureExpected;
+import org.hibernate.testing.orm.junit.ServiceRegistry;
+import org.hibernate.testing.orm.junit.SessionFactory;
+import org.hibernate.testing.orm.junit.SessionFactoryScope;
+import org.hibernate.testing.orm.junit.Setting;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hibernate.testing.orm.junit.ExtraAssertions.assertTyping;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+
+/**
+ * Tests merging multiple detached representations of the same entity when explicitly allowed.
+ *
+ * @author Gail Badner
+ */
+@DomainModel(
+ xmlMappings = "org/hibernate/orm/test/ops/Hoarder.hbm.xml"
+)
+@SessionFactory
+@ServiceRegistry(settings = @Setting(name = AvailableSettings.MERGE_ENTITY_COPY_OBSERVER, value = "allow"))
+public class MergeMultipleEntityCopiesAllowedTest {
+
+ @Test
+ public void testNestedDiffBasicProperty(SessionFactoryScope scope) {
+ Item item1 = new Item();
+ item1.setName( "item1 name" );
+ Category category = new Category();
+ category.setName( "category" );
+
+ item1.setCategory( category );
+ category.setExampleItem( item1 );
+
+ scope.inTransaction(
+ session ->
+ session.persist( item1 )
+ );
+
+ // get another representation of item1
+ Item item1_1 = scope.fromTransaction(
+ session ->
+ session.get( Item.class, item1.getId() )
+ );
+
+ // change basic property of nested entity
+ item1_1.setName( "item1_1 name" );
+
+ // change the nested Item to be the copy with the new name
+ item1.getCategory().setExampleItem( item1_1 );
+
+ scope.inTransaction(
+ session -> {
+ Item item1Merged = (Item) session.merge( item1 );
+ // the name from the top level item will win.
+ assertThat( item1Merged.getName(), is( item1.getName() ) );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Item item1Get = session.get( Item.class, item1.getId() );
+ assertThat( item1Get.getName(), is( item1.getName() ) );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @Test
+ public void testNestedManyToOneChangedToNull(SessionFactoryScope scope) {
+ Item item1 = new Item();
+ item1.setName( "item1 name" );
+ Category category = new Category();
+ category.setName( "category" );
+
+ item1.setCategory( category );
+ category.setExampleItem( item1 );
+
+ scope.inTransaction(
+ session ->
+ session.persist( item1 )
+ );
+
+ // get another representation of item1
+ Item item1_1 = scope.fromTransaction(
+ session ->
+ session.get( Item.class, item1.getId() )
+ );
+
+ // change many-to-one in nested entity to null.
+ item1_1.setCategory( null );
+ item1.getCategory().setExampleItem( item1_1 );
+
+ scope.inTransaction(
+ session -> {
+ Item item1Merged = (Item) session.merge( item1 );
+ // the many-to-one from the top level item will win.
+ assertThat( item1Merged.getCategory().getName(), is( category.getName() ) );
+ assertSame( item1Merged, item1Merged.getCategory().getExampleItem() );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Item item = session.get( Item.class, item1.getId() );
+ assertThat( item.getCategory().getName(), is( category.getName() ) );
+ assertSame( item, item.getCategory().getExampleItem() );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @Test
+ public void testNestedManyToOneChangedToNewEntity(SessionFactoryScope scope) {
+ Item item1 = new Item();
+ item1.setName( "item1 name" );
+ Category category = new Category();
+ category.setName( "category" );
+
+ item1.setCategory( category );
+ category.setExampleItem( item1 );
+
+ scope.inTransaction(
+ session ->
+ session.persist( item1 )
+ );
+
+ // get another representation of item1
+ Item item1_1 = scope.fromTransaction(
+ session ->
+ session.get( Item.class, item1.getId() )
+ );
+
+ // change many-to-one in nested entity to a new (transient) value
+ Category categoryNew = new Category();
+ categoryNew.setName( "new category" );
+ item1_1.setCategory( categoryNew );
+ item1.getCategory().setExampleItem( item1_1 );
+
+ scope.inTransaction(
+ session -> {
+ Item item1Merged = (Item) session.merge( item1 );
+ // the many-to-one from the top level item will win.
+ assertThat( item1Merged.getCategory().getName(), is( category.getName() ) );
+ assertSame( item1Merged, item1Merged.getCategory().getExampleItem() );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Item item = session.get( Item.class, item1.getId() );
+ assertThat( item.getCategory().getName(), is( category.getName() ) );
+ assertSame( item, item.getCategory().getExampleItem() );
+ // make sure new category got persisted
+ Category categoryQueried = (Category) session.createQuery(
+ "from Category c where c.name='new category'" )
+ .uniqueResult();
+ assertNotNull( categoryQueried );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @Test
+ public void testTopLevelManyToOneChangedToNewEntity(SessionFactoryScope scope) {
+ Item item1 = new Item();
+ item1.setName( "item1 name" );
+ Category category = new Category();
+ category.setName( "category" );
+
+ item1.setCategory( category );
+ category.setExampleItem( item1 );
+
+ scope.inTransaction(
+ session ->
+ session.persist( item1 )
+ );
+
+ // get another representation of item1
+ Item item1_1 = scope.fromTransaction(
+ session ->
+ session.get( Item.class, item1.getId() )
+ );
+
+ // change many-to-one in top level to be a new (transient)
+ Category categoryNewer = new Category();
+ categoryNewer.setName( "newer category" );
+ item1.setCategory( categoryNewer );
+
+ // put the other representation in categoryNewer
+ categoryNewer.setExampleItem( item1_1 );
+
+ scope.inTransaction(
+ session -> {
+ Item item1Merged = (Item) session.merge( item1 );
+ // the many-to-one from the top level item will win.
+ assertThat( item1Merged.getCategory().getName(), is( categoryNewer.getName() ) );
+ assertSame( item1Merged, item1Merged.getCategory().getExampleItem() );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Item item = session.get( Item.class, item1.getId() );
+ assertThat( item.getCategory().getName(), is( categoryNewer.getName() ) );
+ assertSame( item, item.getCategory().getExampleItem() );
+ // make sure original category is still there
+ Category categoryQueried = (Category) session.createQuery( "from Category c where c.name='category'" )
+ .uniqueResult();
+ assertNotNull( categoryQueried );
+ // make sure original category has the same item.
+ assertSame( item, categoryQueried.getExampleItem() );
+ // set exampleItem to null to avoid constraint violation on cleanup.
+ categoryQueried.setExampleItem( null );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @Test
+ public void testTopLevelManyToOneManagedNestedIsDetached(SessionFactoryScope scope) {
+ Item item1 = new Item();
+ item1.setName( "item1 name" );
+ Category category = new Category();
+ category.setName( "category" );
+ item1.setCategory( category );
+ category.setExampleItem( item1 );
+
+ scope.inTransaction(
+ session ->
+ session.persist( item1 )
+ );
+
+ // get another representation of item1
+ Item item1_1 = scope.fromTransaction(
+ session ->
+ session.get( Item.class, item1.getId() )
+ );
+
+ scope.inTransaction(
+ session -> {
+ Item item1Merged = (Item) session.merge( item1 );
+
+ item1Merged.setCategory( category );
+ category.setExampleItem( item1_1 );
+
+ // now item1Merged is managed and it has a nested detached item
+ session.merge( item1Merged );
+ assertThat( item1Merged.getCategory().getName(), is( category.getName() ) );
+ assertSame( item1Merged, item1Merged.getCategory().getExampleItem() );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Item item = session.get( Item.class, item1.getId() );
+ assertThat( item.getCategory().getName(), is( category.getName() ) );
+ assertSame( item, item.getCategory().getExampleItem() );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @Test
+ public void testNestedValueCollectionWithChangedElements(SessionFactoryScope scope) {
+ Item item1 = new Item();
+ item1.setName( "item1 name" );
+ Category category = new Category();
+ category.setName( "category" );
+ item1.getColors().add( "red" );
+
+ item1.setCategory( category );
+ category.setExampleItem( item1 );
+
+ scope.inTransaction(
+ session ->
+ session.persist( item1 )
+ );
+
+ // get another representation of item1
+ Item item1_1 = scope.fromTransaction(
+ session -> {
+ Item item = session.get( Item.class, item1.getId() );
+ Hibernate.initialize( item.getColors() );
+ return item;
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ // add an element to collection in nested entity
+ item1_1.getColors().add( "blue" );
+ item1.getCategory().setExampleItem( item1_1 );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Item item1Merged = (Item) session.merge( item1 );
+ // the collection from the top level item will win.
+ assertThat( item1Merged.getColors().size(), is( 1 ) );
+ assertThat( item1Merged.getColors().iterator().next(), is( "red" ) );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Item item = session.get( Item.class, item1.getId() );
+ assertThat( item.getColors().size(), is( 1 ) );
+ assertThat( item.getColors().iterator().next(), is( "red" ) );
+ Hibernate.initialize( item.getCategory() );
+ }
+ );
+
+
+ // get another representation of item1
+ Item item1_2 = scope.fromTransaction(
+ session -> {
+ Item item = session.get( Item.class, item1.getId() );
+ Hibernate.initialize( item.getColors() );
+ return item;
+ }
+ );
+
+
+ // remove the existing elements from collection in nested entity
+ item1_2.getColors().clear();
+ item1.getCategory().setExampleItem( item1_2 );
+
+ scope.inTransaction(
+ session -> {
+ Item item1Merged = (Item) session.merge( item1 );
+ // the collection from the top level item will win.
+ assertThat( item1Merged.getColors().size(), is( 1 ) );
+ assertThat( item1Merged.getColors().iterator().next(), is( "red" ) );
+ }
+ );
+
+
+ scope.inTransaction(
+ session -> {
+ Item item = session.get( Item.class, item1.getId() );
+ assertThat( item.getColors().size(), is( 1 ) );
+ assertThat( item.getColors().iterator().next(), is( "red" ) );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @Test
+ public void testTopValueCollectionWithChangedElements(SessionFactoryScope scope) {
+ Item item1 = new Item();
+ item1.setName( "item1 name" );
+ Category category = new Category();
+ category.setName( "category" );
+ item1.getColors().add( "red" );
+
+ item1.setCategory( category );
+ category.setExampleItem( item1 );
+
+ scope.inTransaction(
+ session ->
+ session.persist( item1 )
+ );
+
+ // get another representation of item1
+ Item item1_1 = scope.fromTransaction(
+ session ->
+ session.get( Item.class, item1.getId() )
+ );
+
+ // add an element to collection in nested entity
+ item1.getColors().add( "blue" );
+ item1.getCategory().setExampleItem( item1_1 );
+
+ scope.inTransaction(
+ session -> {
+ Item item1Merged = (Item) session.merge( item1 );
+ // the collection from the top level item will win.
+ assertThat( item1Merged.getColors().size(), is( 2 ) );
+ assertTrue( item1Merged.getColors().contains( "red" ) );
+ assertTrue( item1Merged.getColors().contains( "blue" ) );
+ }
+ );
+
+ Item item1_3 = scope.fromTransaction(
+ session -> {
+ Item item = session.get( Item.class, item1.getId() );
+ assertThat( item.getColors().size(), is( 2 ) );
+ assertTrue( item.getColors().contains( "red" ) );
+ assertTrue( item.getColors().contains( "blue" ) );
+ Hibernate.initialize( item.getCategory() );
+ return item;
+ }
+ );
+
+ // get another representation of item1
+ Item item1_2 = scope.fromTransaction(
+ session ->
+ session.get( Item.class, item1.getId() )
+ );
+
+ // remove the existing elements from collection in nested entity
+ item1_3.getColors().clear();
+ item1_3.getCategory().setExampleItem( item1_2 );
+
+ scope.inTransaction(
+ session -> {
+ Item item1Merged = (Item) session.merge( item1_3 );
+ // the collection from the top level item will win.
+ assertTrue( item1Merged.getColors().isEmpty() );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Item item = session.get( Item.class, item1_3.getId() );
+ assertTrue( item.getColors().isEmpty() );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @Test
+ public void testCascadeFromTransientToNonDirtyRepresentations(SessionFactoryScope scope) {
+
+ Item item1 = new Item();
+ item1.setName( "item1" );
+
+ scope.inTransaction(
+ session ->
+ session.persist( item1 )
+ );
+
+ // Get another representation of the same Item from a different session.
+
+ Item item1_1 = scope.fromSession(
+ session ->
+ session.get( Item.class, item1.getId() )
+ );
+
+ // item1_1 and item1_2 are unmodified representations of the same persistent entity.
+ assertNotSame( item1, item1_1 );
+ assertEquals( item1, item1_1 );
+
+ // Create a transient entity that references both representationsession.
+ Hoarder hoarder = new Hoarder();
+ hoarder.setName( "joe" );
+ hoarder.getItems().add( item1 );
+ hoarder.setFavoriteItem( item1_1 );
+
+ Hoarder mergedHoarder = scope.fromTransaction(
+ session -> {
+ Hoarder mHoarder = (Hoarder) session.merge( hoarder );
+ assertThat( mHoarder.getItems().size(), is( 1 ) );
+ assertSame( mHoarder.getFavoriteItem(), mHoarder.getItems().iterator().next() );
+ assertThat( mHoarder.getFavoriteItem().getId(), is( item1.getId() ) );
+ assertThat( mHoarder.getFavoriteItem().getCategory(), is( item1.getCategory() ) );
+ return mHoarder;
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Hoarder h = (Hoarder) session.merge( mergedHoarder );
+ assertThat( hoarder.getItems().size(), is( 1 ) );
+ assertSame( h.getFavoriteItem(), h.getItems().iterator().next() );
+ assertThat( h.getFavoriteItem().getId(), is( item1.getId() ) );
+ assertThat( h.getFavoriteItem().getCategory(), is( item1.getCategory() ) );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @Test
+ public void testCascadeFromDetachedToNonDirtyRepresentations(SessionFactoryScope scope) {
+ Item item1 = new Item();
+ item1.setName( "item1" );
+
+ Hoarder hoarder = new Hoarder();
+ hoarder.setName( "joe" );
+
+ scope.inTransaction(
+ session -> {
+ session.persist( item1 );
+ session.persist( hoarder );
+ }
+ );
+
+ // Get another representation of the same Item from a different session.
+
+ Item item1_1 = scope.fromSession(
+ session ->
+ session.get( Item.class, item1.getId() )
+ );
+
+ // item1_1 and item1_2 are unmodified representations of the same persistent entity.
+ assertNotSame( item1, item1_1 );
+ assertEquals( item1, item1_1 );
+
+ // Update hoarder (detached) to references both representationsession.
+ hoarder.getItems().add( item1 );
+ hoarder.setFavoriteItem( item1_1 );
+
+ Hoarder mergedHoarder = scope.fromTransaction(
+ session -> {
+ Hoarder h = (Hoarder) session.merge( hoarder );
+ assertThat( h.getItems().size(), is( 1 ) );
+ assertSame( h.getFavoriteItem(), h.getItems().iterator().next() );
+ assertThat( h.getFavoriteItem().getId(), is( item1.getId() ) );
+ assertThat( h.getFavoriteItem().getCategory(), is( item1.getCategory() ) );
+ return h;
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Hoarder h = (Hoarder) session.merge( mergedHoarder );
+ assertThat( h.getItems().size(), is( 1 ) );
+ assertSame( h.getFavoriteItem(), h.getItems().iterator().next() );
+ assertThat( h.getFavoriteItem().getId(), is( item1.getId() ) );
+ assertThat( h.getFavoriteItem().getCategory(), is( item1.getCategory() ) );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @Test
+ public void testCascadeFromDetachedToGT2DirtyRepresentations(SessionFactoryScope scope) {
+ Item item1 = new Item();
+ item1.setName( "item1" );
+ Category category1 = new Category();
+ category1.setName( "category1" );
+ item1.setCategory( category1 );
+
+ Hoarder hoarder = new Hoarder();
+ hoarder.setName( "joe" );
+
+ scope.inTransaction(
+ session -> {
+ session.persist( item1 );
+ session.persist( hoarder );
+ }
+ );
+
+ // Get another representation of the same Item from a different session.
+
+ Item item1_1 = scope.fromSession(
+ session ->
+ session.get( Item.class, item1.getId() )
+ );
+
+ // item1 and item1_1 are unmodified representations of the same persistent entity.
+ assertNotSame( item1, item1_1 );
+ assertEquals( item1, item1_1 );
+
+ // Get another representation of the same Item from a different session.
+
+ Item item1_2 = scope.fromSession(
+ session ->
+ session.get( Item.class, item1.getId() )
+ );
+
+ // item1_1 and item1_2 are unmodified representations of the same persistent entity.
+ assertNotSame( item1, item1_2 );
+ assertEquals( item1, item1_2 );
+
+ item1_1.setName( "item1_1" );
+ item1_2.setName( "item1_2" );
+
+ // Update hoarder (detached) to references both representationsession.
+ item1.getCategory().setExampleItem( item1_2 );
+ hoarder.getItems().add( item1 );
+ hoarder.setFavoriteItem( item1_1 );
+ hoarder.getFavoriteItem().getCategory();
+
+ Hoarder mergedHoarder = scope.fromTransaction(
+ session -> {
+ Hoarder mHoarder = (Hoarder) session.merge( hoarder );
+ assertThat( mHoarder.getItems().size(), is( 1 ) );
+ assertSame( mHoarder.getFavoriteItem(), mHoarder.getItems().iterator().next() );
+ assertSame( mHoarder.getFavoriteItem(), mHoarder.getFavoriteItem().getCategory().getExampleItem() );
+ assertThat( mHoarder.getFavoriteItem().getId(), is( item1.getId() ) );
+ assertThat( mHoarder.getFavoriteItem().getCategory(), is( item1.getCategory() ) );
+ assertThat( mHoarder.getFavoriteItem().getName(), is( item1.getName() ) );
+ return mHoarder;
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Hoarder h = (Hoarder) session.merge( mergedHoarder );
+ assertThat( h.getItems().size(), is( 1 ) );
+ assertSame( h.getFavoriteItem(), h.getItems().iterator().next() );
+ assertSame( h.getFavoriteItem(), h.getFavoriteItem().getCategory().getExampleItem() );
+ assertThat( h.getFavoriteItem().getId(), is( item1.getId() ) );
+ assertThat( h.getFavoriteItem().getCategory(), is( item1.getCategory() ) );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @Test
+ public void testTopLevelEntityNewerThanNested(SessionFactoryScope scope) {
+ Item item = new Item();
+ item.setName( "item" );
+
+ Category category = new Category();
+ category.setName( "category" );
+
+ scope.inTransaction(
+ session -> {
+ session.persist( item );
+ session.persist( category );
+ }
+ );
+
+ // Get the Category from a different session.
+ Category category1_2 = scope.fromTransaction(
+ session ->
+ session.get( Category.class, category.getId() )
+ );
+
+ // Get and update the same Category.
+ Category category1_1 = scope.fromTransaction(
+ session -> {
+ Category category1 = session.get( Category.class, category.getId() );
+ category1.setName( "new name" );
+ return category1;
+ }
+ );
+
+ assertTrue( category1_2.getVersion() < category1_1.getVersion() );
+
+ category1_1.setExampleItem( item );
+ item.setCategory( category1_2 );
+
+ scope.inTransaction(
+ session -> {
+ try {
+ // representation merged at top level is newer than nested representation.
+ session.merge( category1_1 );
+ fail( "should have failed because one representation is an older version." );
+ }
+ catch (PersistenceException e) {
+ // expected
+ assertTyping( StaleObjectStateException.class, e.getCause() );
+ }
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @Test
+ public void testNestedEntityNewerThanTopLevel(SessionFactoryScope scope) {
+ Item item = new Item();
+ item.setName( "item" );
+
+ Category category = new Category();
+ category.setName( "category" );
+
+ scope.inTransaction(
+ session -> {
+ session.persist( item );
+ session.persist( category );
+ }
+ );
+
+ // Get category1_1 from a different session.
+ Category category1_1 = scope.fromSession(
+ session ->
+ session.get( Category.class, category.getId() )
+ );
+
+ // Get and update category1_2 to increment its version.
+ Category category1_2 = scope.fromTransaction(
+ session -> {
+ Category category1 = session.get( Category.class, category.getId() );
+ category1.setName( "new name" );
+ return category1;
+ }
+ );
+
+ assertTrue( category1_2.getVersion() > category1_1.getVersion() );
+
+ category1_1.setExampleItem( item );
+ item.setCategory( category1_2 );
+
+ scope.inTransaction(
+ session -> {
+ try {
+ // nested representation is newer than top lever representation.
+ session.merge( category1_1 );
+ fail( "should have failed because one representation is an older version." );
+ }
+ catch (PersistenceException e) {
+ // expected
+ assertTyping( StaleObjectStateException.class, e.getCause() );
+ }
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @Test
+ @FailureExpected(jiraKey = "HHH-9240")
+ public void testTopLevelUnidirOneToManyBackrefWithNewElement(SessionFactoryScope scope) {
+ Item item1 = new Item();
+ item1.setName( "item1 name" );
+ SubItem subItem1 = new SubItem();
+ subItem1.setName( "subItem1 name" );
+ item1.getSubItemsBackref().add( subItem1 );
+
+ scope.inTransaction(
+ session ->
+ session.persist( item1 )
+ );
+
+ // get another representation of item1
+ Item item1_1 = scope.fromTransaction(
+ session ->
+ session.get( Item.class, item1.getId() )
+ );
+
+ assertFalse( Hibernate.isInitialized( item1_1.getSubItemsBackref() ) );
+
+ Category category = new Category();
+ category.setName( "category" );
+
+ SubItem subItem2 = new SubItem();
+ subItem2.setName( "subItem2 name" );
+ item1.getSubItemsBackref().add( subItem2 );
+
+ item1.setCategory( category );
+ category.setExampleItem( item1_1 );
+
+ scope.inTransaction(
+ session -> {
+ // The following will fail due to PropertyValueException because item1 will
+ // be removed from the inverted merge map when the operation cascades to item1_1.
+ Item item1Merged = (Item) session.merge( item1 );
+ // top-level collection should win
+ assertThat( item1.getSubItemsBackref().size(), is( 2 ) );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Item item = session.get( Item.class, item1.getId() );
+ assertThat( item.getSubItemsBackref().size(), is( 2 ) );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @Test
+ @FailureExpected(jiraKey = "HHH-9239")
+ public void testNestedUnidirOneToManyBackrefWithNewElement(SessionFactoryScope scope) {
+ Item item1 = new Item();
+ item1.setName( "item1 name" );
+ SubItem subItem1 = new SubItem();
+ subItem1.setName( "subItem1 name" );
+ item1.getSubItemsBackref().add( subItem1 );
+
+ scope.inTransaction(
+ session ->
+ session.persist( item1 )
+ );
+
+ // get another representation of item1
+ Item item1_1 = scope.fromTransaction(
+ session -> {
+ Item item = session.get( Item.class, item1.getId() );
+ Hibernate.initialize( item.getSubItemsBackref() );
+ return item;
+ }
+ );
+
+ Category category = new Category();
+ category.setName( "category" );
+ item1.setCategory( category );
+
+ SubItem subItem2 = new SubItem();
+ subItem2.setName( "subItem2 name" );
+ item1_1.getSubItemsBackref().add( subItem2 );
+
+ category.setExampleItem( item1_1 );
+
+ Item item1Merged = scope.fromTransaction(
+ session -> {
+ Item item = (Item) session.merge( item1 );
+ // The resulting collection should contain the added element
+ assertThat( item.getSubItemsBackref().size(), is( 2 ) );
+ assertThat( item.getSubItemsBackref().get( 0 ).getName(), is( "subItem1 name" ) );
+ assertThat( item.getSubItemsBackref().get( 1 ).getName(), is( "subItem2 name" ) );
+ return item;
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Item item = session.get( Item.class, item1.getId() );
+ assertThat( item.getSubItemsBackref().size(), is( 2 ) );
+ assertThat( item.getSubItemsBackref().get( 0 ).getName(), is( "subItem1 name" ) );
+ assertThat( item1Merged.getSubItemsBackref().get( 1 ).getName(), is( "subItem2 name" ) );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @Test
+ //@FailureExpected( jiraKey = "HHH-9106" )
+ public void testTopLevelUnidirOneToManyBackrefWithRemovedElement(SessionFactoryScope scope) {
+ Item item1 = new Item();
+ item1.setName( "item1 name" );
+ SubItem subItem1 = new SubItem();
+ subItem1.setName( "subItem1 name" );
+ item1.getSubItemsBackref().add( subItem1 );
+ SubItem subItem2 = new SubItem();
+ subItem2.setName( "subItem2 name" );
+ item1.getSubItemsBackref().add( subItem2 );
+
+ scope.inTransaction(
+ session ->
+ session.persist( item1 )
+ );
+
+ // get another representation of item1
+ Item item1_1 = scope.fromTransaction(
+ session ->
+ session.get( Item.class, item1.getId() )
+ );
+
+ assertFalse( Hibernate.isInitialized( item1_1.getSubItemsBackref() ) );
+
+ Category category = new Category();
+ category.setName( "category" );
+
+ item1.setCategory( category );
+ category.setExampleItem( item1_1 );
+
+ // remove subItem1 from top-level Item
+ item1.getSubItemsBackref().remove( subItem1 );
+
+ scope.inTransaction(
+ session -> {
+ Item item1Merged = (Item) session.merge( item1 );
+ // entity should have been removed
+ assertThat( item1Merged.getSubItemsBackref().size(), is( 1 ) );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Item item = session.get( Item.class, item1.getId() );
+ assertThat( item.getSubItemsBackref().size(), is( 1 ) );
+ SubItem subItem = session.get( SubItem.class, subItem1.getId() );
+ // cascade does not include delete-orphan, so subItem1 should still be persistent.
+ assertNotNull( subItem );
+ }
+ );
+
+
+ cleanup( scope );
+ }
+
+ @Test
+ @FailureExpected(jiraKey = "HHH-9239")
+ public void testNestedUnidirOneToManyBackrefWithRemovedElement(SessionFactoryScope scope) {
+ Item item1 = new Item();
+ item1.setName( "item1 name" );
+ SubItem subItem1 = new SubItem();
+ subItem1.setName( "subItem1 name" );
+ item1.getSubItemsBackref().add( subItem1 );
+ SubItem subItem2 = new SubItem();
+ subItem2.setName( "subItem2 name" );
+ item1.getSubItemsBackref().add( subItem2 );
+
+ scope.inTransaction(
+ session ->
+ session.persist( item1 )
+ );
+
+ // get another representation of item1
+ Item item1_1 = scope.fromTransaction(
+ session -> {
+ Item item = session.get( Item.class, item1.getId() );
+ Hibernate.initialize( item.getSubItemsBackref() );
+ return item;
+ }
+ );
+
+ // remove subItem1 from the nested Item
+ item1_1.getSubItemsBackref().remove( subItem1 );
+
+ Category category = new Category();
+ category.setName( "category" );
+ item1.setCategory( category );
+ category.setExampleItem( item1_1 );
+
+ scope.inTransaction(
+ session -> {
+ Item item1Merged = (Item) session.merge( item1 );
+ // entity should have been removed
+ assertThat( item1Merged.getSubItemsBackref().size(), is( 1 ) );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Item item = session.get( Item.class, item1.getId() );
+ assertThat( item.getSubItemsBackref().size(), is( 1 ) );
+ SubItem subItem = session.get( SubItem.class, subItem1.getId() );
+ // cascade does not include delete-orphan, so subItem1 should still be persistent.
+ assertNotNull( subItem );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @Test
+ //@FailureExpected( jiraKey = "HHH-9106" )
+ public void testTopLevelUnidirOneToManyNoBackrefWithNewElement(SessionFactoryScope scope) {
+ Category category1 = new Category();
+ category1.setName( "category1 name" );
+ SubCategory subCategory1 = new SubCategory();
+ subCategory1.setName( "subCategory1 name" );
+ category1.getSubCategories().add( subCategory1 );
+
+ scope.inTransaction(
+ session ->
+ session.persist( category1 )
+ );
+
+ // get another representation of category1
+ Category category1_1 = scope.fromTransaction(
+ session ->
+ session.get( Category.class, category1.getId() )
+ );
+
+ assertFalse( Hibernate.isInitialized( category1_1.getSubCategories() ) );
+
+ SubCategory subCategory2 = new SubCategory();
+ subCategory2.setName( "subCategory2 name" );
+ category1.getSubCategories().add( subCategory2 );
+
+ Item item = new Item();
+ item.setName( "item" );
+ category1.setExampleItem( item );
+ item.setCategory( category1_1 );
+
+ scope.inTransaction(
+ session -> {
+ Category category = (Category) session.merge( category1 );
+ assertThat( category.getSubCategories().size(), is( 2 ) );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Category category = session.get( Category.class, category1.getId() );
+ assertThat( category.getSubCategories().size(), is( 2 ) );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @Test
+ @FailureExpected(jiraKey = "HHH-9239")
+ public void testNestedUnidirOneToManyNoBackrefWithNewElement(SessionFactoryScope scope) {
+ Category category1 = new Category();
+ category1.setName( "category1 name" );
+ SubCategory subCategory1 = new SubCategory();
+ subCategory1.setName( "subCategory1 name" );
+ category1.getSubCategories().add( subCategory1 );
+
+ scope.inTransaction(
+ session ->
+ session.persist( category1 )
+ );
+
+ // get another representation of category1
+ Category category1_1 = scope.fromTransaction(
+ session -> {
+ Category category = session.get( Category.class, category1.getId() );
+ Hibernate.initialize( category.getSubCategories() );
+ return category;
+ }
+ );
+
+ SubCategory subCategory2 = new SubCategory();
+ subCategory2.setName( "subCategory2 name" );
+ category1_1.getSubCategories().add( subCategory2 );
+
+ Item item = new Item();
+ item.setName( "item" );
+ category1.setExampleItem( item );
+ item.setCategory( category1_1 );
+
+ scope.inTransaction(
+ session -> {
+ Category category1Merged = (Category) session.merge( category1 );
+ assertThat( category1Merged.getSubCategories().size(), is( 2 ) );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Category category = session.get( Category.class, category1.getId() );
+ assertThat( category.getSubCategories().size(), is( 2 ) );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @Test
+ //@FailureExpected( jiraKey = "HHH-9106" )
+ public void testTopLevelUnidirOneToManyNoBackrefWithRemovedElement(SessionFactoryScope scope) {
+ Category category1 = new Category();
+ category1.setName( "category1 name" );
+ SubCategory subCategory1 = new SubCategory();
+ subCategory1.setName( "subCategory1 name" );
+ category1.getSubCategories().add( subCategory1 );
+ SubCategory subCategory2 = new SubCategory();
+ subCategory2.setName( "subCategory2 name" );
+ category1.getSubCategories().add( subCategory2 );
+
+ scope.inTransaction(
+ session ->
+ session.persist( category1 )
+ );
+
+ // get another representation of category1
+ Category category1_1 = scope.fromTransaction(
+ session ->
+ session.get( Category.class, category1.getId() )
+ );
+
+ assertFalse( Hibernate.isInitialized( category1_1.getSubCategories() ) );
+
+ Item item = new Item();
+ item.setName( "item" );
+ category1.setExampleItem( item );
+ item.setCategory( category1_1 );
+
+ category1.getSubCategories().remove( subCategory1 );
+
+ scope.inTransaction(
+ session -> {
+ Category category1Merged = (Category) session.merge( category1 );
+ assertThat( category1Merged.getSubCategories().size(), is( 1 ) );
+ assertTrue( category1Merged.getSubCategories().contains( subCategory2 ) );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Category category = session.get( Category.class, category1.getId() );
+ assertThat( category.getSubCategories().size(), is( 1 ) );
+ assertTrue( category.getSubCategories().contains( subCategory2 ) );
+ // cascade does not include delete-orphan, so subCategory1 should still be persistent.
+ SubCategory subCategory = session.get( SubCategory.class, subCategory1.getId() );
+ assertNotNull( subCategory );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @Test
+ @FailureExpected(jiraKey = "HHH-9239")
+ public void testNestedUnidirOneToManyNoBackrefWithRemovedElement(SessionFactoryScope scope) {
+ Category category1 = new Category();
+ category1.setName( "category1 name" );
+ SubCategory subCategory1 = new SubCategory();
+ subCategory1.setName( "subCategory1 name" );
+ category1.getSubCategories().add( subCategory1 );
+ SubCategory subCategory2 = new SubCategory();
+ subCategory2.setName( "subCategory2 name" );
+ category1.getSubCategories().add( subCategory2 );
+
+ scope.inTransaction(
+ session ->
+ session.persist( category1 )
+ );
+
+ // get another representation of category1
+ Category category1_1 = scope.fromTransaction(
+ session -> {
+ Category category = session.get( Category.class, category1.getId() );
+ Hibernate.initialize( category.getSubCategories() );
+ return category;
+ }
+ );
+
+ category1_1.getSubCategories().remove( subCategory2 );
+
+ Item item = new Item();
+ item.setName( "item" );
+ category1.setExampleItem( item );
+ item.setCategory( category1_1 );
+
+ scope.inTransaction(
+ session -> {
+ Category category1Merged = (Category) session.merge( category1 );
+ assertThat( category1Merged.getSubCategories().size(), is( 1 ) );
+ assertTrue( category1Merged.getSubCategories().contains( subCategory2 ) );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Category category = session.get( Category.class, category1.getId() );
+ assertThat( category.getSubCategories().size(), is( 1 ) );
+ assertTrue( category.getSubCategories().contains( subCategory2 ) );
+ // cascade does not include delete-orphan, so subCategory1 should still be persistent.
+ SubCategory subCategory = session.get( SubCategory.class, subCategory1.getId() );
+ assertNotNull( subCategory );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @SuppressWarnings({ "unchecked" })
+ private void cleanup(SessionFactoryScope scope) {
+ scope.inTransaction(
+ session -> {
+ session.createQuery( "delete from SubItem" ).executeUpdate();
+ for ( Hoarder hoarder : (List) session.createQuery( "from Hoarder" ).list() ) {
+ hoarder.getItems().clear();
+ session.delete( hoarder );
+ }
+
+ for ( Category category : (List) session.createQuery( "from Category" ).list() ) {
+ Item exampleItem = category.getExampleItem();
+ if ( exampleItem != null ) {
+ category.setExampleItem( null );
+ exampleItem.setCategory( null );
+ session.delete( category );
+ session.delete( exampleItem );
+ }
+ }
+
+ for ( Item item : (List) session.createQuery( "from Item" ).list() ) {
+ Category category = item.getCategory();
+ item.setCategory( null );
+ if ( category != null ) {
+ category.setExampleItem( null );
+ }
+ session.delete( item );
+ }
+
+ session.createQuery( "delete from Item" ).executeUpdate();
+ }
+ );
+ }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/ops/MergeMultipleEntityCopiesCustomTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/MergeMultipleEntityCopiesCustomTest.java
new file mode 100644
index 0000000000..4b535c2e74
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/MergeMultipleEntityCopiesCustomTest.java
@@ -0,0 +1,193 @@
+/*
+ * 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.orm.test.ops;
+
+import java.util.List;
+
+import org.hibernate.Hibernate;
+import org.hibernate.cfg.AvailableSettings;
+
+import org.hibernate.testing.TestForIssue;
+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.hibernate.testing.orm.junit.Setting;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.fail;
+
+/**
+ * Tests merging multiple detached representations of the same entity using a custom EntityCopyObserver.
+ *
+ * @author Gail Badner
+ */
+@TestForIssue(jiraKey = "HHH-9106")
+@DomainModel(
+ xmlMappings = "org/hibernate/orm/test/ops/Hoarder.hbm.xml",
+ annotatedClasses = {
+ Category.class,
+ Hoarder.class,
+ Item.class
+ }
+)
+@SessionFactory
+@ServiceRegistry(
+ settings = @Setting(name = AvailableSettings.MERGE_ENTITY_COPY_OBSERVER, value = "org.hibernate.orm.test.ops.CustomEntityCopyObserver")
+)
+public class MergeMultipleEntityCopiesCustomTest {
+
+ @Test
+ public void testMergeMultipleEntityCopiesAllowed(SessionFactoryScope scope) {
+ Item item1 = new Item();
+ item1.setName( "item1" );
+
+ Hoarder hoarder = new Hoarder();
+ hoarder.setName( "joe" );
+
+ scope.inTransaction(
+ session -> {
+ session.persist( item1 );
+ session.persist( hoarder );
+ }
+ );
+
+ // Get another representation of the same Item.
+
+ Item item1_1 = scope.fromTransaction(
+ session ->
+ session.get( Item.class, item1.getId() )
+ );
+
+ // item1_1 and item1_2 are unmodified representations of the same persistent entity.
+ assertNotSame( item1, item1_1 );
+ assertEquals( item1, item1_1 );
+
+ // Update hoarder (detached) to references both representations.
+ hoarder.getItems().add( item1 );
+ hoarder.setFavoriteItem( item1_1 );
+
+ Hoarder h = scope.fromTransaction(
+ session -> {
+ // the merge should succeed because it does not have Category copies.
+ // (CustomEntityCopyObserver does not allow Category copies; it does allow Item copies)
+ Hoarder h1 = (Hoarder) session.merge( hoarder );
+ assertThat( h1.getItems().size(), is( 1 ) );
+ assertSame( h1.getFavoriteItem(), h1.getItems().iterator().next() );
+ assertThat( h1.getFavoriteItem().getId(), is( item1.getId() ) );
+ assertThat( h1.getFavoriteItem().getCategory(), is( item1.getCategory() ) );
+ return h1;
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Hoarder h1 = session.get( Hoarder.class, h.getId() );
+ assertThat( h1.getItems().size(), is( 1 ) );
+ assertSame( h1.getFavoriteItem(), h1.getItems().iterator().next() );
+ assertThat( h1.getFavoriteItem().getId(), is( item1.getId() ) );
+ assertThat( h1.getFavoriteItem().getCategory(), is( item1.getCategory() ) );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @Test
+ public void testMergeMultipleEntityCopiesAllowedAndDisallowed(SessionFactoryScope scope) {
+ Item item1 = new Item();
+ item1.setName( "item1 name" );
+ Category category = new Category();
+ category.setName( "category" );
+ item1.setCategory( category );
+ category.setExampleItem( item1 );
+
+ scope.inTransaction(
+ session ->
+ session.persist( item1 )
+ );
+
+ // get another representation of item1
+ Item item1_1 = scope.fromTransaction(
+ session -> {
+ Item item = session.get( Item.class, item1.getId() );
+ // make sure item1_1.category is initialized
+ Hibernate.initialize( item.getCategory() );
+ return item;
+ }
+ );
+
+ scope.inSession(
+ session -> {
+ session.beginTransaction();
+ Item item1Merged = (Item) session.merge( item1 );
+
+ item1Merged.setCategory( category );
+ category.setExampleItem( item1_1 );
+
+ // now item1Merged is managed and it has a nested detached item
+ // and there is multiple managed/detached Category objects
+ try {
+ // the following should fail because multiple copies of Category objects is not allowed by
+ // CustomEntityCopyObserver
+ session.merge( item1Merged );
+ fail( "should have failed because CustomEntityCopyObserver does not allow multiple copies of a Category. " );
+ }
+ catch (IllegalStateException ex) {
+ //expected
+ }
+ finally {
+ if ( session.getTransaction().isActive() ) {
+ session.getTransaction().rollback();
+ }
+ }
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ Item item = session.get( Item.class, item1.getId() );
+ assertThat( item.getCategory().getName(), is( category.getName() ) );
+ assertSame( item, item.getCategory().getExampleItem() );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @SuppressWarnings({ "unchecked" })
+ private void cleanup(SessionFactoryScope scope) {
+ scope.inTransaction(
+ session -> {
+ for ( Hoarder hoarder : (List) session.createQuery( "from Hoarder" ).list() ) {
+ hoarder.getItems().clear();
+ session.delete( hoarder );
+ }
+
+ for ( Category category : (List) session.createQuery( "from Category" ).list() ) {
+ if ( category.getExampleItem() != null ) {
+ category.setExampleItem( null );
+ session.delete( category );
+ }
+ }
+
+ for ( Item item : (List) session.createQuery( "from Item" ).list() ) {
+ item.setCategory( null );
+ session.delete( item );
+ }
+
+ session.createQuery( "delete from Item" ).executeUpdate();
+ }
+ );
+ }
+
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/ops/MergeMultipleEntityCopiesDisallowedByDefaultTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/MergeMultipleEntityCopiesDisallowedByDefaultTest.java
new file mode 100644
index 0000000000..b2dc67793c
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/MergeMultipleEntityCopiesDisallowedByDefaultTest.java
@@ -0,0 +1,145 @@
+/*
+ * 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.orm.test.ops;
+
+import java.util.List;
+
+import org.hibernate.testing.TestForIssue;
+import org.hibernate.testing.orm.junit.DomainModel;
+import org.hibernate.testing.orm.junit.SessionFactory;
+import org.hibernate.testing.orm.junit.SessionFactoryScope;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.fail;
+
+/**
+ * Tests merging multiple detached representations of the same entity using
+ * a the default (that does not allow this).
+ *
+ * @author Gail Badner
+ */
+@TestForIssue(jiraKey = "HHH-9106")
+@DomainModel(
+ xmlMappings = "org/hibernate/orm/test/ops/Hoarder.hbm.xml"
+)
+@SessionFactory
+public class MergeMultipleEntityCopiesDisallowedByDefaultTest {
+
+ @Test
+ public void testCascadeFromDetachedToNonDirtyRepresentations(SessionFactoryScope scope) {
+ Item item1 = new Item();
+ item1.setName( "item1" );
+
+ Hoarder hoarder = new Hoarder();
+ hoarder.setName( "joe" );
+
+ scope.inTransaction(
+ session -> {
+ session.persist( item1 );
+ session.persist( hoarder );
+ }
+ );
+
+ // Get another representation of the same Item from a different session.
+ Item item1_1 = scope.fromTransaction(
+ session ->
+ session.get( Item.class, item1.getId() )
+ );
+
+ // item1_1 and item1_2 are unmodified representations of the same persistent entity.
+ assertNotSame( item1, item1_1 );
+ assertEquals( item1, item1_1 );
+
+ // Update hoarder (detached) to references both representations.
+ hoarder.getItems().add( item1 );
+ hoarder.setFavoriteItem( item1_1 );
+
+ scope.inTransaction(
+ session -> {
+ try {
+ session.merge( hoarder );
+ fail( "should have failed due IllegalStateException" );
+ }
+ catch (IllegalStateException ex) {
+ //expected
+ }
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @Test
+ public void testTopLevelManyToOneManagedNestedIsDetached(SessionFactoryScope scope) {
+ Item item1 = new Item();
+ item1.setName( "item1 name" );
+ Category category = new Category();
+ category.setName( "category" );
+ item1.setCategory( category );
+ category.setExampleItem( item1 );
+
+ scope.inTransaction(
+ session ->
+ session.persist( item1 )
+ );
+
+ // get another representation of item1
+ Item item1_1 = scope.fromTransaction(
+ session ->
+ session.get( Item.class, item1.getId() )
+ );
+
+ scope.inTransaction(
+ session -> {
+ Item item1Merged = (Item) session.merge( item1 );
+
+ item1Merged.setCategory( category );
+ category.setExampleItem( item1_1 );
+
+ // now item1Merged is managed and it has a nested detached item
+ try {
+ session.merge( item1Merged );
+ fail( "should have failed due IllegalStateException" );
+ }
+ catch (IllegalStateException ex) {
+ //expected
+ }
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @SuppressWarnings({ "unchecked" })
+ private void cleanup(SessionFactoryScope scope) {
+ scope.inTransaction(
+ session -> {
+ session.createQuery( "delete from SubItem" ).executeUpdate();
+ for ( Hoarder hoarder : (List) session.createQuery( "from Hoarder" ).list() ) {
+ hoarder.getItems().clear();
+ session.delete( hoarder );
+ }
+
+ for ( Category category : (List) session.createQuery( "from Category" ).list() ) {
+ if ( category.getExampleItem() != null ) {
+ category.setExampleItem( null );
+ session.delete( category );
+ }
+ }
+
+ for ( Item item : (List) session.createQuery( "from Item" ).list() ) {
+ item.setCategory( null );
+ session.delete( item );
+ }
+
+ session.createQuery( "delete from Item" ).executeUpdate();
+ }
+ );
+ }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/MergeMultipleEntityCopiesDisallowedTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/MergeMultipleEntityCopiesDisallowedTest.java
similarity index 61%
rename from hibernate-core/src/test/java/org/hibernate/test/ops/MergeMultipleEntityCopiesDisallowedTest.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ops/MergeMultipleEntityCopiesDisallowedTest.java
index a2df70736e..18d8e67a01 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ops/MergeMultipleEntityCopiesDisallowedTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/MergeMultipleEntityCopiesDisallowedTest.java
@@ -4,11 +4,13 @@
* 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.ops;
+package org.hibernate.orm.test.ops;
-import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.AvailableSettings;
import org.hibernate.testing.TestForIssue;
+import org.hibernate.testing.orm.junit.ServiceRegistry;
+import org.hibernate.testing.orm.junit.Setting;
/**
@@ -16,14 +18,9 @@ import org.hibernate.testing.TestForIssue;
*
* @author Gail Badner
*/
-@TestForIssue( jiraKey = "HHH-9106")
+@TestForIssue(jiraKey = "HHH-9106")
+@ServiceRegistry(
+ settings = @Setting(name = AvailableSettings.MERGE_ENTITY_COPY_OBSERVER, value = "disallow")
+)
public class MergeMultipleEntityCopiesDisallowedTest extends MergeMultipleEntityCopiesDisallowedByDefaultTest {
-
- public void configure(Configuration cfg) {
- super.configure( cfg );
- cfg.setProperty(
- "hibernate.event.merge.entity_copy_observer",
- "disallow"
- );
- }
}
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/ops/MergeTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/MergeTest.java
new file mode 100755
index 0000000000..125d6d388b
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/MergeTest.java
@@ -0,0 +1,850 @@
+/*
+ * 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.orm.test.ops;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import javax.persistence.PersistenceException;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Root;
+
+import org.hibernate.Hibernate;
+import org.hibernate.NonUniqueObjectException;
+import org.hibernate.Session;
+import org.hibernate.StaleObjectStateException;
+import org.hibernate.dialect.AbstractHANADialect;
+
+import org.hibernate.testing.orm.junit.DialectFeatureChecks;
+import org.hibernate.testing.orm.junit.RequiresDialectFeature;
+import org.hibernate.testing.orm.junit.SessionFactoryScope;
+import org.hibernate.testing.orm.junit.SkipForDialect;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hibernate.testing.orm.junit.ExtraAssertions.assertTyping;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+/**
+ * @author Gavin King
+ */
+@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsNoColumnInsert.class)
+public class MergeTest extends AbstractOperationTestCase {
+
+ @Test
+ public void testMergeStaleVersionFails(SessionFactoryScope scope) {
+ VersionedEntity entity = new VersionedEntity( "entity", "entity" );
+ scope.inTransaction(
+ session ->
+ session.persist( entity )
+ );
+
+ // make the detached 'entity' reference stale...
+ scope.inTransaction(
+ session -> {
+ VersionedEntity entity2 = session.get( VersionedEntity.class, entity.getId() );
+ entity2.setName( "entity-name" );
+ }
+ );
+
+ // now try to reattach it
+ scope.inSession(
+ session -> {
+ try {
+ session.beginTransaction();
+ session.merge( entity );
+ session.getTransaction().commit();
+ fail( "was expecting staleness error" );
+ }
+ catch (PersistenceException e) {
+ // expected
+ assertTyping( StaleObjectStateException.class, e.getCause() );
+ }
+ finally {
+ if ( session.getTransaction().isActive() ) {
+ session.getTransaction().rollback();
+ }
+ }
+ }
+ );
+ }
+
+ @Test
+ public void testMergeBidiPrimayKeyOneToOne(SessionFactoryScope scope) {
+// scope.getSessionFactory().close();
+ Person p = new Person( "steve" );
+ scope.inTransaction(
+ session -> {
+ new PersonalDetails( "I have big feet", p );
+ session.persist( p );
+ }
+ );
+
+ clearCounts( scope );
+
+ p.getDetails().setSomePersonalDetail( p.getDetails().getSomePersonalDetail() + " and big hands too" );
+
+ Person person = scope.fromTransaction(
+ session ->
+ (Person) session.merge( p )
+ );
+
+ assertInsertCount( 0, scope );
+ assertUpdateCount( 1, scope );
+ assertDeleteCount( 0, scope );
+
+ scope.inTransaction(
+ session ->
+ session.delete( person )
+ );
+ }
+
+ @Test
+ public void testMergeBidiForeignKeyOneToOne(SessionFactoryScope scope) {
+ Person p = new Person( "steve" );
+ Address a = new Address( "123 Main", "Austin", "US", p );
+ scope.inTransaction(
+ session -> {
+ new PersonalDetails( "I have big feet", p );
+ session.persist( a );
+ session.persist( p );
+ }
+ );
+
+ clearCounts( scope );
+
+ p.getAddress().setStreetAddress( "321 Main" );
+ Person person = scope.fromTransaction(
+ session ->
+ (Person) session.merge( p )
+ );
+
+ assertInsertCount( 0, scope );
+ assertUpdateCount( 0, scope ); // no cascade
+ assertDeleteCount( 0, scope );
+
+ scope.inTransaction(
+ session -> {
+ session.delete( a );
+ session.delete( person );
+ }
+ );
+ }
+
+ @Test
+ public void testNoExtraUpdatesOnMerge(SessionFactoryScope scope) {
+ Node node = new Node( "test" );
+ scope.inTransaction(
+ session ->
+ session.persist( node )
+ );
+
+ clearCounts( scope );
+
+ // node is now detached, but we have made no changes. so attempt to merge it
+ // into this new session; this should cause no updates...
+ Node n = (Node) scope.fromTransaction(
+ session ->
+ session.merge( node )
+ );
+
+ assertUpdateCount( 0, scope );
+ assertInsertCount( 0, scope );
+
+ ///////////////////////////////////////////////////////////////////////
+ // as a control measure, now update the node while it is detached and
+ // make sure we get an update as a result...
+ n.setDescription( "new description" );
+
+ scope.inTransaction(
+ session ->
+ session.merge( n )
+ );
+
+ assertUpdateCount( 1, scope );
+ assertInsertCount( 0, scope );
+ ///////////////////////////////////////////////////////////////////////
+
+ cleanup( scope );
+ }
+
+ @Test
+ @SuppressWarnings({ "unchecked" })
+ public void testNoExtraUpdatesOnMergeWithCollection(SessionFactoryScope scope) {
+ Node parent = new Node( "parent" );
+ scope.inTransaction(
+ session -> {
+ Node child = new Node( "child" );
+ parent.getChildren().add( child );
+ child.setParent( parent );
+ session.persist( parent );
+ }
+ );
+
+ clearCounts( scope );
+
+ // parent is now detached, but we have made no changes. so attempt to merge it
+ // into this new session; this should cause no updates...
+ Node p = scope.fromTransaction(
+ session ->
+ (Node) session.merge( parent )
+ );
+
+ assertUpdateCount( 0, scope );
+ assertInsertCount( 0, scope );
+
+ ///////////////////////////////////////////////////////////////////////
+ // as a control measure, now update the node while it is detached and
+ // make sure we get an update as a result...
+ ( (Node) p.getChildren().iterator().next() ).setDescription( "child's new description" );
+ p.addChild( new Node( "second child" ) );
+ scope.inTransaction(
+ session ->
+ session.merge( p )
+ );
+ assertUpdateCount( 1, scope );
+ assertInsertCount( 1, scope );
+ ///////////////////////////////////////////////////////////////////////
+
+ cleanup( scope );
+ }
+
+ @Test
+ public void testNoExtraUpdatesOnMergeVersioned(SessionFactoryScope scope) {
+ VersionedEntity entity = new VersionedEntity( "entity", "entity" );
+ scope.inTransaction(
+ session ->
+ session.persist( entity )
+ );
+
+ clearCounts( scope );
+
+ // entity is now detached, but we have made no changes. so attempt to merge it
+ // into this new session; this should cause no updates...
+ VersionedEntity mergedEntity = scope.fromTransaction(
+ session ->
+ (VersionedEntity) session.merge( entity )
+ );
+
+ assertUpdateCount( 0, scope );
+ assertInsertCount( 0, scope );
+ assertThat( "unexpected version increment", mergedEntity.getVersion(), is( entity.getVersion() ) );
+
+
+ ///////////////////////////////////////////////////////////////////////
+ // as a control measure, now update the node while it is detached and
+ // make sure we get an update as a result...
+ entity.setName( "new name" );
+
+ scope.inTransaction(
+ session ->
+ session.merge( entity )
+ );
+ assertUpdateCount( 1, scope );
+ assertInsertCount( 0, scope );
+ ///////////////////////////////////////////////////////////////////////
+
+ cleanup( scope );
+ }
+
+ @Test
+ @SuppressWarnings({ "unchecked" })
+ public void testNoExtraUpdatesOnMergeVersionedWithCollection(SessionFactoryScope scope) {
+ VersionedEntity parent = new VersionedEntity( "parent", "parent" );
+ VersionedEntity child = new VersionedEntity( "child", "child" );
+ scope.inTransaction(
+ session -> {
+ parent.getChildren().add( child );
+ child.setParent( parent );
+ session.persist( parent );
+ }
+ );
+
+ clearCounts( scope );
+
+ // parent is now detached, but we have made no changes. so attempt to merge it
+ // into this new session; this should cause no updates...
+ VersionedEntity mergedParent =
+
+ scope.fromTransaction(
+ session ->
+ (VersionedEntity) session.merge( parent )
+ );
+
+ assertUpdateCount( 0, scope );
+ assertInsertCount( 0, scope );
+ assertThat( "unexpected parent version increment", mergedParent.getVersion(), is( parent.getVersion() ) );
+ VersionedEntity mergedChild = (VersionedEntity) mergedParent.getChildren().iterator().next();
+ assertThat( "unexpected child version increment", mergedChild.getVersion(), is( child.getVersion() ) );
+
+ ///////////////////////////////////////////////////////////////////////
+ // as a control measure, now update the node while it is detached and
+ // make sure we get an update as a result...
+ mergedParent.setName( "new name" );
+ mergedParent.getChildren().add( new VersionedEntity( "child2", "new child" ) );
+
+ scope.inTransaction(
+ session ->
+ session.merge( mergedParent )
+ );
+
+ assertUpdateCount( 1, scope );
+ assertInsertCount( 1, scope );
+ ///////////////////////////////////////////////////////////////////////
+
+ cleanup( scope );
+ }
+
+ @Test
+ @SuppressWarnings({ "unchecked", "UnusedAssignment", "UnusedDeclaration" })
+ public void testNoExtraUpdatesOnPersistentMergeVersionedWithCollection(SessionFactoryScope scope) {
+ VersionedEntity parent = new VersionedEntity( "parent", "parent" );
+ VersionedEntity child = new VersionedEntity( "child", "child" );
+ scope.inTransaction(
+ session -> {
+ parent.getChildren().add( child );
+ child.setParent( parent );
+ session.persist( parent );
+ }
+ );
+
+ clearCounts( scope );
+
+ // parent is now detached, but we have made no changes. so attempt to merge it
+ // into this new session; this should cause no updates...
+ VersionedEntity mergedParent = scope.fromTransaction(
+ session -> {
+ // load parent so that merge will follow entityIsPersistent path
+ VersionedEntity persistentParent = session.get(
+ VersionedEntity.class,
+ parent.getId()
+ );
+ // load children
+ VersionedEntity persistentChild = (VersionedEntity) persistentParent.getChildren()
+ .iterator()
+ .next();
+ return (VersionedEntity) session.merge( persistentParent ); // <-- This merge leads to failure
+ }
+ );
+
+ assertUpdateCount( 0, scope );
+ assertInsertCount( 0, scope );
+ assertThat( "unexpected parent version increment", mergedParent.getVersion(), is( parent.getVersion() ) );
+ VersionedEntity mergedChild = (VersionedEntity) mergedParent.getChildren().iterator().next();
+ assertThat( "unexpected child version increment", mergedChild.getVersion(), is( child.getVersion() ) );
+
+ ///////////////////////////////////////////////////////////////////////
+ // as a control measure, now update the node once it is loaded and
+ // make sure we get an update as a result...
+ scope.inTransaction(
+ session -> {
+ VersionedEntity persistentParent = session.get(
+ VersionedEntity.class,
+ parent.getId()
+ );
+ persistentParent.setName( "new name" );
+ persistentParent.getChildren().add( new VersionedEntity( "child2", "new child" ) );
+ persistentParent = (VersionedEntity) session.merge( persistentParent );
+
+ }
+ );
+ assertUpdateCount( 1, scope );
+ assertInsertCount( 1, scope );
+ ///////////////////////////////////////////////////////////////////////
+
+ // cleanup();
+ }
+
+ @Test
+ public void testPersistThenMergeInSameTxnWithVersion(SessionFactoryScope scope) {
+ scope.inTransaction(
+ session -> {
+
+ VersionedEntity entity = new VersionedEntity( "test", "test" );
+ session.persist( entity );
+ session.merge( new VersionedEntity( "test", "test-2" ) );
+
+ try {
+ // control operation...
+ session.saveOrUpdate( new VersionedEntity( "test", "test-3" ) );
+ fail( "saveOrUpdate() should fail here" );
+ }
+ catch (NonUniqueObjectException expected) {
+ // expected behavior
+ }
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @Test
+ public void testPersistThenMergeInSameTxnWithTimestamp(SessionFactoryScope scope) {
+ scope.inTransaction(
+ session -> {
+ TimestampedEntity entity = new TimestampedEntity( "test", "test" );
+ session.persist( entity );
+ session.merge( new TimestampedEntity( "test", "test-2" ) );
+
+ try {
+ // control operation...
+ session.saveOrUpdate( new TimestampedEntity( "test", "test-3" ) );
+ fail( "saveOrUpdate() should fail here" );
+ }
+ catch (NonUniqueObjectException expected) {
+ // expected behavior
+ }
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @Test
+ public void testMergeDeepTree(SessionFactoryScope scope) {
+ clearCounts( scope );
+
+ Node root = new Node( "root" );
+ Node grandchild = new Node( "grandchild" );
+ Node child = new Node( "child" );
+ scope.inTransaction(
+ session -> {
+ root.addChild( child );
+ child.addChild( grandchild );
+ session.merge( root );
+ }
+ );
+
+
+ assertInsertCount( 3, scope );
+ assertUpdateCount( 0, scope );
+ clearCounts( scope );
+
+ grandchild.setDescription( "the grand child" );
+ Node grandchild2 = new Node( "grandchild2" );
+ child.addChild( grandchild2 );
+
+ scope.inTransaction(
+ session ->
+ session.merge( root )
+ );
+
+ assertInsertCount( 1, scope );
+ assertUpdateCount( 1, scope );
+ clearCounts( scope );
+
+ Node child2 = new Node( "child2" );
+ Node grandchild3 = new Node( "grandchild3" );
+ child2.addChild( grandchild3 );
+ root.addChild( child2 );
+
+ scope.inTransaction(
+ session ->
+ session.merge( root )
+ );
+
+ assertInsertCount( 2, scope );
+ assertUpdateCount( 0, scope );
+ clearCounts( scope );
+
+ scope.inTransaction(
+ session -> {
+ session.delete( grandchild );
+ session.delete( grandchild2 );
+ session.delete( grandchild3 );
+ session.delete( child );
+ session.delete( child2 );
+ session.delete( root );
+ }
+ );
+ }
+
+ @Test
+ public void testMergeDeepTreeWithGeneratedId(SessionFactoryScope scope) {
+ clearCounts( scope );
+
+ NumberedNode root = scope.fromTransaction(
+ session -> {
+ NumberedNode r = new NumberedNode( "root" );
+ NumberedNode child = new NumberedNode( "child" );
+ NumberedNode grandchild = new NumberedNode( "grandchild" );
+ r.addChild( child );
+ child.addChild( grandchild );
+ return (NumberedNode) session.merge( r );
+ }
+ );
+
+ assertInsertCount( 3, scope );
+ assertUpdateCount( 0, scope );
+ clearCounts( scope );
+
+ NumberedNode child = (NumberedNode) root.getChildren().iterator().next();
+ NumberedNode grandchild = (NumberedNode) child.getChildren().iterator().next();
+ grandchild.setDescription( "the grand child" );
+ NumberedNode grandchild2 = new NumberedNode( "grandchild2" );
+ child.addChild( grandchild2 );
+
+ NumberedNode node = scope.fromTransaction(
+ session ->
+ (NumberedNode) session.merge( root )
+ );
+
+ assertInsertCount( 1, scope );
+ assertUpdateCount( 1, scope );
+ clearCounts( scope );
+
+ scope.getSessionFactory().getCache().evictEntityRegion( NumberedNode.class );
+
+ NumberedNode child2 = new NumberedNode( "child2" );
+ NumberedNode grandchild3 = new NumberedNode( "grandchild3" );
+ child2.addChild( grandchild3 );
+ node.addChild( child2 );
+
+ scope.inTransaction(
+ session ->
+ session.merge( node )
+ );
+
+ assertInsertCount( 2, scope );
+ assertUpdateCount( 0, scope );
+ clearCounts( scope );
+
+ scope.inTransaction(
+ session -> {
+ session.createQuery( "delete from NumberedNode where name like 'grand%'" ).executeUpdate();
+ session.createQuery( "delete from NumberedNode where name like 'child%'" ).executeUpdate();
+ session.createQuery( "delete from NumberedNode" ).executeUpdate();
+ }
+ );
+ }
+
+ @Test
+ public void testMergeTree(SessionFactoryScope scope) {
+ clearCounts( scope );
+
+ Node root = new Node( "root" );
+ Node child = new Node( "child" );
+ scope.inTransaction(
+ session -> {
+ root.addChild( child );
+ session.persist( root );
+ }
+ );
+
+ assertInsertCount( 2, scope );
+ clearCounts( scope );
+
+ root.setDescription( "The root node" );
+ child.setDescription( "The child node" );
+
+ Node secondChild = new Node( "second child" );
+
+ root.addChild( secondChild );
+
+ scope.inTransaction(
+ session ->
+ session.merge( root )
+ );
+
+ assertInsertCount( 1, scope );
+ assertUpdateCount( 2, scope );
+
+ cleanup( scope );
+ }
+
+ @Test
+ public void testMergeTreeWithGeneratedId(SessionFactoryScope scope) {
+ clearCounts( scope );
+
+ NumberedNode root = new NumberedNode( "root" );
+ NumberedNode child = new NumberedNode( "child" );
+
+ scope.inTransaction(
+ session -> {
+ root.addChild( child );
+ session.persist( root );
+ }
+ );
+
+ assertInsertCount( 2, scope );
+ clearCounts( scope );
+
+ root.setDescription( "The root node" );
+ child.setDescription( "The child node" );
+
+ NumberedNode secondChild = new NumberedNode( "second child" );
+
+ root.addChild( secondChild );
+
+ scope.inTransaction(
+ session ->
+ session.merge( root )
+ );
+
+ assertInsertCount( 1, scope );
+ assertUpdateCount( 2, scope );
+
+ cleanup( scope );
+ }
+
+ @Test
+ public void testMergeManaged(SessionFactoryScope scope) {
+ scope.inTransaction(
+ session -> {
+ NumberedNode root = new NumberedNode( "root" );
+ session.persist( root );
+ session.getTransaction().commit();
+
+ clearCounts( scope );
+
+ session.beginTransaction();
+ NumberedNode child = new NumberedNode( "child" );
+ root.addChild( child );
+ assertSame( root, session.merge( root ) );
+ Object mergedChild = root.getChildren().iterator().next();
+ assertNotSame( mergedChild, child );
+ assertTrue( session.contains( mergedChild ) );
+ assertFalse( session.contains( child ) );
+ assertThat( root.getChildren().size(), is( 1 ) );
+ assertTrue( root.getChildren().contains( mergedChild ) );
+ //assertNotSame( mergedChild, s.merge(child) ); //yucky :(
+ session.getTransaction().commit();
+
+ assertInsertCount( 1, scope );
+ assertUpdateCount( 0, scope );
+
+ assertThat( root.getChildren().size(), is( 1 ) );
+ assertTrue( root.getChildren().contains( mergedChild ) );
+
+ session.beginTransaction();
+ assertThat(
+ getNumneredNodeRowCount( session ),
+ is( 2L )
+ );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ private Long getNumneredNodeRowCount(Session s) {
+ CriteriaBuilder criteriaBuilder = s.getCriteriaBuilder();
+ CriteriaQuery criteria = criteriaBuilder.createQuery( Long.class );
+ Root root = criteria.from( NumberedNode.class );
+ criteria.select( criteriaBuilder.count( root ) );
+ return s.createQuery( criteria ).uniqueResult();
+ }
+
+ @Test
+ public void testMergeManagedUninitializedCollection(SessionFactoryScope scope) {
+ NumberedNode root = new NumberedNode( "root" );
+ scope.inTransaction(
+ session -> {
+ root.addChild( new NumberedNode( "child" ) );
+ session.persist( root );
+ }
+ );
+
+ clearCounts( scope );
+
+ NumberedNode newRoot = new NumberedNode( "root" );
+ newRoot.setId( root.getId() );
+
+ scope.inTransaction(
+ session -> {
+ NumberedNode r = session.get( NumberedNode.class, root.getId() );
+ Set managedChildren = r.getChildren();
+ assertFalse( Hibernate.isInitialized( managedChildren ) );
+ newRoot.setChildren( managedChildren );
+ assertSame( r, session.merge( newRoot ) );
+ assertSame( managedChildren, r.getChildren() );
+ assertFalse( Hibernate.isInitialized( managedChildren ) );
+ session.getTransaction().commit();
+
+ assertInsertCount( 0, scope );
+ assertUpdateCount( 0, scope );
+ assertDeleteCount( 0, scope );
+
+ session.beginTransaction();
+ assertThat(
+ getNumneredNodeRowCount( session ),
+ is( 2L )
+ );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @Test
+ public void testMergeManagedInitializedCollection(SessionFactoryScope scope) {
+ NumberedNode r = new NumberedNode( "root" );
+ scope.inTransaction(
+ session -> {
+ r.addChild( new NumberedNode( "child" ) );
+ session.persist( r );
+ }
+ );
+
+ clearCounts( scope );
+
+ NumberedNode newRoot = new NumberedNode( "root" );
+ newRoot.setId( r.getId() );
+
+ scope.inTransaction(
+ session -> {
+ NumberedNode root = session.get( NumberedNode.class, r.getId() );
+ Set managedChildren = root.getChildren();
+ Hibernate.initialize( managedChildren );
+ assertTrue( Hibernate.isInitialized( managedChildren ) );
+ newRoot.setChildren( managedChildren );
+ assertSame( root, session.merge( newRoot ) );
+ assertSame( managedChildren, root.getChildren() );
+ assertTrue( Hibernate.isInitialized( managedChildren ) );
+ session.getTransaction().commit();
+
+ assertInsertCount( 0, scope );
+ assertUpdateCount( 0, scope );
+ assertDeleteCount( 0, scope );
+
+ session.beginTransaction();
+ assertThat(
+ getNumneredNodeRowCount( session ),
+ is( 2L )
+ );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @Test
+ @SuppressWarnings({ "unchecked" })
+ @SkipForDialect(dialectClass = AbstractHANADialect.class, reason = " HANA doesn't support tables consisting of only a single auto-generated column")
+ public void testRecursiveMergeTransient(SessionFactoryScope scope) {
+ scope.inTransaction(
+ session -> {
+ Employer jboss = new Employer();
+ Employee gavin = new Employee();
+ jboss.setEmployees( new ArrayList() );
+ jboss.getEmployees().add( gavin );
+ session.merge( jboss );
+ session.flush();
+ jboss = (Employer) session.createQuery( "from Employer e join fetch e.employees" ).uniqueResult();
+ assertTrue( Hibernate.isInitialized( jboss.getEmployees() ) );
+ assertThat( jboss.getEmployees().size(), is( 1 ) );
+ session.clear();
+ session.merge( jboss.getEmployees().iterator().next() );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @Test
+ public void testDeleteAndMerge(SessionFactoryScope scope) {
+ scope.inTransaction(
+ session -> {
+ Employer jboss = new Employer();
+ session.persist( jboss );
+ session.getTransaction().commit();
+ session.clear();
+
+ session.getTransaction().begin();
+ Employer otherJboss;
+ otherJboss = session.get( Employer.class, jboss.getId() );
+ session.delete( otherJboss );
+ session.getTransaction().commit();
+ session.clear();
+ jboss.setVers( 1 );
+ session.getTransaction().begin();
+ session.merge( jboss );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @SuppressWarnings({ "unchecked" })
+ @Test
+ @SkipForDialect(dialectClass = AbstractHANADialect.class, reason = " HANA doesn't support tables consisting of only a single auto-generated column")
+ public void testMergeManyToManyWithCollectionDeference(SessionFactoryScope scope) {
+ // setup base data...
+ Competition competition = new Competition();
+ scope.inTransaction(
+ session -> {
+ competition.getCompetitors().add( new Competitor( "Name" ) );
+ competition.getCompetitors().add( new Competitor() );
+ competition.getCompetitors().add( new Competitor() );
+ session.persist( competition );
+ }
+ );
+
+ // the competition graph is now detached:
+ // 1) create a new List reference to represent the competitors
+ Competition competition2 = scope.fromTransaction(
+ session -> {
+ List newComp = new ArrayList();
+ Competitor originalCompetitor = (Competitor) competition.getCompetitors().get( 0 );
+ originalCompetitor.setName( "Name2" );
+ newComp.add( originalCompetitor );
+ newComp.add( new Competitor() );
+ // 2) set that new List reference unto the Competition reference
+ competition.setCompetitors( newComp );
+ // 3) attempt the merge
+ return (Competition) session.merge( competition );
+ }
+ );
+
+ assertNotSame( competition, competition2 );
+ assertNotSame( competition.getCompetitors(), competition2.getCompetitors() );
+ assertThat( competition2.getCompetitors().size(), is( 2 ) );
+
+ scope.inTransaction(
+ session -> {
+ Competition c = session.get( Competition.class, competition.getId() );
+ assertThat( c.getCompetitors().size(), is( 2 ) );
+ session.delete( c );
+ }
+ );
+
+ cleanup( scope );
+ }
+
+ @AfterEach
+ private void cleanup(SessionFactoryScope scope) {
+ scope.inTransaction(
+ session -> {
+ session.createQuery( "delete from NumberedNode where parent is not null" ).executeUpdate();
+ session.createQuery( "delete from NumberedNode" ).executeUpdate();
+
+ session.createQuery( "delete from Node where parent is not null" ).executeUpdate();
+ session.createQuery( "delete from Node" ).executeUpdate();
+
+ session.createQuery( "delete from VersionedEntity where parent is not null" ).executeUpdate();
+ session.createQuery( "delete from VersionedEntity" ).executeUpdate();
+ session.createQuery( "delete from TimestampedEntity" ).executeUpdate();
+
+ session.createQuery( "delete from Competitor" ).executeUpdate();
+ session.createQuery( "delete from Competition" ).executeUpdate();
+
+ for ( Employer employer : (List) session.createQuery( "from Employer" ).list() ) {
+ session.delete( employer );
+ }
+ }
+ );
+
+ }
+}
+
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/Node.hbm.xml b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/Node.hbm.xml
similarity index 96%
rename from hibernate-core/src/test/java/org/hibernate/test/ops/Node.hbm.xml
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ops/Node.hbm.xml
index 3adc610b8d..dde682a0df 100755
--- a/hibernate-core/src/test/java/org/hibernate/test/ops/Node.hbm.xml
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/Node.hbm.xml
@@ -13,7 +13,7 @@
-->
-
+
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/Node.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/Node.java
similarity index 98%
rename from hibernate-core/src/test/java/org/hibernate/test/ops/Node.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ops/Node.java
index 3cc9542d33..1f72c655e3 100755
--- a/hibernate-core/src/test/java/org/hibernate/test/ops/Node.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/Node.java
@@ -6,7 +6,8 @@
*/
//$Id: Node.java 10759 2006-11-08 00:00:53Z steve.ebersole@jboss.com $
-package org.hibernate.test.ops;
+package org.hibernate.orm.test.ops;
+
import java.sql.Date;
import java.util.HashSet;
import java.util.Set;
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/NumberedNode.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/NumberedNode.java
similarity index 97%
rename from hibernate-core/src/test/java/org/hibernate/test/ops/NumberedNode.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ops/NumberedNode.java
index 2ed5b6b70a..a5d5e65ef7 100755
--- a/hibernate-core/src/test/java/org/hibernate/test/ops/NumberedNode.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/NumberedNode.java
@@ -6,7 +6,7 @@
*/
//$Id: NumberedNode.java 7236 2005-06-20 03:19:34Z oneovthafew $
-package org.hibernate.test.ops;
+package org.hibernate.orm.test.ops;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/OneToOne.hbm.xml b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/OneToOne.hbm.xml
similarity index 97%
rename from hibernate-core/src/test/java/org/hibernate/test/ops/OneToOne.hbm.xml
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ops/OneToOne.hbm.xml
index bfaf78c3ec..7d9637c782 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ops/OneToOne.hbm.xml
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/OneToOne.hbm.xml
@@ -17,7 +17,7 @@
Person -> Details is modeled as a bidirectional one to one based on PK.
-->
-
+
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/OneToOneMergeTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/OneToOneMergeTest.java
similarity index 58%
rename from hibernate-core/src/test/java/org/hibernate/test/ops/OneToOneMergeTest.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ops/OneToOneMergeTest.java
index 5d8e887309..695b869aec 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ops/OneToOneMergeTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/OneToOneMergeTest.java
@@ -4,7 +4,7 @@
* 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.ops;
+package org.hibernate.orm.test.ops;
import java.io.Serializable;
import javax.persistence.CascadeType;
@@ -17,54 +17,52 @@ import javax.persistence.JoinColumn;
import javax.persistence.MapsId;
import javax.persistence.OneToOne;
-import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
-
import org.hibernate.testing.TestForIssue;
-import org.junit.Test;
+import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
+import org.hibernate.testing.orm.junit.Jpa;
+import org.junit.jupiter.api.Test;
-import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
-import static org.junit.Assert.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
/**
- *
* @author localEvg
*/
-@TestForIssue( jiraKey = "HHH-12436" )
-public class OneToOneMergeTest extends BaseEntityManagerFunctionalTestCase {
-
- @Override
- public Class>[] getAnnotatedClasses() {
- return new Class[]{
- Prima.class,
- Secunda.class
- };
- }
+@TestForIssue(jiraKey = "HHH-12436")
+@Jpa(
+ annotatedClasses = {
+ OneToOneMergeTest.Prima.class,
+ OneToOneMergeTest.Secunda.class
+ }
+)
+public class OneToOneMergeTest {
@Test
- public void testMerge() throws Exception {
+ public void testMerge(EntityManagerFactoryScope scope) throws Exception {
- Long primaId = doInJPA( this::entityManagerFactory, entityManager -> {
- Prima prima = new Prima();
- prima.setOptionalData(null);
+ Long primaId = scope.fromTransaction(
+ entityManager -> {
+ Prima prima = new Prima();
+ prima.setOptionalData( null );
- entityManager.persist(prima);
+ entityManager.persist( prima );
- return prima.getId();
- } );
+ return prima.getId();
+ } );
- assertNotNull(primaId);
+ assertNotNull( primaId );
- doInJPA( this::entityManagerFactory, entityManager -> {
- Prima prima = entityManager.find( Prima.class, primaId );
+ scope.inTransaction(
+ entityManager -> {
+ Prima prima = entityManager.find( Prima.class, primaId );
- Secunda sec = new Secunda();
- sec.setParent(prima);
- prima.setOptionalData(sec);
+ Secunda sec = new Secunda();
+ sec.setParent( prima );
+ prima.setOptionalData( sec );
- Prima mergedPrima = entityManager.merge(prima);
+ Prima mergedPrima = entityManager.merge( prima );
- assertNotNull(mergedPrima);
- } );
+ assertNotNull( mergedPrima );
+ } );
}
@@ -76,7 +74,7 @@ public class OneToOneMergeTest extends BaseEntityManagerFunctionalTestCase {
private Long id;
//@PrimaryKeyJoinColumn
- @OneToOne(mappedBy = "parent", optional = true , cascade = CascadeType.ALL)
+ @OneToOne(mappedBy = "parent", optional = true, cascade = CascadeType.ALL)
private Secunda optionalData;
public Long getId() {
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/OptLockEntity.hbm.xml b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/OptLockEntity.hbm.xml
similarity index 95%
rename from hibernate-core/src/test/java/org/hibernate/test/ops/OptLockEntity.hbm.xml
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ops/OptLockEntity.hbm.xml
index 57ab878b35..a6720b7ab0 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ops/OptLockEntity.hbm.xml
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/OptLockEntity.hbm.xml
@@ -13,7 +13,7 @@
-->
-
+
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/ops/OracleNoColumnInsertTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/OracleNoColumnInsertTest.java
new file mode 100644
index 0000000000..a2c75c90bb
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/OracleNoColumnInsertTest.java
@@ -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 .
+ */
+package org.hibernate.orm.test.ops;
+
+import org.hibernate.dialect.OracleDialect;
+
+import org.hibernate.testing.TestForIssue;
+import org.hibernate.testing.orm.junit.DomainModel;
+import org.hibernate.testing.orm.junit.RequiresDialect;
+import org.hibernate.testing.orm.junit.SessionFactory;
+import org.hibernate.testing.orm.junit.SessionFactoryScope;
+import org.junit.jupiter.api.Test;
+
+/**
+ * @author Vlad Mihalcea
+ */
+@RequiresDialect(value = OracleDialect.class, version = 900)
+@TestForIssue(jiraKey = "HHH-13104")
+@DomainModel(
+ xmlMappings = "org/hibernate/orm/test/ops/Competition.hbm.xml"
+)
+@SessionFactory
+public class OracleNoColumnInsertTest {
+
+ @Test
+ public void test(SessionFactoryScope scope) throws Exception {
+ scope.inTransaction( session -> {
+ Competition competition = new Competition();
+
+ session.persist( competition );
+ } );
+ }
+}
+
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/Person.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/Person.java
similarity index 96%
rename from hibernate-core/src/test/java/org/hibernate/test/ops/Person.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ops/Person.java
index bcc6b2e1d6..782f1f6b2a 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ops/Person.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/Person.java
@@ -4,7 +4,7 @@
* 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.ops;
+package org.hibernate.orm.test.ops;
/**
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/PersonalDetails.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/PersonalDetails.java
similarity index 96%
rename from hibernate-core/src/test/java/org/hibernate/test/ops/PersonalDetails.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ops/PersonalDetails.java
index 1af858b6a5..af9266d944 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ops/PersonalDetails.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/PersonalDetails.java
@@ -4,7 +4,7 @@
* 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.ops;
+package org.hibernate.orm.test.ops;
/**
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/RemoveOrderingTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/RemoveOrderingTest.java
similarity index 58%
rename from hibernate-core/src/test/java/org/hibernate/test/ops/RemoveOrderingTest.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ops/RemoveOrderingTest.java
index 81a0b4d332..3a43994219 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ops/RemoveOrderingTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/RemoveOrderingTest.java
@@ -4,7 +4,7 @@
* 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.ops;
+package org.hibernate.orm.test.ops;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
@@ -15,49 +15,43 @@ import javax.persistence.Table;
import org.hibernate.Session;
-import org.junit.Test;
-
-import org.hibernate.testing.FailureExpected;
import org.hibernate.testing.TestForIssue;
-import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
+import org.hibernate.testing.orm.junit.DomainModel;
+import org.hibernate.testing.orm.junit.FailureExpected;
+import org.hibernate.testing.orm.junit.SessionFactoryScope;
+import org.junit.jupiter.api.Test;
/**
* @author Steve Ebersole
*/
-public class RemoveOrderingTest extends BaseCoreFunctionalTestCase {
- @Override
- protected Class>[] getAnnotatedClasses() {
- return new Class[] { Company.class, Person.class };
- }
+@DomainModel(
+ annotatedClasses = { RemoveOrderingTest.Company.class, RemoveOrderingTest.Person.class }
+)
+public class RemoveOrderingTest {
@Test
@TestForIssue( jiraKey = "HHH-8550" )
@FailureExpected( jiraKey = "HHH-8550" )
- public void testManyToOne() throws Exception {
- Session session = openSession();
- session.beginTransaction();
- try {
- Company company = new Company( 1, "acme" );
- Person person = new Person( 1, "joe", company );
- session.persist( person );
- session.flush();
+ public void testManyToOne(SessionFactoryScope scope) throws Exception {
+ scope.inTransaction(
+ session -> {
+ Company company = new Company( 1, "acme" );
+ Person person = new Person( 1, "joe", company );
+ session.persist( person );
+ session.flush();
- company = person.employer;
+ company = person.employer;
- session.delete( company );
- session.delete( person );
- session.flush();
+ session.delete( company );
+ session.delete( person );
+ session.flush();
- session.persist( person );
- session.flush();
+ session.persist( person );
+ session.flush();
- session.getTransaction().commit();
- }
- catch (Exception e) {
- session.getTransaction().rollback();
- throw e;
- }
- session.close();
+ session.getTransaction().commit();
+ }
+ );
}
@Entity( name="Company" )
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/ops/SaveOrUpdateTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/SaveOrUpdateTest.java
new file mode 100755
index 0000000000..f3ab91c6b1
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/SaveOrUpdateTest.java
@@ -0,0 +1,533 @@
+/*
+ * 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.orm.test.ops;
+
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Root;
+
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.Session;
+import org.hibernate.cfg.AvailableSettings;
+import org.hibernate.engine.spi.PersistentAttributeInterceptable;
+
+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.hibernate.testing.orm.junit.Setting;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+/**
+ * @author Gavin King
+ */
+@DomainModel(
+ xmlMappings = "org/hibernate/orm/test/ops/Node.hbm.xml",
+ concurrencyStrategy = "nonstrict-read-write"
+)
+@SessionFactory(
+ generateStatistics = true
+)
+@ServiceRegistry(
+ settings = @Setting(name = AvailableSettings.STATEMENT_BATCH_SIZE, value = "0")
+)
+public class SaveOrUpdateTest {
+
+ @Test
+ public void testSaveOrUpdateDeepTree(SessionFactoryScope scope) {
+ clearCounts( scope );
+
+ Node root = new Node( "root" );
+ Node child = new Node( "child" );
+ Node grandchild = new Node( "grandchild" );
+
+ scope.inTransaction(
+ session -> {
+ root.addChild( child );
+ child.addChild( grandchild );
+ session.saveOrUpdate( root );
+ }
+ );
+
+ assertInsertCount( 3, scope );
+ assertUpdateCount( 0, scope );
+ clearCounts( scope );
+
+ grandchild.setDescription( "the grand child" );
+ Node grandchild2 = new Node( "grandchild2" );
+ child.addChild( grandchild2 );
+
+ scope.inTransaction(
+ session ->
+ session.saveOrUpdate( root )
+ );
+
+ assertInsertCount( 1, scope );
+ assertUpdateCount( 1, scope );
+ clearCounts( scope );
+
+ Node child2 = new Node( "child2" );
+ Node grandchild3 = new Node( "grandchild3" );
+ child2.addChild( grandchild3 );
+ root.addChild( child2 );
+
+ scope.inTransaction(
+ session ->
+ session.saveOrUpdate( root )
+ );
+
+ assertInsertCount( 2, scope );
+ assertUpdateCount( 0, scope );
+ clearCounts( scope );
+
+ scope.inTransaction(
+ session -> {
+ session.delete( grandchild );
+ session.delete( grandchild2 );
+ session.delete( grandchild3 );
+ session.delete( child );
+ session.delete( child2 );
+ session.delete( root );
+ }
+ );
+ }
+
+ @Test
+ public void testSaveOrUpdateDeepTreeWithGeneratedId(SessionFactoryScope scope) {
+ boolean instrumented = PersistentAttributeInterceptable.class.isAssignableFrom( NumberedNode.class );
+ clearCounts( scope );
+
+ NumberedNode root = new NumberedNode( "root" );
+ NumberedNode c = new NumberedNode( "child" );
+ NumberedNode gc = new NumberedNode( "grandchild" );
+ scope.inTransaction(
+ session -> {
+ root.addChild( c );
+ c.addChild( gc );
+ session.saveOrUpdate( root );
+ }
+ );
+
+ assertInsertCount( 3, scope );
+ assertUpdateCount( 0, scope );
+ clearCounts( scope );
+
+ NumberedNode child = (NumberedNode) root.getChildren().iterator().next();
+ NumberedNode grandchild = (NumberedNode) child.getChildren().iterator().next();
+ grandchild.setDescription( "the grand child" );
+ NumberedNode grandchild2 = new NumberedNode( "grandchild2" );
+ child.addChild( grandchild2 );
+
+ scope.inTransaction(
+ session ->
+ session.saveOrUpdate( root )
+ );
+
+ assertInsertCount( 1, scope );
+ assertUpdateCount( instrumented ? 1 : 3, scope );
+ clearCounts( scope );
+
+ NumberedNode child2 = new NumberedNode( "child2" );
+ NumberedNode grandchild3 = new NumberedNode( "grandchild3" );
+ child2.addChild( grandchild3 );
+ root.addChild( child2 );
+
+ scope.inTransaction(
+ session ->
+ session.saveOrUpdate( root )
+ );
+
+ assertInsertCount( 2, scope );
+ assertUpdateCount( instrumented ? 0 : 4, scope );
+ clearCounts( scope );
+
+ scope.inTransaction(
+ session -> {
+ session.createQuery( "delete from NumberedNode where name like 'grand%'" ).executeUpdate();
+ session.createQuery( "delete from NumberedNode where name like 'child%'" ).executeUpdate();
+ session.createQuery( "delete from NumberedNode" ).executeUpdate();
+ }
+ );
+ }
+
+ @Test
+ public void testSaveOrUpdateTree(SessionFactoryScope scope) {
+ clearCounts( scope );
+
+ Node root = new Node( "root" );
+ Node child = new Node( "child" );
+ scope.inTransaction(
+ session -> {
+ root.addChild( child );
+ session.saveOrUpdate( root );
+ }
+ );
+
+ assertInsertCount( 2, scope );
+ clearCounts( scope );
+
+ root.setDescription( "The root node" );
+ child.setDescription( "The child node" );
+
+ Node secondChild = new Node( "second child" );
+
+ root.addChild( secondChild );
+
+ scope.inTransaction(
+ session ->
+ session.saveOrUpdate( root )
+ );
+
+ assertInsertCount( 1, scope );
+ assertUpdateCount( 2, scope );
+
+ scope.inTransaction(
+ session -> {
+ session.createQuery( "delete from Node where parent is not null" ).executeUpdate();
+ session.createQuery( "delete from Node" ).executeUpdate();
+ }
+ );
+ }
+
+ @Test
+ public void testSaveOrUpdateTreeWithGeneratedId(SessionFactoryScope scope) {
+ clearCounts( scope );
+
+ NumberedNode root = new NumberedNode( "root" );
+ NumberedNode child = new NumberedNode( "child" );
+ scope.inTransaction(
+ session -> {
+ root.addChild( child );
+ session.saveOrUpdate( root );
+ }
+ );
+
+ assertInsertCount( 2, scope );
+ clearCounts( scope );
+
+ root.setDescription( "The root node" );
+ child.setDescription( "The child node" );
+
+ NumberedNode secondChild = new NumberedNode( "second child" );
+
+ root.addChild( secondChild );
+
+ scope.inTransaction(
+ session ->
+ session.saveOrUpdate( root )
+ );
+
+ assertInsertCount( 1, scope );
+ assertUpdateCount( 2, scope );
+
+ scope.inTransaction(
+ session -> {
+ session.createQuery( "delete from NumberedNode where parent is not null" ).executeUpdate();
+ session.createQuery( "delete from NumberedNode" ).executeUpdate();
+ }
+ );
+ }
+
+ @Test
+ public void testSaveOrUpdateManaged(SessionFactoryScope scope) {
+ scope.inTransaction(
+ session -> {
+ NumberedNode root = new NumberedNode( "root" );
+ session.saveOrUpdate( root );
+
+ session.getTransaction().commit();
+
+ session.beginTransaction();
+ NumberedNode child = new NumberedNode( "child" );
+ root.addChild( child );
+ session.saveOrUpdate( root );
+ assertFalse( session.contains( child ) );
+ session.flush();
+ assertTrue( session.contains( child ) );
+ session.getTransaction().commit();
+
+ assertTrue( root.getChildren().contains( child ) );
+ assertThat( root.getChildren().size(), is( 1 ) );
+
+ session.beginTransaction();
+ assertThat(
+ getRowCount( session, NumberedNode.class ),
+ is( 2L )
+ );
+ session.delete( root );
+ session.delete( child );
+ }
+ );
+ }
+
+ @Test
+ public void testSaveOrUpdateGot(SessionFactoryScope scope) {
+ clearCounts( scope );
+
+ boolean instrumented = PersistentAttributeInterceptable.class.isAssignableFrom( NumberedNode.class );
+
+ NumberedNode root = new NumberedNode( "root" );
+ scope.inTransaction(
+ session ->
+ session.saveOrUpdate( root )
+ );
+
+ assertInsertCount( 1, scope );
+ assertUpdateCount( 0, scope );
+ clearCounts( scope );
+
+ scope.inTransaction(
+ session ->
+ session.saveOrUpdate( root )
+ );
+
+ assertInsertCount( 0, scope );
+ assertUpdateCount( instrumented ? 0 : 1, scope );
+
+ NumberedNode r = scope.fromTransaction(
+ session -> {
+ NumberedNode r1 = session.get( NumberedNode.class, root.getId() );
+ Hibernate.initialize( r1.getChildren() );
+ return r1;
+ }
+ );
+
+ clearCounts( scope );
+
+ scope.inTransaction(
+ session -> {
+ NumberedNode child = new NumberedNode( "child" );
+ r.addChild( child );
+ session.saveOrUpdate( r );
+ assertTrue( session.contains( child ) );
+ session.getTransaction().commit();
+
+ assertInsertCount( 1, scope );
+ assertUpdateCount( instrumented ? 0 : 1, scope );
+
+ session.beginTransaction();
+ assertThat(
+ getRowCount( session, NumberedNode.class ),
+ is( 2L )
+ );
+ session.delete( r );
+ session.delete( child );
+ }
+ );
+ }
+
+ @Test
+ public void testSaveOrUpdateGotWithMutableProp(SessionFactoryScope scope) {
+ clearCounts( scope );
+
+ Node root = new Node( "root" );
+ scope.inTransaction(
+ session ->
+ session.saveOrUpdate( root )
+ );
+
+ assertInsertCount( 1, scope );
+ assertUpdateCount( 0, scope );
+ clearCounts( scope );
+
+ scope.inTransaction(
+ session ->
+ session.saveOrUpdate( root )
+ );
+
+ assertInsertCount( 0, scope );
+ assertUpdateCount( 0, scope );
+
+ Node root1 = scope.fromTransaction(
+ session -> {
+ Node r1 = session.get( Node.class, "root" );
+ Hibernate.initialize( r1.getChildren() );
+ return r1;
+ }
+ );
+
+ clearCounts( scope );
+
+ scope.inTransaction(
+ session -> {
+ Node child = new Node( "child" );
+ root1.addChild( child );
+ session.saveOrUpdate( root1 );
+ assertTrue( session.contains( child ) );
+ session.getTransaction().commit();
+
+ assertInsertCount( 1, scope );
+ assertUpdateCount( 1, scope ); //note: will fail here if no second-level cache
+
+ session.beginTransaction();
+ assertThat(
+ getRowCount( session, Node.class ),
+ is( 2L )
+ );
+ session.delete( root1 );
+ session.delete( child );
+ }
+ );
+ }
+
+ @Test
+ public void testEvictThenSaveOrUpdate(SessionFactoryScope scope) {
+ scope.inTransaction(
+ session -> {
+ Node parent = new Node( "1:parent" );
+ Node child = new Node( "2:child" );
+ Node grandchild = new Node( "3:grandchild" );
+ parent.addChild( child );
+ child.addChild( grandchild );
+ session.saveOrUpdate( parent );
+ }
+ );
+
+
+ Session s1 = scope.getSessionFactory().openSession();
+ Session s2 = null;
+ try {
+ s1.getTransaction().begin();
+ Node child = s1.load( Node.class, "2:child" );
+ assertTrue( s1.contains( child ) );
+ assertFalse( Hibernate.isInitialized( child ) );
+ assertTrue( s1.contains( child.getParent() ) );
+ assertTrue( Hibernate.isInitialized( child ) );
+ assertFalse( Hibernate.isInitialized( child.getChildren() ) );
+ assertFalse( Hibernate.isInitialized( child.getParent() ) );
+ assertTrue( s1.contains( child ) );
+ s1.evict( child );
+ assertFalse( s1.contains( child ) );
+ assertTrue( s1.contains( child.getParent() ) );
+
+ s2 = scope.getSessionFactory().openSession();
+ try {
+ s2.getTransaction().begin();
+ s2.saveOrUpdate( child );
+ fail();
+ }
+ catch (HibernateException ex) {
+ // expected because parent is connected to s1
+ }
+ finally {
+ s2.getTransaction().rollback();
+ }
+ s2.close();
+
+ s1.evict( child.getParent() );
+ assertFalse( s1.contains( child.getParent() ) );
+
+ s2 = scope.getSessionFactory().openSession();
+ s2.getTransaction().begin();
+ s2.saveOrUpdate( child );
+ assertTrue( s2.contains( child ) );
+ assertFalse( s1.contains( child ) );
+ assertTrue( s2.contains( child.getParent() ) );
+ assertFalse( s1.contains( child.getParent() ) );
+ assertFalse( Hibernate.isInitialized( child.getChildren() ) );
+ assertFalse( Hibernate.isInitialized( child.getParent() ) );
+ assertThat( child.getChildren().size(), is( 1 ) );
+ assertThat( child.getParent().getName(), is( "1:parent" ) );
+ assertTrue( Hibernate.isInitialized( child.getChildren() ) );
+ assertFalse( Hibernate.isInitialized( child.getParent() ) );
+ assertNull( child.getParent().getDescription() );
+ assertTrue( Hibernate.isInitialized( child.getParent() ) );
+
+ s1.getTransaction().commit();
+ s2.getTransaction().commit();
+ }
+ finally {
+ if ( s1.getTransaction().isActive() ) {
+ s1.getTransaction().rollback();
+ }
+ s1.close();
+ if ( s2 != null ) {
+ if ( s2.getTransaction().isActive() ) {
+ s1.getTransaction().rollback();
+ }
+ s2.close();
+ }
+ }
+
+ scope.inTransaction(
+ session -> {
+ session.delete( session.get( Node.class, "3:grandchild" ) );
+ session.delete( session.get( Node.class, "2:child" ) );
+ session.delete( session.get( Node.class, "1:parent" ) );
+ }
+ );
+ }
+
+ @Test
+ public void testSavePersistentEntityWithUpdate(SessionFactoryScope scope) {
+ clearCounts( scope );
+
+ NumberedNode root = new NumberedNode( "root" );
+ root.setName( "a name" );
+ scope.inTransaction(
+ session ->
+ session.saveOrUpdate( root )
+ );
+
+ assertInsertCount( 1, scope );
+ assertUpdateCount( 0, scope );
+ clearCounts( scope );
+
+ NumberedNode r = scope.fromTransaction(
+ session -> {
+ NumberedNode node = session.get( NumberedNode.class, root.getId() );
+ assertThat( node.getName(), is( "a name" ) );
+ node.setName( "a new name" );
+ session.save( node );
+ return node;
+ }
+ );
+
+ assertInsertCount( 0, scope );
+ assertUpdateCount( 1, scope );
+ clearCounts( scope );
+
+ scope.inTransaction(
+ session -> {
+ NumberedNode node = session.get( NumberedNode.class, r.getId() );
+ assertThat( node.getName(), is( "a new name" ) );
+ session.delete( node );
+ }
+ );
+ }
+
+ private Long getRowCount(Session s, Class clazz) {
+ CriteriaBuilder criteriaBuilder = s.getCriteriaBuilder();
+ CriteriaQuery criteria = criteriaBuilder.createQuery( Long.class );
+ Root root = criteria.from( clazz );
+ criteria.select( criteriaBuilder.count( root ) );
+ return s.createQuery( criteria ).uniqueResult();
+ }
+
+ private void clearCounts(SessionFactoryScope scope) {
+ scope.getSessionFactory().getStatistics().clear();
+ }
+
+ private void assertInsertCount(int count, SessionFactoryScope scope) {
+ int inserts = (int) scope.getSessionFactory().getStatistics().getEntityInsertCount();
+ assertThat( inserts, is( count ) );
+ }
+
+ private void assertUpdateCount(int count, SessionFactoryScope scope) {
+ int updates = (int) scope.getSessionFactory().getStatistics().getEntityUpdateCount();
+ assertThat( updates, is( count ) );
+ }
+}
+
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/SimpleEntity.hbm.xml b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/SimpleEntity.hbm.xml
similarity index 91%
rename from hibernate-core/src/test/java/org/hibernate/test/ops/SimpleEntity.hbm.xml
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ops/SimpleEntity.hbm.xml
index a9e7e542ab..764ce636a8 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ops/SimpleEntity.hbm.xml
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/SimpleEntity.hbm.xml
@@ -10,7 +10,7 @@
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
-
+
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/SimpleEntity.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/SimpleEntity.java
similarity index 94%
rename from hibernate-core/src/test/java/org/hibernate/test/ops/SimpleEntity.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ops/SimpleEntity.java
index 4a4eda4a92..56d682e4d6 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ops/SimpleEntity.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/SimpleEntity.java
@@ -4,7 +4,7 @@
* 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.ops;
+package org.hibernate.orm.test.ops;
/**
* @author Steve Ebersole
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/ops/SimpleOpsTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/SimpleOpsTest.java
new file mode 100755
index 0000000000..6b0814ab0d
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/SimpleOpsTest.java
@@ -0,0 +1,110 @@
+/*
+ * 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.orm.test.ops;
+
+import org.hibernate.Hibernate;
+
+import org.hibernate.testing.orm.junit.DomainModel;
+import org.hibernate.testing.orm.junit.SessionFactoryScope;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * @author Gail Badner
+ */
+@DomainModel(
+ xmlMappings = "org/hibernate/orm/test/ops/SimpleEntity.hbm.xml"
+)
+public class SimpleOpsTest extends AbstractOperationTestCase {
+
+ public String[] getMappings() {
+ return new String[] {};
+ }
+
+ @Test
+ public void testBasicOperations(SessionFactoryScope scope) {
+ clearCounts( scope );
+
+ Long id = 1L;
+ scope.inTransaction(
+ session -> {
+ SimpleEntity entity = new SimpleEntity();
+ entity.setId( id );
+ entity.setName( "name" );
+ session.save( entity );
+ }
+ );
+
+ assertInsertCount( 1, scope );
+ assertUpdateCount( 0, scope );
+ assertDeleteCount( 0, scope );
+
+ clearCounts( scope );
+
+ scope.inTransaction(
+ session -> {
+ SimpleEntity entity = session.get( SimpleEntity.class, id );
+ assertThat( entity.getId(), is( 1L ) );
+ assertThat( entity.getName(), is( "name" ) );
+ entity.setName( "new name" );
+ }
+ );
+
+ assertInsertCount( 0, scope );
+ assertUpdateCount( 1, scope );
+ assertDeleteCount( 0, scope );
+
+ clearCounts( scope );
+
+ SimpleEntity simpleEntity = scope.fromTransaction(
+ session -> {
+ SimpleEntity entity = session.load( SimpleEntity.class, id );
+ assertFalse( Hibernate.isInitialized( entity ) );
+ assertThat( entity.getId(), is( 1L ) );
+ assertThat( entity.getName(), is( "new name" ) );
+ assertTrue( Hibernate.isInitialized( entity ) );
+ return entity;
+ }
+ );
+
+ assertInsertCount( 0, scope );
+ assertUpdateCount( 0, scope );
+ assertDeleteCount( 0, scope );
+
+ simpleEntity.setName( "another new name" );
+
+ scope.inTransaction(
+ session ->
+ session.merge( simpleEntity )
+ );
+
+
+ assertInsertCount( 0, scope );
+ assertUpdateCount( 1, scope );
+ assertDeleteCount( 0, scope );
+
+ clearCounts( scope );
+
+ scope.inTransaction(
+ session -> {
+ SimpleEntity entity = session.get( SimpleEntity.class, id );
+ assertThat( entity.getId(), is( 1L ) );
+ assertThat( entity.getName(), is( "another new name" ) );
+ session.delete( entity );
+ }
+ );
+
+ assertInsertCount( 0, scope );
+ assertUpdateCount( 0, scope );
+ assertDeleteCount( 1, scope );
+ }
+}
+
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/SubCategory.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/SubCategory.java
similarity index 96%
rename from hibernate-core/src/test/java/org/hibernate/test/ops/SubCategory.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ops/SubCategory.java
index 7574d0d380..5b39f1bdfa 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ops/SubCategory.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/SubCategory.java
@@ -4,7 +4,7 @@
* 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.ops;
+package org.hibernate.orm.test.ops;
/**
* @author Gail Badner
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/SubItem.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/SubItem.java
similarity index 96%
rename from hibernate-core/src/test/java/org/hibernate/test/ops/SubItem.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ops/SubItem.java
index 6dbe8bce3e..fc849f65a7 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ops/SubItem.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/SubItem.java
@@ -4,7 +4,7 @@
* 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.ops;
+package org.hibernate.orm.test.ops;
/**
* @author Gail Badner
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/TimestampedEntity.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/TimestampedEntity.java
similarity index 96%
rename from hibernate-core/src/test/java/org/hibernate/test/ops/TimestampedEntity.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ops/TimestampedEntity.java
index cbe45db921..24ea1805ca 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ops/TimestampedEntity.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/TimestampedEntity.java
@@ -4,7 +4,7 @@
* 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.ops;
+package org.hibernate.orm.test.ops;
import java.util.Date;
/**
diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/VersionedEntity.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/VersionedEntity.java
similarity index 97%
rename from hibernate-core/src/test/java/org/hibernate/test/ops/VersionedEntity.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/ops/VersionedEntity.java
index 570b3837e4..33978552bb 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/ops/VersionedEntity.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/VersionedEntity.java
@@ -4,7 +4,7 @@
* 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.ops;
+package org.hibernate.orm.test.ops;
import java.util.HashSet;
import java.util.Set;
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/ops/genericApi/BasicGetLoadAccessTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/genericApi/BasicGetLoadAccessTest.java
index 1813a62217..42b941f8de 100644
--- a/hibernate-core/src/test/java/org/hibernate/orm/test/ops/genericApi/BasicGetLoadAccessTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/genericApi/BasicGetLoadAccessTest.java
@@ -15,30 +15,144 @@ import javax.persistence.Table;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
-import org.hibernate.Session;
import org.hibernate.annotations.GenericGenerator;
-import org.hibernate.boot.MetadataSources;
-import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
-import org.junit.Test;
+import org.hibernate.testing.orm.junit.DomainModel;
+import org.hibernate.testing.orm.junit.SessionFactory;
+import org.hibernate.testing.orm.junit.SessionFactoryScope;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.fail;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.fail;
/**
* @author Steve Ebersole
*/
-public class BasicGetLoadAccessTest extends BaseNonConfigCoreFunctionalTestCase {
- @Override
- protected void applyMetadataSources(MetadataSources sources) {
- super.applyMetadataSources( sources );
- sources.addAnnotatedClass( User.class );
+@DomainModel(
+ annotatedClasses = BasicGetLoadAccessTest.User.class
+)
+@SessionFactory
+public class BasicGetLoadAccessTest {
+
+ @AfterEach
+ public void tearDown(SessionFactoryScope scope){
+ scope.inTransaction(
+ session ->
+ session.createQuery( "delete from User" ).executeUpdate()
+ );
}
- @Entity( name = "User" )
- @Table( name = "my_user" )
+ @Test
+ public void testIt(SessionFactoryScope scope) {
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ // create a row
+ scope.inTransaction(
+ session ->
+ session.save( new User( "steve" ) )
+ );
+
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ // test `get` access
+ scope.inTransaction(
+ session ->
+ session.get( User.class, 1 )
+ );
+
+
+ scope.inTransaction(
+ session ->
+ session.get( User.class, 1, LockMode.PESSIMISTIC_WRITE )
+ );
+
+ scope.inTransaction(
+ session ->
+ session.get( User.class, 1, LockOptions.UPGRADE )
+ );
+
+ scope.inTransaction(
+ session ->
+ session.byId( User.class ).load( 1 )
+ );
+
+ scope.inTransaction(
+ session ->
+ session.byId( User.class ).with( LockOptions.UPGRADE ).load( 1 )
+ );
+
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ // test `load` access
+ scope.inTransaction(
+ session ->
+ session.load( User.class, 1 )
+ );
+
+ scope.inTransaction(
+ session ->
+ session.load( User.class, 1, LockMode.PESSIMISTIC_WRITE )
+ );
+
+ scope.inTransaction(
+ session ->
+ session.load( User.class, 1, LockOptions.UPGRADE )
+ );
+
+ scope.inTransaction(
+ session ->
+ session.byId( User.class ).getReference( 1 )
+ );
+
+ scope.inTransaction(
+ session ->
+ session.byId( User.class ).with( LockOptions.UPGRADE ).getReference( 1 )
+ );
+ }
+
+ @Test
+ public void testNullLoadResult(SessionFactoryScope scope) {
+ scope.inTransaction(
+ session -> {
+ assertNull( session.byId( User.class ).load( -1 ) );
+
+ Optional user = session.byId( User.class ).loadOptional( -1 );
+ assertNotNull( user );
+ assertFalse( user.isPresent() );
+ try {
+ user.get();
+ fail( "Expecting call to Optional#get to throw NoSuchElementException" );
+ }
+ catch (NoSuchElementException expected) {
+ // the expected result...
+ }
+ }
+ );
+ }
+
+ @Test
+ public void testNullQueryResult(SessionFactoryScope scope) {
+ scope.inTransaction(
+ session -> {
+ assertNull( session.createQuery( "select u from User u where u.id = -1" ).uniqueResult() );
+
+ Optional user = session.createQuery( "select u from User u where u.id = -1" ).uniqueResultOptional();
+ assertNotNull( user );
+ assertFalse( user.isPresent() );
+ try {
+ user.get();
+ fail( "Expecting call to Optional#get to throw NoSuchElementException" );
+ }
+ catch (NoSuchElementException expected) {
+ // the expected result...
+ }
+ }
+ );
+ }
+
+ @Entity(name = "User")
+ @Table(name = "my_user")
public static class User {
private Integer id;
private String name;
@@ -51,8 +165,8 @@ public class BasicGetLoadAccessTest extends BaseNonConfigCoreFunctionalTestCase
}
@Id
- @GeneratedValue( generator = "increment" )
- @GenericGenerator( name = "increment", strategy = "increment" )
+ @GeneratedValue(generator = "increment")
+ @GenericGenerator(name = "increment", strategy = "increment")
public Integer getId() {
return id;
}
@@ -70,125 +184,4 @@ public class BasicGetLoadAccessTest extends BaseNonConfigCoreFunctionalTestCase
}
}
- @Test
- public void testIt() {
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // create a row
- Session s = openSession();
- s.beginTransaction();
- s.save( new User( "steve" ) );
- s.getTransaction().commit();
- s.close();
-
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // test `get` access
- s = openSession();
- s.beginTransaction();
- User user = s.get( User.class, 1 );
- s.getTransaction().commit();
- s.close();
-
- s = openSession();
- s.beginTransaction();
- user = s.get( User.class, 1, LockMode.PESSIMISTIC_WRITE );
- s.getTransaction().commit();
- s.close();
-
- s = openSession();
- s.beginTransaction();
- user = s.get( User.class, 1, LockOptions.UPGRADE );
- s.getTransaction().commit();
- s.close();
-
- s = openSession();
- s.beginTransaction();
- user = s.byId( User.class ).load( 1 );
- s.getTransaction().commit();
- s.close();
-
- s = openSession();
- s.beginTransaction();
- user = s.byId( User.class ).with( LockOptions.UPGRADE ).load( 1 );
- s.getTransaction().commit();
- s.close();
-
-
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // test `load` access
- s = openSession();
- s.beginTransaction();
- user = s.load( User.class, 1 );
- s.getTransaction().commit();
- s.close();
-
- s = openSession();
- s.beginTransaction();
- user = s.load( User.class, 1, LockMode.PESSIMISTIC_WRITE );
- s.getTransaction().commit();
- s.close();
-
- s = openSession();
- s.beginTransaction();
- user = s.load( User.class, 1, LockOptions.UPGRADE );
- s.getTransaction().commit();
- s.close();
-
- s = openSession();
- s.beginTransaction();
- user = s.byId( User.class ).getReference( 1 );
- s.getTransaction().commit();
- s.close();
-
- s = openSession();
- s.beginTransaction();
- user = s.byId( User.class ).with( LockOptions.UPGRADE ).getReference( 1 );
- s.getTransaction().commit();
- s.close();
- }
-
- @Test
- public void testNullLoadResult() {
- Session s = openSession();
- s.beginTransaction();
-
- assertNull( s.byId( User.class ).load( -1 ) );
-
- Optional user = s.byId( User.class ).loadOptional( -1 );
- assertNotNull( user );
- assertFalse( user.isPresent() );
- try {
- user.get();
- fail( "Expecting call to Optional#get to throw NoSuchElementException" );
- }
- catch (NoSuchElementException expected) {
- // the expected result...
- }
-
- s.getTransaction().commit();
- s.close();
-
- }
-
- @Test
- public void testNullQueryResult() {
- Session s = openSession();
- s.beginTransaction();
-
- assertNull( s.createQuery( "select u from User u where u.id = -1" ).uniqueResult() );
-
- Optional user = s.createQuery( "select u from User u where u.id = -1" ).uniqueResultOptional();
- assertNotNull( user );
- assertFalse( user.isPresent() );
- try {
- user.get();
- fail( "Expecting call to Optional#get to throw NoSuchElementException" );
- }
- catch (NoSuchElementException expected) {
- // the expected result...
- }
-
- s.getTransaction().commit();
- s.close();
-
- }
}
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/ops/genericApi/ProxiedGetLoadAccessTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/genericApi/ProxiedGetLoadAccessTest.java
index 805c8d89a0..315c5a9c69 100644
--- a/hibernate-core/src/test/java/org/hibernate/orm/test/ops/genericApi/ProxiedGetLoadAccessTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/genericApi/ProxiedGetLoadAccessTest.java
@@ -13,33 +13,118 @@ import javax.persistence.Table;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
-import org.hibernate.Session;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Proxy;
-import org.hibernate.boot.MetadataSources;
-import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
-import org.junit.Test;
+import org.hibernate.testing.orm.junit.DomainModel;
+import org.hibernate.testing.orm.junit.SessionFactory;
+import org.hibernate.testing.orm.junit.SessionFactoryScope;
+import org.junit.jupiter.api.Test;
/**
* @author Steve Ebersole
*/
-public class ProxiedGetLoadAccessTest extends BaseNonConfigCoreFunctionalTestCase {
- @Override
- protected void applyMetadataSources(MetadataSources sources) {
- super.applyMetadataSources( sources );
- sources.addAnnotatedClass( UserImpl.class );
+@DomainModel(
+ annotatedClasses = ProxiedGetLoadAccessTest.UserImpl.class
+)
+@SessionFactory
+public class ProxiedGetLoadAccessTest {
+
+ @Test
+ public void testIt(SessionFactoryScope scope) {
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ // create a row
+ scope.inTransaction(
+ session ->
+ session.save( new UserImpl( "steve" ) )
+ );
+
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ // test `get` access
+ scope.inTransaction(
+ session -> {
+ // THis technically works
+ session.get( UserImpl.class, 1 );
+ session.get( User.class, 1 );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ session.get( UserImpl.class, 1, LockMode.PESSIMISTIC_WRITE );
+ session.get( User.class, 1, LockMode.PESSIMISTIC_WRITE );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ session.get( UserImpl.class, 1, LockOptions.UPGRADE );
+ session.get( User.class, 1, LockOptions.UPGRADE );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ session.byId( UserImpl.class ).load( 1 );
+ session.byId( User.class ).load( 1 );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ session.byId( UserImpl.class ).with( LockOptions.UPGRADE ).load( 1 );
+ session.byId( User.class ).with( LockOptions.UPGRADE ).load( 1 );
+ }
+ );
+
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ // test `load` access
+ scope.inTransaction(
+ session -> {
+ session.load( UserImpl.class, 1 );
+ session.load( User.class, 1 );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ session.load( UserImpl.class, 1, LockMode.PESSIMISTIC_WRITE );
+ session.load( User.class, 1, LockMode.PESSIMISTIC_WRITE );
+ }
+ );
+ scope.inTransaction(
+ session -> {
+ session.load( UserImpl.class, 1, LockOptions.UPGRADE );
+ session.load( User.class, 1, LockOptions.UPGRADE );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ session.byId( UserImpl.class ).getReference( 1 );
+ session.byId( User.class ).getReference( 1 );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ session.byId( UserImpl.class ).with( LockOptions.UPGRADE ).getReference( 1 );
+ session.byId( User.class ).with( LockOptions.UPGRADE ).getReference( 1 );
+ }
+ );
}
- public static interface User {
- public Integer getId();
- public String getName();
- public void setName(String name);
+ public interface User {
+ Integer getId();
+
+ String getName();
+
+ void setName(String name);
}
- @Entity( name = "User" )
- @Table( name = "my_user" )
- @Proxy( proxyClass = User.class )
+ @Entity(name = "User")
+ @Table(name = "my_user")
+ @Proxy(proxyClass = User.class)
public static class UserImpl implements User {
private Integer id;
private String name;
@@ -52,8 +137,8 @@ public class ProxiedGetLoadAccessTest extends BaseNonConfigCoreFunctionalTestCas
}
@Id
- @GeneratedValue( generator = "increment" )
- @GenericGenerator( name = "increment", strategy = "increment" )
+ @GeneratedValue(generator = "increment")
+ @GenericGenerator(name = "increment", strategy = "increment")
@Override
public Integer getId() {
return id;
@@ -73,91 +158,4 @@ public class ProxiedGetLoadAccessTest extends BaseNonConfigCoreFunctionalTestCas
this.name = name;
}
}
-
- @Test
- public void testIt() {
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // create a row
- Session s = openSession();
- s.beginTransaction();
- s.save( new UserImpl( "steve" ) );
- s.getTransaction().commit();
- s.close();
-
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // test `get` access
- s = openSession();
- s.beginTransaction();
- // THis technically works
- User user = s.get( UserImpl.class, 1 );
- user = s.get( User.class, 1 );
- s.getTransaction().commit();
- s.close();
-
- s = openSession();
- s.beginTransaction();
- user = s.get( UserImpl.class, 1, LockMode.PESSIMISTIC_WRITE );
- user = s.get( User.class, 1, LockMode.PESSIMISTIC_WRITE );
- s.getTransaction().commit();
- s.close();
-
- s = openSession();
- s.beginTransaction();
- user = s.get( UserImpl.class, 1, LockOptions.UPGRADE );
- user = s.get( User.class, 1, LockOptions.UPGRADE );
- s.getTransaction().commit();
- s.close();
-
- s = openSession();
- s.beginTransaction();
- user = s.byId( UserImpl.class ).load( 1 );
- user = s.byId( User.class ).load( 1 );
- s.getTransaction().commit();
- s.close();
-
- s = openSession();
- s.beginTransaction();
- user = s.byId( UserImpl.class ).with( LockOptions.UPGRADE ).load( 1 );
- user = s.byId( User.class ).with( LockOptions.UPGRADE ).load( 1 );
- s.getTransaction().commit();
- s.close();
-
-
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // test `load` access
- s = openSession();
- s.beginTransaction();
- user = s.load( UserImpl.class, 1 );
- user = s.load( User.class, 1 );
- s.getTransaction().commit();
- s.close();
-
- s = openSession();
- s.beginTransaction();
- user = s.load( UserImpl.class, 1, LockMode.PESSIMISTIC_WRITE );
- user = s.load( User.class, 1, LockMode.PESSIMISTIC_WRITE );
- s.getTransaction().commit();
- s.close();
-
- s = openSession();
- s.beginTransaction();
- user = s.load( UserImpl.class, 1, LockOptions.UPGRADE );
- user = s.load( User.class, 1, LockOptions.UPGRADE );
- s.getTransaction().commit();
- s.close();
-
- s = openSession();
- s.beginTransaction();
- user = s.byId( UserImpl.class ).getReference( 1 );
- user = s.byId( User.class ).getReference( 1 );
- s.getTransaction().commit();
- s.close();
-
- s = openSession();
- s.beginTransaction();
- user = s.byId( UserImpl.class ).with( LockOptions.UPGRADE ).getReference( 1 );
- user = s.byId( User.class ).with( LockOptions.UPGRADE ).getReference( 1 );
- s.getTransaction().commit();
- s.close();
- }
}
diff --git a/hibernate-core/src/test/java/org/hibernate/test/unionsubclass2/Address.java b/hibernate-core/src/test/java/org/hibernate/orm/test/unionsubclass2/Address.java
similarity index 90%
rename from hibernate-core/src/test/java/org/hibernate/test/unionsubclass2/Address.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/unionsubclass2/Address.java
index 3039c9fced..f562a58168 100755
--- a/hibernate-core/src/test/java/org/hibernate/test/unionsubclass2/Address.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/unionsubclass2/Address.java
@@ -6,7 +6,7 @@
*/
//$Id: Address.java 7192 2005-06-18 14:40:15Z oneovthafew $
-package org.hibernate.test.unionsubclass2;
+package org.hibernate.orm.test.unionsubclass2;
/**
diff --git a/hibernate-core/src/test/java/org/hibernate/test/unionsubclass2/Customer.java b/hibernate-core/src/test/java/org/hibernate/orm/test/unionsubclass2/Customer.java
similarity index 95%
rename from hibernate-core/src/test/java/org/hibernate/test/unionsubclass2/Customer.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/unionsubclass2/Customer.java
index 4635a430d1..948aab4a66 100755
--- a/hibernate-core/src/test/java/org/hibernate/test/unionsubclass2/Customer.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/unionsubclass2/Customer.java
@@ -6,7 +6,7 @@
*/
//$Id: Customer.java 7192 2005-06-18 14:40:15Z oneovthafew $
-package org.hibernate.test.unionsubclass2;
+package org.hibernate.orm.test.unionsubclass2;
/**
diff --git a/hibernate-core/src/test/java/org/hibernate/test/unionsubclass2/Employee.java b/hibernate-core/src/test/java/org/hibernate/orm/test/unionsubclass2/Employee.java
similarity index 96%
rename from hibernate-core/src/test/java/org/hibernate/test/unionsubclass2/Employee.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/unionsubclass2/Employee.java
index 4fab07b13f..92328849c5 100755
--- a/hibernate-core/src/test/java/org/hibernate/test/unionsubclass2/Employee.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/unionsubclass2/Employee.java
@@ -6,7 +6,7 @@
*/
//$Id: Employee.java 7192 2005-06-18 14:40:15Z oneovthafew $
-package org.hibernate.test.unionsubclass2;
+package org.hibernate.orm.test.unionsubclass2;
import java.math.BigDecimal;
/**
diff --git a/hibernate-core/src/test/java/org/hibernate/test/unionsubclass2/Person.hbm.xml b/hibernate-core/src/test/java/org/hibernate/orm/test/unionsubclass2/Person.hbm.xml
similarity index 97%
rename from hibernate-core/src/test/java/org/hibernate/test/unionsubclass2/Person.hbm.xml
rename to hibernate-core/src/test/java/org/hibernate/orm/test/unionsubclass2/Person.hbm.xml
index ce6c63f720..a29fc94967 100755
--- a/hibernate-core/src/test/java/org/hibernate/test/unionsubclass2/Person.hbm.xml
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/unionsubclass2/Person.hbm.xml
@@ -22,7 +22,7 @@
-->
diff --git a/hibernate-core/src/test/java/org/hibernate/test/unionsubclass2/Person.java b/hibernate-core/src/test/java/org/hibernate/orm/test/unionsubclass2/Person.java
similarity index 97%
rename from hibernate-core/src/test/java/org/hibernate/test/unionsubclass2/Person.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/unionsubclass2/Person.java
index 8cceaa8e31..9f25233120 100755
--- a/hibernate-core/src/test/java/org/hibernate/test/unionsubclass2/Person.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/unionsubclass2/Person.java
@@ -6,7 +6,7 @@
*/
//$Id: Person.java 7192 2005-06-18 14:40:15Z oneovthafew $
-package org.hibernate.test.unionsubclass2;
+package org.hibernate.orm.test.unionsubclass2;
diff --git a/hibernate-core/src/test/java/org/hibernate/test/unionsubclass2/UnionSubclassTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/unionsubclass2/UnionSubclassTest.java
similarity index 88%
rename from hibernate-core/src/test/java/org/hibernate/test/unionsubclass2/UnionSubclassTest.java
rename to hibernate-core/src/test/java/org/hibernate/orm/test/unionsubclass2/UnionSubclassTest.java
index f875784121..3bcafd4d3f 100755
--- a/hibernate-core/src/test/java/org/hibernate/test/unionsubclass2/UnionSubclassTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/unionsubclass2/UnionSubclassTest.java
@@ -4,7 +4,7 @@
* 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.unionsubclass2;
+package org.hibernate.orm.test.unionsubclass2;
import java.math.BigDecimal;
import java.util.List;
@@ -13,28 +13,35 @@ import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import org.hibernate.Hibernate;
-import org.hibernate.dialect.HSQLDialect;
-import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
-import org.junit.Test;
+import org.hibernate.testing.orm.junit.DomainModel;
+import org.hibernate.testing.orm.junit.SessionFactory;
+import org.hibernate.testing.orm.junit.SessionFactoryScope;
+import org.junit.jupiter.api.Test;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
/**
* @author Gavin King
*/
-public class UnionSubclassTest extends BaseCoreFunctionalTestCase {
+@DomainModel(
+ xmlMappings = "org/hibernate/orm/test/unionsubclass2/Person.hbm.xml"
+)
+@SessionFactory
+public class UnionSubclassTest {
protected String[] getMappings() {
- return new String[] { "unionsubclass2/Person.hbm.xml" };
+ return new String[] {};
}
@Test
- public void testUnionSubclass() {
-
- inTransaction(
+ public void testUnionSubclass(SessionFactoryScope scope) {
+ scope.inTransaction(
s -> {
Employee mark = new Employee();
mark.setName( "Mark" );
@@ -61,7 +68,13 @@ public class UnionSubclassTest extends BaseCoreFunctionalTestCase {
s.save( mark );
s.save( joe );
- assertEquals( s.createQuery( "from java.io.Serializable" ).list().size(), 0 );
+ try {
+ assertEquals( s.createQuery( "from java.io.Serializable" ).list().size(), 0 );
+ fail( "IllegalArgumentException expected" );
+ }
+ catch (Exception e) {
+ assertThat( e, instanceOf( IllegalArgumentException.class ) );
+ }
assertEquals( s.createQuery( "from Person" ).list().size(), 3 );
assertEquals( s.createQuery( "from Person p where p.class = Customer" ).list().size(), 1 );
@@ -109,7 +122,8 @@ public class UnionSubclassTest extends BaseCoreFunctionalTestCase {
Root root = criteria.from( Person.class );
CriteriaBuilder.In