HHH-13129 - Add test
HHH-13129 : Move and reformat test
HHH-13129 : Add more tests
(cherry picked from commit c62f0a75cd
)
This commit is contained in:
parent
56f67fb0cd
commit
fb3b710d99
|
@ -0,0 +1,256 @@
|
||||||
|
/*
|
||||||
|
* 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.test.bytecode.enhancement.cascade;
|
||||||
|
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||||
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import javax.persistence.Basic;
|
||||||
|
import javax.persistence.CascadeType;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.FetchType;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.GenerationType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.persistence.OneToMany;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.Hibernate;
|
||||||
|
import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
|
||||||
|
|
||||||
|
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Luis Barreiro
|
||||||
|
*/
|
||||||
|
@TestForIssue( jiraKey = "HHH-10252" )
|
||||||
|
@RunWith( BytecodeEnhancerRunner.class )
|
||||||
|
public class CascadeDeleteCollectionTest extends BaseCoreFunctionalTestCase {
|
||||||
|
private Parent originalParent;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class[]{Parent.class, Child.class};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void prepare() {
|
||||||
|
// Create a Parent with one Child
|
||||||
|
originalParent = doInHibernate( this::sessionFactory, s -> {
|
||||||
|
Parent p = new Parent();
|
||||||
|
p.setName( "PARENT" );
|
||||||
|
p.setLazy( "LAZY" );
|
||||||
|
p.makeChild();
|
||||||
|
s.persist( p );
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testManagedWithUninitializedAssociation() {
|
||||||
|
// Delete the Parent
|
||||||
|
doInHibernate( this::sessionFactory, s -> {
|
||||||
|
Parent loadedParent = (Parent) s.createQuery( "SELECT p FROM Parent p WHERE name=:name" )
|
||||||
|
.setParameter( "name", "PARENT" )
|
||||||
|
.uniqueResult();
|
||||||
|
checkInterceptor( loadedParent, false );
|
||||||
|
assertFalse( Hibernate.isPropertyInitialized( loadedParent, "children" ) );
|
||||||
|
s.delete( loadedParent );
|
||||||
|
} );
|
||||||
|
// If the lazy relation is not fetch on cascade there is a constraint violation on commit
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue(jiraKey = "HHH-13129")
|
||||||
|
public void testManagedWithInitializedAssociation() {
|
||||||
|
// Delete the Parent
|
||||||
|
doInHibernate( this::sessionFactory, s -> {
|
||||||
|
Parent loadedParent = (Parent) s.createQuery( "SELECT p FROM Parent p WHERE name=:name" )
|
||||||
|
.setParameter( "name", "PARENT" )
|
||||||
|
.uniqueResult();
|
||||||
|
checkInterceptor( loadedParent, false );
|
||||||
|
loadedParent.getChildren();
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( loadedParent, "children" ) );
|
||||||
|
s.delete( loadedParent );
|
||||||
|
} );
|
||||||
|
// If the lazy relation is not fetch on cascade there is a constraint violation on commit
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue(jiraKey = "HHH-13129")
|
||||||
|
public void testDetachedWithUninitializedAssociation() {
|
||||||
|
final Parent detachedParent = doInHibernate( this::sessionFactory, s -> {
|
||||||
|
return s.get( Parent.class, originalParent.getId() );
|
||||||
|
} );
|
||||||
|
|
||||||
|
assertFalse( Hibernate.isPropertyInitialized( detachedParent, "children" ) );
|
||||||
|
|
||||||
|
checkInterceptor( detachedParent, false );
|
||||||
|
|
||||||
|
// Delete the detached Parent with uninitialized children
|
||||||
|
doInHibernate( this::sessionFactory, s -> {
|
||||||
|
s.delete( detachedParent );
|
||||||
|
} );
|
||||||
|
// If the lazy relation is not fetch on cascade there is a constraint violation on commit
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue(jiraKey = "HHH-13129")
|
||||||
|
public void testDetachedWithInitializedAssociation() {
|
||||||
|
final Parent detachedParent = doInHibernate( this::sessionFactory, s -> {
|
||||||
|
Parent parent = s.get( Parent.class, originalParent.getId() );
|
||||||
|
assertFalse( Hibernate.isPropertyInitialized( parent, "children" ) );
|
||||||
|
|
||||||
|
// initialize collection before detaching
|
||||||
|
parent.getChildren();
|
||||||
|
return parent;
|
||||||
|
} );
|
||||||
|
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( detachedParent, "children" ) );
|
||||||
|
|
||||||
|
checkInterceptor( detachedParent, false );
|
||||||
|
|
||||||
|
// Delete the detached Parent with initialized children
|
||||||
|
doInHibernate( this::sessionFactory, s -> {
|
||||||
|
s.delete( detachedParent );
|
||||||
|
} );
|
||||||
|
// If the lazy relation is not fetch on cascade there is a constraint violation on commit
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue(jiraKey = "HHH-13129")
|
||||||
|
public void testDetachedOriginal() {
|
||||||
|
|
||||||
|
// originalParent#children should be initialized
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( originalParent, "children" ) );
|
||||||
|
|
||||||
|
checkInterceptor( originalParent, true );
|
||||||
|
|
||||||
|
// Delete the Parent
|
||||||
|
doInHibernate( this::sessionFactory, s -> {
|
||||||
|
s.delete( originalParent );
|
||||||
|
} );
|
||||||
|
// If the lazy relation is not fetch on cascade there is a constraint violation on commit
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkInterceptor(Parent parent, boolean isNullExpected) {
|
||||||
|
final BytecodeEnhancementMetadata bytecodeEnhancementMetadata =
|
||||||
|
sessionFactory()
|
||||||
|
.getMetamodel()
|
||||||
|
.entityPersister( Parent.class )
|
||||||
|
.getEntityMetamodel()
|
||||||
|
.getBytecodeEnhancementMetadata();
|
||||||
|
if ( isNullExpected ) {
|
||||||
|
// if a null Interceptor is expected, then there shouldn't be any uninitialized attributes
|
||||||
|
assertFalse( bytecodeEnhancementMetadata.hasUnFetchedAttributes( parent ) );
|
||||||
|
assertNull( bytecodeEnhancementMetadata.extractInterceptor( parent ) );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assertNotNull( bytecodeEnhancementMetadata.extractInterceptor( parent ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- //
|
||||||
|
|
||||||
|
@Entity( name = "Parent" )
|
||||||
|
@Table( name = "PARENT" )
|
||||||
|
public static class Parent {
|
||||||
|
|
||||||
|
Long id;
|
||||||
|
|
||||||
|
String name;
|
||||||
|
|
||||||
|
List<Child> children = new ArrayList<>();
|
||||||
|
|
||||||
|
String lazy;
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue( strategy = GenerationType.AUTO )
|
||||||
|
Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@OneToMany( mappedBy = "parent", cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE}, fetch = FetchType.LAZY )
|
||||||
|
List<Child> getChildren() {
|
||||||
|
return Collections.unmodifiableList( children );
|
||||||
|
}
|
||||||
|
|
||||||
|
void setChildren(List<Child> children) {
|
||||||
|
this.children = children;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Basic( fetch = FetchType.LAZY )
|
||||||
|
String getLazy() {
|
||||||
|
return lazy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLazy(String lazy) {
|
||||||
|
this.lazy = lazy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void makeChild() {
|
||||||
|
Child c = new Child();
|
||||||
|
c.setParent( this );
|
||||||
|
children.add( c );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table( name = "CHILD" )
|
||||||
|
private static class Child {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue( strategy = GenerationType.AUTO )
|
||||||
|
Long id;
|
||||||
|
|
||||||
|
@ManyToOne( optional = false )
|
||||||
|
@JoinColumn( name = "parent_id" )
|
||||||
|
Parent parent;
|
||||||
|
|
||||||
|
Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
Parent getParent() {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setParent(Parent parent) {
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,288 @@
|
||||||
|
/*
|
||||||
|
* 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.test.bytecode.enhancement.cascade;
|
||||||
|
|
||||||
|
import javax.persistence.Basic;
|
||||||
|
import javax.persistence.CascadeType;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.FetchType;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.GenerationType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
import org.hibernate.Hibernate;
|
||||||
|
import org.hibernate.annotations.LazyToOne;
|
||||||
|
import org.hibernate.annotations.LazyToOneOption;
|
||||||
|
import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
|
||||||
|
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||||
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Luis Barreiro
|
||||||
|
*/
|
||||||
|
@TestForIssue(jiraKey = "HHH-10252")
|
||||||
|
@RunWith(BytecodeEnhancerRunner.class)
|
||||||
|
public class CascadeDeleteManyToOneTest extends BaseCoreFunctionalTestCase {
|
||||||
|
private Child originalChild;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class[] { Parent.class, Child.class };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void prepare() {
|
||||||
|
// Create a Parent with one Child
|
||||||
|
originalChild = doInHibernate(
|
||||||
|
this::sessionFactory, s -> {
|
||||||
|
Child c = new Child();
|
||||||
|
c.setName( "CHILD" );
|
||||||
|
c.setLazy( "LAZY" );
|
||||||
|
c.makeParent();
|
||||||
|
s.persist( c );
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testManagedWithUninitializedAssociation() {
|
||||||
|
// Delete the Child
|
||||||
|
doInHibernate(
|
||||||
|
this::sessionFactory, s -> {
|
||||||
|
Child loadedChild = (Child) s.createQuery( "SELECT c FROM Child c WHERE name=:name" )
|
||||||
|
.setParameter( "name", "CHILD" )
|
||||||
|
.uniqueResult();
|
||||||
|
checkInterceptor( loadedChild, false );
|
||||||
|
assertFalse( Hibernate.isPropertyInitialized( loadedChild, "parent" ) );
|
||||||
|
s.delete( loadedChild );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// Explicitly check that both got deleted
|
||||||
|
doInHibernate(
|
||||||
|
this::sessionFactory, s -> {
|
||||||
|
assertNull( s.createQuery( "FROM Child c" ).uniqueResult() );
|
||||||
|
assertNull( s.createQuery( "FROM Parent p" ).uniqueResult() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testManagedWithInitializedAssociation() {
|
||||||
|
// Delete the Child
|
||||||
|
doInHibernate(
|
||||||
|
this::sessionFactory, s -> {
|
||||||
|
Child loadedChild = (Child) s.createQuery( "SELECT c FROM Child c WHERE name=:name" )
|
||||||
|
.setParameter( "name", "CHILD" )
|
||||||
|
.uniqueResult();
|
||||||
|
checkInterceptor( loadedChild, false );
|
||||||
|
loadedChild.getParent();
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( loadedChild, "parent" ) );
|
||||||
|
s.delete( loadedChild );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// Explicitly check that both got deleted
|
||||||
|
doInHibernate(
|
||||||
|
this::sessionFactory, s -> {
|
||||||
|
assertNull( s.createQuery( "FROM Child c" ).uniqueResult() );
|
||||||
|
assertNull( s.createQuery( "FROM Parent p" ).uniqueResult() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDetachedWithUninitializedAssociation() {
|
||||||
|
final Child detachedChild = doInHibernate(
|
||||||
|
this::sessionFactory, s -> {
|
||||||
|
return s.get( Child.class, originalChild.getId() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assertFalse( Hibernate.isPropertyInitialized( detachedChild, "parent" ) );
|
||||||
|
|
||||||
|
checkInterceptor( detachedChild, false );
|
||||||
|
|
||||||
|
// Delete the detached Child with uninitialized parent
|
||||||
|
doInHibernate(
|
||||||
|
this::sessionFactory, s -> {
|
||||||
|
s.delete( detachedChild );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// Explicitly check that both got deleted
|
||||||
|
doInHibernate(
|
||||||
|
this::sessionFactory, s -> {
|
||||||
|
assertNull( s.createQuery( "FROM Child c" ).uniqueResult() );
|
||||||
|
assertNull( s.createQuery( "FROM Parent p" ).uniqueResult() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDetachedWithInitializedAssociation() {
|
||||||
|
final Child detachedChild = doInHibernate(
|
||||||
|
this::sessionFactory, s -> {
|
||||||
|
Child child = s.get( Child.class, originalChild.getId() );
|
||||||
|
assertFalse( Hibernate.isPropertyInitialized( child, "parent" ) );
|
||||||
|
|
||||||
|
// initialize parent before detaching
|
||||||
|
child.getParent();
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( detachedChild, "parent" ) );
|
||||||
|
|
||||||
|
checkInterceptor( detachedChild, false );
|
||||||
|
|
||||||
|
// Delete the detached Child with initialized parent
|
||||||
|
doInHibernate(
|
||||||
|
this::sessionFactory, s -> {
|
||||||
|
s.delete( detachedChild );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// Explicitly check that both got deleted
|
||||||
|
doInHibernate(
|
||||||
|
this::sessionFactory, s -> {
|
||||||
|
assertNull( s.createQuery( "FROM Child c" ).uniqueResult() );
|
||||||
|
assertNull( s.createQuery( "FROM Parent p" ).uniqueResult() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDetachedOriginal() {
|
||||||
|
|
||||||
|
// originalChild#parent should be initialized
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( originalChild, "parent" ) );
|
||||||
|
|
||||||
|
checkInterceptor( originalChild, true );
|
||||||
|
|
||||||
|
// Delete the Child
|
||||||
|
doInHibernate(
|
||||||
|
this::sessionFactory, s -> {
|
||||||
|
s.delete( originalChild );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// Explicitly check that both got deleted
|
||||||
|
doInHibernate(
|
||||||
|
this::sessionFactory, s -> {
|
||||||
|
assertNull( s.createQuery( "FROM Child c" ).uniqueResult() );
|
||||||
|
assertNull( s.createQuery( "FROM Parent p" ).uniqueResult() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkInterceptor(Child child, boolean isNullExpected) {
|
||||||
|
final BytecodeEnhancementMetadata bytecodeEnhancementMetadata =
|
||||||
|
sessionFactory()
|
||||||
|
.getMetamodel()
|
||||||
|
.entityPersister( Child.class )
|
||||||
|
.getEntityMetamodel()
|
||||||
|
.getBytecodeEnhancementMetadata();
|
||||||
|
if ( isNullExpected ) {
|
||||||
|
// if a null Interceptor is expected, then there shouldn't be any uninitialized attributes
|
||||||
|
assertFalse( bytecodeEnhancementMetadata.hasUnFetchedAttributes( child ) );
|
||||||
|
assertNull( bytecodeEnhancementMetadata.extractInterceptor( child ) );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assertNotNull( bytecodeEnhancementMetadata.extractInterceptor( child ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- //
|
||||||
|
|
||||||
|
@Entity(name = "Parent")
|
||||||
|
@Table(name = "PARENT")
|
||||||
|
public static class Parent {
|
||||||
|
|
||||||
|
Long id;
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
|
Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Child")
|
||||||
|
@Table(name = "CHILD")
|
||||||
|
private static class Child {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
|
Long id;
|
||||||
|
|
||||||
|
String name;
|
||||||
|
|
||||||
|
@ManyToOne(optional = false, cascade = {
|
||||||
|
CascadeType.PERSIST,
|
||||||
|
CascadeType.MERGE,
|
||||||
|
CascadeType.REMOVE
|
||||||
|
}, fetch = FetchType.LAZY)
|
||||||
|
@JoinColumn(name = "parent_id")
|
||||||
|
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||||
|
Parent parent;
|
||||||
|
|
||||||
|
@Basic(fetch = FetchType.LAZY)
|
||||||
|
String lazy;
|
||||||
|
|
||||||
|
Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
Parent getParent() {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setParent(Parent parent) {
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getLazy() {
|
||||||
|
return lazy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLazy(String lazy) {
|
||||||
|
this.lazy = lazy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void makeParent() {
|
||||||
|
parent = new Parent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,156 +0,0 @@
|
||||||
/*
|
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
|
||||||
*
|
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
|
||||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
|
||||||
*/
|
|
||||||
package org.hibernate.test.bytecode.enhancement.cascade;
|
|
||||||
|
|
||||||
import org.hibernate.testing.TestForIssue;
|
|
||||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
|
||||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
import javax.persistence.Basic;
|
|
||||||
import javax.persistence.CascadeType;
|
|
||||||
import javax.persistence.Entity;
|
|
||||||
import javax.persistence.FetchType;
|
|
||||||
import javax.persistence.GeneratedValue;
|
|
||||||
import javax.persistence.GenerationType;
|
|
||||||
import javax.persistence.Id;
|
|
||||||
import javax.persistence.JoinColumn;
|
|
||||||
import javax.persistence.ManyToOne;
|
|
||||||
import javax.persistence.OneToMany;
|
|
||||||
import javax.persistence.Table;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Luis Barreiro
|
|
||||||
*/
|
|
||||||
@TestForIssue( jiraKey = "HHH-10252" )
|
|
||||||
@RunWith( BytecodeEnhancerRunner.class )
|
|
||||||
public class CascadeDeleteTest extends BaseCoreFunctionalTestCase {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Class<?>[] getAnnotatedClasses() {
|
|
||||||
return new Class[]{Parent.class, Child.class};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void prepare() {
|
|
||||||
// Create a Parent with one Child
|
|
||||||
doInHibernate( this::sessionFactory, s -> {
|
|
||||||
Parent p = new Parent();
|
|
||||||
p.setName( "PARENT" );
|
|
||||||
p.setLazy( "LAZY" );
|
|
||||||
p.makeChild();
|
|
||||||
s.persist( p );
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void test() {
|
|
||||||
// Delete the Parent
|
|
||||||
doInHibernate( this::sessionFactory, s -> {
|
|
||||||
Parent loadedParent = (Parent) s.createQuery( "SELECT p FROM Parent p WHERE name=:name" )
|
|
||||||
.setParameter( "name", "PARENT" )
|
|
||||||
.uniqueResult();
|
|
||||||
|
|
||||||
s.delete( loadedParent );
|
|
||||||
} );
|
|
||||||
// If the lazy relation is not fetch on cascade there is a constraint violation on commit
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- //
|
|
||||||
|
|
||||||
@Entity( name = "Parent" )
|
|
||||||
@Table( name = "PARENT" )
|
|
||||||
public static class Parent {
|
|
||||||
|
|
||||||
Long id;
|
|
||||||
|
|
||||||
String name;
|
|
||||||
|
|
||||||
List<Child> children = new ArrayList<>();
|
|
||||||
|
|
||||||
String lazy;
|
|
||||||
|
|
||||||
@Id
|
|
||||||
@GeneratedValue( strategy = GenerationType.AUTO )
|
|
||||||
Long getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setId(Long id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
@OneToMany( mappedBy = "parent", cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE}, fetch = FetchType.LAZY )
|
|
||||||
List<Child> getChildren() {
|
|
||||||
return Collections.unmodifiableList( children );
|
|
||||||
}
|
|
||||||
|
|
||||||
void setChildren(List<Child> children) {
|
|
||||||
this.children = children;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Basic( fetch = FetchType.LAZY )
|
|
||||||
String getLazy() {
|
|
||||||
return lazy;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setLazy(String lazy) {
|
|
||||||
this.lazy = lazy;
|
|
||||||
}
|
|
||||||
|
|
||||||
void makeChild() {
|
|
||||||
Child c = new Child();
|
|
||||||
c.setParent( this );
|
|
||||||
children.add( c );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Entity
|
|
||||||
@Table( name = "CHILD" )
|
|
||||||
private static class Child {
|
|
||||||
|
|
||||||
@Id
|
|
||||||
@GeneratedValue( strategy = GenerationType.AUTO )
|
|
||||||
Long id;
|
|
||||||
|
|
||||||
@ManyToOne( optional = false )
|
|
||||||
@JoinColumn( name = "parent_id" )
|
|
||||||
Parent parent;
|
|
||||||
|
|
||||||
Long getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setId(Long id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
Parent getParent() {
|
|
||||||
return parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setParent(Parent parent) {
|
|
||||||
this.parent = parent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,286 @@
|
||||||
|
package org.hibernate.test.bytecode.enhancement.cascade;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import javax.persistence.CascadeType;
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.FetchType;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.persistence.OneToMany;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
import org.hibernate.Hibernate;
|
||||||
|
import org.hibernate.annotations.LazyToOne;
|
||||||
|
import org.hibernate.annotations.LazyToOneOption;
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||||
|
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||||
|
import org.hibernate.testing.transaction.TransactionUtil;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import static junit.framework.TestCase.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Bolek Ziobrowski
|
||||||
|
* @author Gail Badner
|
||||||
|
*/
|
||||||
|
@RunWith(BytecodeEnhancerRunner.class)
|
||||||
|
@TestForIssue(jiraKey = "HHH-13129")
|
||||||
|
public class CascadeOnUninitializedTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class<?>[] {
|
||||||
|
Person.class,
|
||||||
|
Address.class,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addSettings(Map settings) {
|
||||||
|
super.addSettings( settings );
|
||||||
|
settings.put( AvailableSettings.SHOW_SQL, "true" );
|
||||||
|
settings.put( AvailableSettings.FORMAT_SQL, "true" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMergeDetachedEnhancedEntityWithUninitializedManyToOne() {
|
||||||
|
|
||||||
|
Person person = persistPersonWithManyToOne();
|
||||||
|
|
||||||
|
// get a detached Person
|
||||||
|
Person detachedPerson = TransactionUtil.doInHibernate(
|
||||||
|
this::sessionFactory, session -> {
|
||||||
|
return session.get( Person.class, person.getId() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// address should not be initialized
|
||||||
|
assertFalse( Hibernate.isPropertyInitialized( detachedPerson, "primaryAddress" ) );
|
||||||
|
detachedPerson.setName( "newName" );
|
||||||
|
|
||||||
|
Person mergedPerson = TransactionUtil.doInHibernate(
|
||||||
|
this::sessionFactory, session -> {
|
||||||
|
return (Person) session.merge( detachedPerson );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// address should not be initialized
|
||||||
|
assertFalse( Hibernate.isPropertyInitialized( mergedPerson, "primaryAddress" ) );
|
||||||
|
assertEquals( "newName", mergedPerson.getName() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteEnhancedEntityWithUninitializedManyToOne() {
|
||||||
|
Person person = persistPersonWithManyToOne();
|
||||||
|
|
||||||
|
// get a detached Person
|
||||||
|
Person detachedPerson = TransactionUtil.doInHibernate(
|
||||||
|
this::sessionFactory, session -> {
|
||||||
|
return session.get( Person.class, person.getId() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// address should not be initialized
|
||||||
|
assertFalse( Hibernate.isPropertyInitialized( detachedPerson, "primaryAddress" ) );
|
||||||
|
|
||||||
|
// deleting detachedPerson should result in detachedPerson.address being initialized,
|
||||||
|
// so that the DELETE operation can be cascaded to it.
|
||||||
|
TransactionUtil.doInHibernate(
|
||||||
|
this::sessionFactory, session -> {
|
||||||
|
session.delete( detachedPerson );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// both the Person and its Address should be deleted
|
||||||
|
TransactionUtil.doInHibernate(
|
||||||
|
this::sessionFactory, session -> {
|
||||||
|
assertNull( session.get( Person.class, person.getId() ) );
|
||||||
|
assertNull( session.get( Person.class, person.getPrimaryAddress().getId() ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMergeDetachedEnhancedEntityWithUninitializedOneToMany() {
|
||||||
|
|
||||||
|
Person person = persistPersonWithOneToMany();
|
||||||
|
|
||||||
|
// get a detached Person
|
||||||
|
Person detachedPerson = TransactionUtil.doInHibernate(
|
||||||
|
this::sessionFactory, session -> {
|
||||||
|
return session.get( Person.class, person.getId() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// address should not be initialized
|
||||||
|
assertFalse( Hibernate.isPropertyInitialized( detachedPerson, "addresses" ) );
|
||||||
|
detachedPerson.setName( "newName" );
|
||||||
|
|
||||||
|
Person mergedPerson = TransactionUtil.doInHibernate(
|
||||||
|
this::sessionFactory, session -> {
|
||||||
|
return (Person) session.merge( detachedPerson );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// address should be initialized
|
||||||
|
assertTrue( Hibernate.isPropertyInitialized( mergedPerson, "addresses" ) );
|
||||||
|
assertEquals( "newName", mergedPerson.getName() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteEnhancedEntityWithUninitializedOneToMany() {
|
||||||
|
Person person = persistPersonWithOneToMany();
|
||||||
|
|
||||||
|
// get a detached Person
|
||||||
|
Person detachedPerson = TransactionUtil.doInHibernate(
|
||||||
|
this::sessionFactory, session -> {
|
||||||
|
return session.get( Person.class, person.getId() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// address should not be initialized
|
||||||
|
assertFalse( Hibernate.isPropertyInitialized( detachedPerson, "addresses" ) );
|
||||||
|
|
||||||
|
// deleting detachedPerson should result in detachedPerson.address being initialized,
|
||||||
|
// so that the DELETE operation can be cascaded to it.
|
||||||
|
TransactionUtil.doInHibernate(
|
||||||
|
this::sessionFactory, session -> {
|
||||||
|
session.delete( detachedPerson );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// both the Person and its Address should be deleted
|
||||||
|
TransactionUtil.doInHibernate(
|
||||||
|
this::sessionFactory, session -> {
|
||||||
|
assertNull( session.get( Person.class, person.getId() ) );
|
||||||
|
assertNull( session.get( Person.class, person.getAddresses().iterator().next().getId() ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Person persistPersonWithManyToOne() {
|
||||||
|
Address address = new Address();
|
||||||
|
address.setDescription( "ABC" );
|
||||||
|
|
||||||
|
final Person person = new Person();
|
||||||
|
person.setName( "John Doe" );
|
||||||
|
person.setPrimaryAddress( address );
|
||||||
|
|
||||||
|
TransactionUtil.doInHibernate(
|
||||||
|
this::sessionFactory, session -> {
|
||||||
|
session.persist( person );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return person;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Person persistPersonWithOneToMany() {
|
||||||
|
Address address = new Address();
|
||||||
|
address.setDescription( "ABC" );
|
||||||
|
|
||||||
|
final Person person = new Person();
|
||||||
|
person.setName( "John Doe" );
|
||||||
|
person.getAddresses().add( address );
|
||||||
|
|
||||||
|
TransactionUtil.doInHibernate(
|
||||||
|
this::sessionFactory, session -> {
|
||||||
|
session.persist( person );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return person;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "TEST_PERSON")
|
||||||
|
public static class Person {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(name = "NAME", length = 300, nullable = true)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@ManyToOne(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY)
|
||||||
|
@JoinColumn(name = "ADDRESS_ID")
|
||||||
|
@LazyToOne(LazyToOneOption.NO_PROXY)
|
||||||
|
private Address primaryAddress;
|
||||||
|
|
||||||
|
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
||||||
|
@JoinColumn
|
||||||
|
private Set<Address> addresses = new HashSet<>();
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Address getPrimaryAddress() {
|
||||||
|
return primaryAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPrimaryAddress(Address primaryAddress) {
|
||||||
|
this.primaryAddress = primaryAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Address> getAddresses() {
|
||||||
|
return addresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddresses(Set<Address> addresses) {
|
||||||
|
this.addresses = addresses;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "TEST_ADDRESS")
|
||||||
|
public static class Address {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(name = "DESCRIPTION", length = 300, nullable = true)
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ import static org.junit.Assert.fail;
|
||||||
@TestForIssue( jiraKey = "HHH-11459" )
|
@TestForIssue( jiraKey = "HHH-11459" )
|
||||||
@RunWith( BytecodeEnhancerRunner.class )
|
@RunWith( BytecodeEnhancerRunner.class )
|
||||||
public class MergeEnhancedEntityTest extends BaseCoreFunctionalTestCase {
|
public class MergeEnhancedEntityTest extends BaseCoreFunctionalTestCase {
|
||||||
|
private Person person;
|
||||||
@Override
|
@Override
|
||||||
public Class<?>[] getAnnotatedClasses() {
|
public Class<?>[] getAnnotatedClasses() {
|
||||||
return new Class<?>[]{Person.class, PersonAddress.class};
|
return new Class<?>[]{Person.class, PersonAddress.class};
|
||||||
|
@ -42,8 +42,9 @@ public class MergeEnhancedEntityTest extends BaseCoreFunctionalTestCase {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void prepare() {
|
public void prepare() {
|
||||||
|
person = new Person( 1L, "Sam" );
|
||||||
doInHibernate( this::sessionFactory, s -> {
|
doInHibernate( this::sessionFactory, s -> {
|
||||||
s.persist( new Person( 1L, "Sam" ) );
|
s.persist( person );
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +77,7 @@ public class MergeEnhancedEntityTest extends BaseCoreFunctionalTestCase {
|
||||||
@After
|
@After
|
||||||
public void cleanup() {
|
public void cleanup() {
|
||||||
doInHibernate( this::sessionFactory, s -> {
|
doInHibernate( this::sessionFactory, s -> {
|
||||||
s.delete( new Person( 1L, "Sam" ) );
|
s.delete( person );
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue