/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.test.jpa.cascade;
import org.jboss.logging.Logger;
import org.hibernate.Session;
import org.hibernate.TransientObjectException;
import static org.junit.Assert.fail;
import org.junit.Test;
import org.hibernate.test.jpa.AbstractJPATest;
/**
* According to the JPA spec, persist()ing an entity should throw an exception
* when said entity contains a reference to a transient entity through a mapped
* association where that association is not marked for cascading the persist
* operation.
* <p/>
* This test-case tests that requirement in the various association style
* scenarios such as many-to-one, one-to-one, many-to-one (property-ref),
* one-to-one (property-ref). Additionally, it performs each of these tests
* in both generated and assigned identifier usages...
*
* @author Steve Ebersole
*/
public class CascadeTest extends AbstractJPATest {
private static final Logger log = Logger.getLogger( CascadeTest.class );
public String[] getMappings() {
return new String[] { "jpa/cascade/ParentChild.hbm.xml" };
}
@Test
public void testManyToOneGeneratedIdsOnSave() {
// NOTES: Child defines a many-to-one back to its Parent. This
// association does not define persist cascading (which is natural;
// a child should not be able to create its parent).
try {
Session s = openSession();
s.beginTransaction();
Parent p = new Parent( "parent" );
Child c = new Child( "child" );
c.setParent( p );
s.save( c );
try {
s.getTransaction().commit();
fail( "expecting TransientObjectException on flush" );
}
catch( TransientObjectException e ) {
// expected result
log.trace( "handled expected exception", e );
s.getTransaction().rollback();
}
finally {
s.close();
}
}
finally {
cleanupData();
}
}
public void testManyToOneGeneratedIds() {
// NOTES: Child defines a many-to-one back to its Parent. This
// association does not define persist cascading (which is natural;
// a child should not be able to create its parent).
try {
Session s = openSession();
s.beginTransaction();
Parent p = new Parent( "parent" );
Child c = new Child( "child" );
c.setParent( p );
s.persist( c );
try {
s.getTransaction().commit();
fail( "expecting TransientObjectException on flush" );
}
catch( TransientObjectException e ) {
// expected result
log.trace( "handled expected exception", e );
s.getTransaction().rollback();
}
finally {
s.close();
}
}
finally {
cleanupData();
}
}
public void testManyToOneAssignedIds() {
// NOTES: Child defines a many-to-one back to its Parent. This
// association does not define persist cascading (which is natural;
// a child should not be able to create its parent).
try {
Session s = openSession();
s.beginTransaction();
ParentAssigned p = new ParentAssigned( new Long( 1 ), "parent" );
ChildAssigned c = new ChildAssigned( new Long( 2 ), "child" );
c.setParent( p );
s.persist( c );
try {
s.getTransaction().commit();
fail( "expecting TransientObjectException on flush" );
}
catch( TransientObjectException e ) {
// expected result
log.trace( "handled expected exception", e );
s.getTransaction().rollback();
}
finally {
s.close();
}
}
finally {
cleanupData();
}
}
public void testOneToOneGeneratedIds() {
try {
Session s = openSession();
s.beginTransaction();
Parent p = new Parent( "parent" );
ParentInfo info = new ParentInfo( "xyz" );
p.setInfo( info );
info.setOwner( p );
s.persist( p );
try {
s.getTransaction().commit();
fail( "expecting TransientObjectException on flush" );
}
catch( TransientObjectException e ) {
// expected result
log.trace( "handled expected exception", e );
s.getTransaction().rollback();
}
finally {
s.close();
}
}
finally {
cleanupData();
}
}
public void testOneToOneAssignedIds() {
try {
Session s = openSession();
s.beginTransaction();
ParentAssigned p = new ParentAssigned( new Long( 1 ), "parent" );
ParentInfoAssigned info = new ParentInfoAssigned( "something secret" );
p.setInfo( info );
info.setOwner( p );
s.persist( p );
try {
s.getTransaction().commit();
fail( "expecting TransientObjectException on flush" );
}
catch( TransientObjectException e ) {
// expected result
log.trace( "handled expected exception", e );
s.getTransaction().rollback();
}
finally {
s.close();
}
}
finally {
cleanupData();
}
}
public void testManyToOnePropertyRefGeneratedIds() {
try {
Session s = openSession();
s.beginTransaction();
Parent p = new Parent( "parent" );
Other other = new Other();
other.setOwner( p );
s.persist( other );
try {
s.getTransaction().commit();
fail( "expecting TransientObjectException on flush" );
}
catch( TransientObjectException e ) {
// expected result
log.trace( "handled expected exception", e );
s.getTransaction().rollback();
}
finally {
s.close();
}
}
finally {
cleanupData();
}
}
public void testManyToOnePropertyRefAssignedIds() {
try {
Session s = openSession();
s.beginTransaction();
ParentAssigned p = new ParentAssigned( new Long( 1 ), "parent" );
OtherAssigned other = new OtherAssigned( new Long( 2 ) );
other.setOwner( p );
s.persist( other );
try {
s.getTransaction().commit();
fail( "expecting TransientObjectException on flush" );
}
catch( TransientObjectException e ) {
// expected result
log.trace( "handled expected exception", e );
s.getTransaction().rollback();
}
finally {
s.close();
}
}
finally {
cleanupData();
}
}
public void testOneToOnePropertyRefGeneratedIds() {
try {
Session s = openSession();
s.beginTransaction();
Child c2 = new Child( "c2" );
ChildInfo info = new ChildInfo( "blah blah blah" );
c2.setInfo( info );
info.setOwner( c2 );
s.persist( c2 );
try {
s.getTransaction().commit();
fail( "expecting TransientObjectException on flush" );
}
catch( TransientObjectException e ) {
// expected result
log.trace( "handled expected exception : " + e );
s.getTransaction().rollback();
}
finally {
s.close();
}
}
finally {
cleanupData();
}
}
public void testOneToOnePropertyRefAssignedIds() {
try {
Session s = openSession();
s.beginTransaction();
ChildAssigned c2 = new ChildAssigned( new Long( 3 ), "c3" );
ChildInfoAssigned info = new ChildInfoAssigned( new Long( 4 ), "blah blah blah" );
c2.setInfo( info );
info.setOwner( c2 );
s.persist( c2 );
try {
s.getTransaction().commit();
fail( "expecting TransientObjectException on flush" );
}
catch( TransientObjectException e ) {
// expected result
log.trace( "handled expected exception : " + e );
s.getTransaction().rollback();
}
finally {
s.close();
}
}
finally {
cleanupData();
}
}
private void cleanupData() {
Session s = null;
try {
s = openSession();
s.beginTransaction();
s.createQuery( "delete ChildInfoAssigned" ).executeUpdate();
s.createQuery( "delete ChildAssigned" ).executeUpdate();
s.createQuery( "delete ParentAssigned" ).executeUpdate();
s.createQuery( "delete ChildInfoAssigned" ).executeUpdate();
s.createQuery( "delete ChildAssigned" ).executeUpdate();
s.createQuery( "delete ParentAssigned" ).executeUpdate();
s.getTransaction().commit();
}
catch( Throwable t ) {
log.warn( "unable to cleanup test data : " + t );
}
finally {
if ( s != null ) {
try {
s.close();
}
catch( Throwable ignore ) {
}
}
}
}
}