HHH-16337 Bytecode enhancement : ElementCollection is not deleted when replaced
This commit is contained in:
parent
570ccae476
commit
6f3feca7f4
|
@ -12,6 +12,7 @@ import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLaziness
|
||||||
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor;
|
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor;
|
||||||
import org.hibernate.collection.spi.PersistentCollection;
|
import org.hibernate.collection.spi.PersistentCollection;
|
||||||
import org.hibernate.engine.spi.CollectionEntry;
|
import org.hibernate.engine.spi.CollectionEntry;
|
||||||
|
import org.hibernate.engine.spi.CollectionKey;
|
||||||
import org.hibernate.engine.spi.EntityEntry;
|
import org.hibernate.engine.spi.EntityEntry;
|
||||||
import org.hibernate.engine.spi.PersistenceContext;
|
import org.hibernate.engine.spi.PersistenceContext;
|
||||||
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
|
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
|
||||||
|
@ -114,8 +115,6 @@ public class WrapVisitor extends ProxyVisitor {
|
||||||
&& ((LazyAttributeLoadingInterceptor)attributeInterceptor).isAttributeLoaded( persister.getAttributeMapping().getAttributeName() ) ) {
|
&& ((LazyAttributeLoadingInterceptor)attributeInterceptor).isAttributeLoaded( persister.getAttributeMapping().getAttributeName() ) ) {
|
||||||
final EntityEntry entry = persistenceContext.getEntry( entity );
|
final EntityEntry entry = persistenceContext.getEntry( entity );
|
||||||
if ( entry.isExistsInDatabase() ) {
|
if ( entry.isExistsInDatabase() ) {
|
||||||
// the collection has not been initialized and new collection values have been assigned,
|
|
||||||
// we need to be sure to delete all the collection elements before inserting the new ones
|
|
||||||
final AbstractEntityPersister entityDescriptor =
|
final AbstractEntityPersister entityDescriptor =
|
||||||
(AbstractEntityPersister) persister.getOwnerEntityPersister();
|
(AbstractEntityPersister) persister.getOwnerEntityPersister();
|
||||||
final Object key = entityDescriptor.getCollectionKey(
|
final Object key = entityDescriptor.getCollectionKey(
|
||||||
|
@ -124,17 +123,26 @@ public class WrapVisitor extends ProxyVisitor {
|
||||||
entry,
|
entry,
|
||||||
session
|
session
|
||||||
);
|
);
|
||||||
final PersistentCollection<?> collectionInstance = persister.getCollectionSemantics()
|
PersistentCollection<?> collectionInstance = persistenceContext.getCollection(
|
||||||
.instantiateWrapper( key, persister, session );
|
new CollectionKey( persister, key )
|
||||||
collectionInstance.setOwner( entity );
|
);
|
||||||
persistenceContext.addUninitializedCollection( persister, collectionInstance, key );
|
|
||||||
|
|
||||||
final CollectionEntry collectionEntry = persistenceContext
|
if ( collectionInstance == null ) {
|
||||||
.getCollectionEntry( collectionInstance );
|
// the collection has not been initialized and new collection values have been assigned,
|
||||||
|
// we need to be sure to delete all the collection elements before inserting the new ones
|
||||||
|
collectionInstance = persister.getCollectionSemantics().instantiateWrapper(
|
||||||
|
key,
|
||||||
|
persister,
|
||||||
|
session
|
||||||
|
);
|
||||||
|
persistenceContext.addUninitializedCollection( persister, collectionInstance, key );
|
||||||
|
final CollectionEntry collectionEntry = persistenceContext.getCollectionEntry(
|
||||||
|
collectionInstance );
|
||||||
collectionEntry.setDoremove( true );
|
collectionEntry.setDoremove( true );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final PersistentCollection<?> persistentCollection = collectionType.wrap( session, collection );
|
final PersistentCollection<?> persistentCollection = collectionType.wrap( session, collection );
|
||||||
persistenceContext.addNewCollection( persister, persistentCollection );
|
persistenceContext.addNewCollection( persister, persistentCollection );
|
||||||
|
|
|
@ -0,0 +1,128 @@
|
||||||
|
package org.hibernate.orm.test.bytecode.enhancement.collectionelement.flush;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||||
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import jakarta.persistence.CollectionTable;
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.ElementCollection;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
|
||||||
|
|
||||||
|
@RunWith(BytecodeEnhancerRunner.class)
|
||||||
|
@TestForIssue(jiraKey = "HHH-16337")
|
||||||
|
public class ElementCollectionFlushAfterQueryTest extends BaseCoreFunctionalTestCase {
|
||||||
|
private static final Long MY_ENTITY_ID = 1l;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class[] getAnnotatedClasses() {
|
||||||
|
return new Class[] {
|
||||||
|
MyEntity.class,
|
||||||
|
MyOtherEntity.class
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAutoFlush() {
|
||||||
|
inTransaction(
|
||||||
|
session -> {
|
||||||
|
MyEntity myEntity = new MyEntity( MY_ENTITY_ID, "my entity" );
|
||||||
|
myEntity.addRedirectUris( "1" );
|
||||||
|
session.persist( myEntity );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
inTransaction(
|
||||||
|
session -> {
|
||||||
|
MyEntity myEntity = session.find( MyEntity.class, MY_ENTITY_ID );
|
||||||
|
|
||||||
|
Set<String> set = new HashSet<>();
|
||||||
|
set.add( "3" );
|
||||||
|
myEntity.setRedirectUris( set );
|
||||||
|
|
||||||
|
session.createQuery( "from MyOtherEntity ", MyOtherEntity.class ).getResultList();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
inTransaction(
|
||||||
|
session -> {
|
||||||
|
MyEntity myEntity = session.find( MyEntity.class, MY_ENTITY_ID );
|
||||||
|
Set<String> redirectUris = myEntity.getRedirectUris();
|
||||||
|
assertThat( redirectUris.size() ).isEqualTo( 1 );
|
||||||
|
assertThat( redirectUris.contains( "3" ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "MyEntity")
|
||||||
|
public static class MyEntity {
|
||||||
|
@Id
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@ElementCollection
|
||||||
|
@Column(name = "val")
|
||||||
|
@CollectionTable(name = "REDIRECT_URIS", joinColumns = { @JoinColumn(name = "ID") })
|
||||||
|
protected Set<String> redirectUris = new HashSet<>();
|
||||||
|
|
||||||
|
public MyEntity() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public MyEntity(Long id, String name) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> getRedirectUris() {
|
||||||
|
return redirectUris;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRedirectUris(Set<String> redirectUris) {
|
||||||
|
this.redirectUris = redirectUris;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addRedirectUris(String redirectUri) {
|
||||||
|
this.redirectUris.add( redirectUri );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "MyOtherEntity")
|
||||||
|
public class MyOtherEntity {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public MyOtherEntity() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public MyOtherEntity(Long id, String name) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,224 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.test.bytecode.enhancement.collectionelement.recreate;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.boot.SessionFactoryBuilder;
|
||||||
|
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||||
|
import org.hibernate.testing.bytecode.enhancement.EnhancementOptions;
|
||||||
|
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import jakarta.persistence.ElementCollection;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.OrderColumn;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
@RunWith(BytecodeEnhancerRunner.class)
|
||||||
|
@EnhancementOptions(lazyLoading = true)
|
||||||
|
@TestForIssue(jiraKey = "HHH-14387")
|
||||||
|
public class BytecodeEnhancementElementCollectionRecreateCollectionsInDefaultGroupTest
|
||||||
|
extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class[] getAnnotatedClasses() {
|
||||||
|
return new Class[] {
|
||||||
|
MyEntity.class
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) {
|
||||||
|
super.configureSessionFactoryBuilder( sfb );
|
||||||
|
sfb.applyCollectionsInDefaultFetchGroup( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void check() {
|
||||||
|
inSession(
|
||||||
|
session ->
|
||||||
|
assertTrue( session.getSessionFactory().getSessionFactoryOptions()
|
||||||
|
.isCollectionsInDefaultFetchGroupEnabled() )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() {
|
||||||
|
inTransaction(
|
||||||
|
session ->
|
||||||
|
session.createQuery( "delete from myentity" ).executeUpdate()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRecreateCollection() {
|
||||||
|
inTransaction( session -> {
|
||||||
|
MyEntity entity = new MyEntity();
|
||||||
|
entity.setId( 1 );
|
||||||
|
entity.setElements( Arrays.asList( "one", "two", "four" ) );
|
||||||
|
session.persist( entity );
|
||||||
|
} );
|
||||||
|
|
||||||
|
inTransaction( session -> {
|
||||||
|
MyEntity entity = session.get( MyEntity.class, 1 );
|
||||||
|
entity.setElements( Arrays.asList( "two", "three" ) );
|
||||||
|
session.persist( entity );
|
||||||
|
} );
|
||||||
|
|
||||||
|
inTransaction( session -> {
|
||||||
|
MyEntity entity = session.get( MyEntity.class, 1 );
|
||||||
|
assertThat( entity.getElements() )
|
||||||
|
.containsExactlyInAnyOrder( "two", "three" );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRecreateCollectionFind() {
|
||||||
|
inTransaction( session -> {
|
||||||
|
MyEntity entity = new MyEntity();
|
||||||
|
entity.setId( 1 );
|
||||||
|
entity.setElements( Arrays.asList( "one", "two", "four" ) );
|
||||||
|
session.persist( entity );
|
||||||
|
} );
|
||||||
|
|
||||||
|
inTransaction( session -> {
|
||||||
|
MyEntity entity = session.find( MyEntity.class, 1 );
|
||||||
|
entity.setElements( Arrays.asList( "two", "three" ) );
|
||||||
|
session.persist( entity );
|
||||||
|
} );
|
||||||
|
|
||||||
|
inTransaction( session -> {
|
||||||
|
MyEntity entity = session.find( MyEntity.class, 1 );
|
||||||
|
assertThat( entity.getElements() )
|
||||||
|
.containsExactlyInAnyOrder( "two", "three" );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteCollection() {
|
||||||
|
inTransaction( session -> {
|
||||||
|
MyEntity entity = new MyEntity();
|
||||||
|
entity.setId( 1 );
|
||||||
|
entity.setElements( Arrays.asList( "one", "two", "four" ) );
|
||||||
|
session.persist( entity );
|
||||||
|
} );
|
||||||
|
|
||||||
|
inTransaction( session -> {
|
||||||
|
MyEntity entity = session.get( MyEntity.class, 1 );
|
||||||
|
entity.setElements( new ArrayList<>() );
|
||||||
|
} );
|
||||||
|
|
||||||
|
inTransaction( session -> {
|
||||||
|
MyEntity entity = session.get( MyEntity.class, 1 );
|
||||||
|
assertThat( entity.getElements() )
|
||||||
|
.isEmpty();
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteCollectionFind() {
|
||||||
|
inTransaction( session -> {
|
||||||
|
MyEntity entity = new MyEntity();
|
||||||
|
entity.setId( 1 );
|
||||||
|
entity.setElements( Arrays.asList( "one", "two", "four" ) );
|
||||||
|
session.persist( entity );
|
||||||
|
} );
|
||||||
|
|
||||||
|
inTransaction( session -> {
|
||||||
|
MyEntity entity = session.find( MyEntity.class, 1 );
|
||||||
|
entity.setElements( new ArrayList<>() );
|
||||||
|
} );
|
||||||
|
|
||||||
|
inTransaction( session -> {
|
||||||
|
MyEntity entity = session.find( MyEntity.class, 1 );
|
||||||
|
assertThat( entity.getElements() )
|
||||||
|
.isEmpty();
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLoadAndCommitTransactionDoesNotDeleteCollection() {
|
||||||
|
inTransaction( session -> {
|
||||||
|
MyEntity entity = new MyEntity();
|
||||||
|
entity.setId( 1 );
|
||||||
|
entity.setElements( Arrays.asList( "one", "two", "four" ) );
|
||||||
|
session.persist( entity );
|
||||||
|
} );
|
||||||
|
|
||||||
|
inTransaction( session ->
|
||||||
|
session.get( MyEntity.class, 1 )
|
||||||
|
);
|
||||||
|
|
||||||
|
inTransaction( session -> {
|
||||||
|
MyEntity entity = session.get( MyEntity.class, 1 );
|
||||||
|
assertThat( entity.getElements() )
|
||||||
|
.containsExactlyInAnyOrder( "one", "two", "four" );
|
||||||
|
} );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLoadAndCommitTransactionDoesNotDeleteCollectionFind() {
|
||||||
|
inTransaction( session -> {
|
||||||
|
MyEntity entity = new MyEntity();
|
||||||
|
entity.setId( 1 );
|
||||||
|
entity.setElements( Arrays.asList( "one", "two", "four" ) );
|
||||||
|
session.persist( entity );
|
||||||
|
} );
|
||||||
|
|
||||||
|
inTransaction( session ->
|
||||||
|
session.find( MyEntity.class, 1 )
|
||||||
|
);
|
||||||
|
|
||||||
|
inTransaction( session -> {
|
||||||
|
MyEntity entity = session.find( MyEntity.class, 1 );
|
||||||
|
assertThat( entity.getElements() )
|
||||||
|
.containsExactlyInAnyOrder( "one", "two", "four" );
|
||||||
|
} );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "myentity")
|
||||||
|
public static class MyEntity {
|
||||||
|
@Id
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
@ElementCollection
|
||||||
|
@OrderColumn
|
||||||
|
private List<String> elements;
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getElements() {
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setElements(List<String> elements) {
|
||||||
|
this.elements = elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,222 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.test.bytecode.enhancement.collectionelement.recreate;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.boot.SessionFactoryBuilder;
|
||||||
|
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||||
|
import org.hibernate.testing.bytecode.enhancement.EnhancementOptions;
|
||||||
|
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import jakarta.persistence.ElementCollection;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.OrderColumn;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
|
||||||
|
@RunWith(BytecodeEnhancerRunner.class)
|
||||||
|
@EnhancementOptions(lazyLoading = true)
|
||||||
|
@TestForIssue(jiraKey = "HHH-14387")
|
||||||
|
public class BytecodeEnhancementElementCollectionRecreateTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class[] getAnnotatedClasses() {
|
||||||
|
return new Class[] {
|
||||||
|
MyEntity.class
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) {
|
||||||
|
super.configureSessionFactoryBuilder( sfb );
|
||||||
|
sfb.applyCollectionsInDefaultFetchGroup( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void check() {
|
||||||
|
inSession(
|
||||||
|
session ->
|
||||||
|
assertFalse( session.getSessionFactory().getSessionFactoryOptions()
|
||||||
|
.isCollectionsInDefaultFetchGroupEnabled() )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() {
|
||||||
|
inTransaction(
|
||||||
|
session ->
|
||||||
|
session.createQuery( "delete from myentity" ).executeUpdate()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRecreateCollection() {
|
||||||
|
inTransaction( session -> {
|
||||||
|
MyEntity entity = new MyEntity();
|
||||||
|
entity.setId( 1 );
|
||||||
|
entity.setElements( Arrays.asList( "one", "two", "four" ) );
|
||||||
|
session.persist( entity );
|
||||||
|
} );
|
||||||
|
|
||||||
|
inTransaction( session -> {
|
||||||
|
MyEntity entity = session.get( MyEntity.class, 1 );
|
||||||
|
entity.setElements( Arrays.asList( "two", "three" ) );
|
||||||
|
session.persist( entity );
|
||||||
|
} );
|
||||||
|
|
||||||
|
inTransaction( session -> {
|
||||||
|
MyEntity entity = session.get( MyEntity.class, 1 );
|
||||||
|
assertThat( entity.getElements() )
|
||||||
|
.containsExactlyInAnyOrder( "two", "three" );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRecreateCollectionFind() {
|
||||||
|
inTransaction( session -> {
|
||||||
|
MyEntity entity = new MyEntity();
|
||||||
|
entity.setId( 1 );
|
||||||
|
entity.setElements( Arrays.asList( "one", "two", "four" ) );
|
||||||
|
session.persist( entity );
|
||||||
|
} );
|
||||||
|
|
||||||
|
inTransaction( session -> {
|
||||||
|
MyEntity entity = session.find( MyEntity.class, 1 );
|
||||||
|
entity.setElements( Arrays.asList( "two", "three" ) );
|
||||||
|
session.persist( entity );
|
||||||
|
} );
|
||||||
|
|
||||||
|
inTransaction( session -> {
|
||||||
|
MyEntity entity = session.find( MyEntity.class, 1 );
|
||||||
|
assertThat( entity.getElements() )
|
||||||
|
.containsExactlyInAnyOrder( "two", "three" );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteCollection() {
|
||||||
|
inTransaction( session -> {
|
||||||
|
MyEntity entity = new MyEntity();
|
||||||
|
entity.setId( 1 );
|
||||||
|
entity.setElements( Arrays.asList( "one", "two", "four" ) );
|
||||||
|
session.persist( entity );
|
||||||
|
} );
|
||||||
|
|
||||||
|
inTransaction( session -> {
|
||||||
|
MyEntity entity = session.get( MyEntity.class, 1 );
|
||||||
|
entity.setElements( new ArrayList<>() );
|
||||||
|
} );
|
||||||
|
|
||||||
|
inTransaction( session -> {
|
||||||
|
MyEntity entity = session.get( MyEntity.class, 1 );
|
||||||
|
assertThat( entity.getElements() )
|
||||||
|
.isEmpty();
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteCollectionFind() {
|
||||||
|
inTransaction( session -> {
|
||||||
|
MyEntity entity = new MyEntity();
|
||||||
|
entity.setId( 1 );
|
||||||
|
entity.setElements( Arrays.asList( "one", "two", "four" ) );
|
||||||
|
session.persist( entity );
|
||||||
|
} );
|
||||||
|
|
||||||
|
inTransaction( session -> {
|
||||||
|
MyEntity entity = session.find( MyEntity.class, 1 );
|
||||||
|
entity.setElements( new ArrayList<>() );
|
||||||
|
} );
|
||||||
|
|
||||||
|
inTransaction( session -> {
|
||||||
|
MyEntity entity = session.find( MyEntity.class, 1 );
|
||||||
|
assertThat( entity.getElements() )
|
||||||
|
.isEmpty();
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLoadAndCommitTransactionDoesNotDeleteCollection() {
|
||||||
|
inTransaction( session -> {
|
||||||
|
MyEntity entity = new MyEntity();
|
||||||
|
entity.setId( 1 );
|
||||||
|
entity.setElements( Arrays.asList( "one", "two", "four" ) );
|
||||||
|
session.persist( entity );
|
||||||
|
} );
|
||||||
|
|
||||||
|
inTransaction( session ->
|
||||||
|
session.get( MyEntity.class, 1 )
|
||||||
|
);
|
||||||
|
|
||||||
|
inTransaction( session -> {
|
||||||
|
MyEntity entity = session.get( MyEntity.class, 1 );
|
||||||
|
assertThat( entity.getElements() )
|
||||||
|
.containsExactlyInAnyOrder( "one", "two", "four" );
|
||||||
|
} );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLoadAndCommitTransactionDoesNotDeleteCollectionFind() {
|
||||||
|
inTransaction( session -> {
|
||||||
|
MyEntity entity = new MyEntity();
|
||||||
|
entity.setId( 1 );
|
||||||
|
entity.setElements( Arrays.asList( "one", "two", "four" ) );
|
||||||
|
session.persist( entity );
|
||||||
|
} );
|
||||||
|
|
||||||
|
inTransaction( session ->
|
||||||
|
session.find( MyEntity.class, 1 )
|
||||||
|
);
|
||||||
|
|
||||||
|
inTransaction( session -> {
|
||||||
|
MyEntity entity = session.find( MyEntity.class, 1 );
|
||||||
|
assertThat( entity.getElements() )
|
||||||
|
.containsExactlyInAnyOrder( "one", "two", "four" );
|
||||||
|
} );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "myentity")
|
||||||
|
public static class MyEntity {
|
||||||
|
@Id
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
@ElementCollection
|
||||||
|
@OrderColumn
|
||||||
|
private List<String> elements;
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getElements() {
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setElements(List<String> elements) {
|
||||||
|
this.elements = elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,157 @@
|
||||||
|
package org.hibernate.orm.test.bytecode.enhancement.flush;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||||
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import jakarta.persistence.CascadeType;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.OneToMany;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
|
||||||
|
|
||||||
|
@RunWith(BytecodeEnhancerRunner.class)
|
||||||
|
@TestForIssue(jiraKey = "HHH-16337")
|
||||||
|
public class CollectionFlushAfterQueryTest extends BaseCoreFunctionalTestCase {
|
||||||
|
|
||||||
|
private static final Long MY_ENTITY_ID = 1l;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class[] getAnnotatedClasses() {
|
||||||
|
return new Class[] {
|
||||||
|
CollectionFlushAfterQueryTest.MyEntity.class,
|
||||||
|
CollectionFlushAfterQueryTest.MyOtherEntity.class,
|
||||||
|
CollectionFlushAfterQueryTest.MyAnotherEntity.class
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAutoFlush() {
|
||||||
|
inTransaction(
|
||||||
|
session -> {
|
||||||
|
MyEntity myEntity = new MyEntity( MY_ENTITY_ID, "my entity" );
|
||||||
|
MyOtherEntity otherEntity = new MyOtherEntity( 2l, "my other entity" );
|
||||||
|
myEntity.addOtherEntity( otherEntity );
|
||||||
|
session.persist( otherEntity );
|
||||||
|
session.persist( myEntity );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
inTransaction(
|
||||||
|
session -> {
|
||||||
|
MyEntity myEntity = session.find( MyEntity.class, MY_ENTITY_ID );
|
||||||
|
|
||||||
|
MyOtherEntity otherEntity = new MyOtherEntity( 3l, "my new other entity" );
|
||||||
|
Set<MyOtherEntity> set = new HashSet<>();
|
||||||
|
set.add( otherEntity );
|
||||||
|
myEntity.setOtherEntities( set );
|
||||||
|
|
||||||
|
session.createQuery( "from MyAnotherEntity ", MyAnotherEntity.class ).getResultList();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
inTransaction(
|
||||||
|
session -> {
|
||||||
|
MyEntity myEntity = session.find( MyEntity.class, MY_ENTITY_ID );
|
||||||
|
Set<MyOtherEntity> redirectUris = myEntity.getOtherEntities();
|
||||||
|
assertThat( redirectUris.size() ).isEqualTo( 1 );
|
||||||
|
|
||||||
|
Optional<MyOtherEntity> first = redirectUris.stream().findFirst();
|
||||||
|
assertThat( first.get().getName() ).isEqualTo( "my new other entity" );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "MyEntity")
|
||||||
|
public static class MyEntity {
|
||||||
|
@Id
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@OneToMany(cascade = CascadeType.ALL)
|
||||||
|
protected Set<MyOtherEntity> otherEntities = new HashSet<>();
|
||||||
|
|
||||||
|
public MyEntity() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public MyEntity(Long id, String name) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<MyOtherEntity> getOtherEntities() {
|
||||||
|
return otherEntities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOtherEntities(Set<MyOtherEntity> otherEntities) {
|
||||||
|
this.otherEntities = otherEntities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addOtherEntity(MyOtherEntity otherEntity) {
|
||||||
|
this.otherEntities.add( otherEntity );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "MyOtherEntity")
|
||||||
|
public static class MyOtherEntity {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public MyOtherEntity() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public MyOtherEntity(Long id, String name) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "MyAnotherEntity")
|
||||||
|
public static class MyAnotherEntity {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public MyAnotherEntity() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public MyAnotherEntity(Long id, String name) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,8 +6,8 @@ import java.util.List;
|
||||||
import org.hibernate.testing.TestForIssue;
|
import org.hibernate.testing.TestForIssue;
|
||||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
import org.junit.After;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
|
@ -21,9 +21,11 @@ import static jakarta.persistence.CascadeType.MERGE;
|
||||||
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
|
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
|
||||||
|
|
||||||
@RunWith(BytecodeEnhancerRunner.class)
|
@RunWith(BytecodeEnhancerRunner.class)
|
||||||
@TestForIssue( jiraKey = "HHH-16322")
|
@TestForIssue(jiraKey = "HHH-16322")
|
||||||
public class MergeUnsavedEntitiesTest extends BaseCoreFunctionalTestCase {
|
public class MergeUnsavedEntitiesTest extends BaseCoreFunctionalTestCase {
|
||||||
|
|
||||||
|
public static final String CHILD_NAME = "first child";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Class<?>[] getAnnotatedClasses() {
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
return new Class[] {
|
return new Class[] {
|
||||||
|
@ -32,23 +34,13 @@ public class MergeUnsavedEntitiesTest extends BaseCoreFunctionalTestCase {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterEach
|
|
||||||
public void tearDown() {
|
|
||||||
inTransaction(
|
|
||||||
session -> {
|
|
||||||
session.createMutationQuery( "delete from Child" ).executeUpdate();
|
|
||||||
session.createMutationQuery( "delete from Parent" ).executeUpdate();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMerge() {
|
public void testMerge() {
|
||||||
inTransaction(
|
inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
Parent parent = new Parent( 1l, 2l );
|
Parent parent = new Parent( 1l, 2l );
|
||||||
parent = session.merge( parent );
|
parent = session.merge( parent );
|
||||||
Child child = new Child( 2l, "first child" );
|
Child child = new Child( 2l, CHILD_NAME );
|
||||||
child = session.merge( child );
|
child = session.merge( child );
|
||||||
parent.addChild( child );
|
parent.addChild( child );
|
||||||
parent.getId();
|
parent.getId();
|
||||||
|
@ -59,6 +51,8 @@ public class MergeUnsavedEntitiesTest extends BaseCoreFunctionalTestCase {
|
||||||
session -> {
|
session -> {
|
||||||
Parent parent = session.find( Parent.class, 1l );
|
Parent parent = session.find( Parent.class, 1l );
|
||||||
assertThat( parent.getChildren().size() ).isEqualTo( 1 );
|
assertThat( parent.getChildren().size() ).isEqualTo( 1 );
|
||||||
|
Child child = parent.getChildren().get( 0 );
|
||||||
|
assertThat( child.getName() ).isEqualTo( CHILD_NAME );
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -72,20 +66,16 @@ public class MergeUnsavedEntitiesTest extends BaseCoreFunctionalTestCase {
|
||||||
inTransaction(
|
inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
Parent parent = session.find( Parent.class, 1l );
|
Parent parent = session.find( Parent.class, 1l );
|
||||||
parent.setChildren( new ArrayList<>() );
|
assertThat( parent.getChildren().size() ).isEqualTo( 1 );
|
||||||
session.merge( parent );
|
Child child = parent.getChildren().get( 0 );
|
||||||
}
|
|
||||||
);
|
assertThat( child.getName() ).isEqualTo( CHILD_NAME );
|
||||||
|
|
||||||
inTransaction(
|
|
||||||
session -> {
|
|
||||||
Parent parent = session.find( Parent.class, 1l );
|
|
||||||
assertThat( parent.getChildren().size() ).isEqualTo( 0 );
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity(name = "parent")
|
@Entity(name = "Parent")
|
||||||
@Table(name = "parent")
|
@Table(name = "parent")
|
||||||
public static class Parent {
|
public static class Parent {
|
||||||
@Id
|
@Id
|
||||||
|
@ -139,7 +129,7 @@ public class MergeUnsavedEntitiesTest extends BaseCoreFunctionalTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity
|
@Entity(name = "Child")
|
||||||
@Table(name = "child")
|
@Table(name = "child")
|
||||||
public static class Child {
|
public static class Child {
|
||||||
|
|
||||||
|
@ -175,6 +165,9 @@ public class MergeUnsavedEntitiesTest extends BaseCoreFunctionalTestCase {
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue