From 165f2e5f736db18ec5262fad3e2644e460502cdc Mon Sep 17 00:00:00 2001 From: Scott Marlow Date: Tue, 22 Dec 2009 18:07:38 +0000 Subject: [PATCH] HHH-4601 implement orphanRemoval for OneToMany. OneToOne is not yet done (see HHH-4725) git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@18318 1b8cb986-b30d-0410-93ca-fae66ebed9b2 --- .../org/hibernate/cfg/AnnotationBinder.java | 24 ++++--- .../entity/BasicHibernateAnnotationsTest.java | 54 ++++++++++++++- .../test/annotations/entity/Player.java | 65 +++++++++++++++++++ .../test/annotations/entity/SoccerTeam.java | 63 ++++++++++++++++++ 4 files changed, 195 insertions(+), 11 deletions(-) create mode 100644 annotations/src/test/java/org/hibernate/test/annotations/entity/Player.java create mode 100644 annotations/src/test/java/org/hibernate/test/annotations/entity/SoccerTeam.java diff --git a/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java b/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java index 286c79e126..39c2894d27 100644 --- a/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java +++ b/annotations/src/main/java/org/hibernate/cfg/AnnotationBinder.java @@ -1,4 +1,4 @@ -// $Id:$ +// $Id$ /* * Hibernate, Relational Persistence for Idiomatic Java * @@ -1486,7 +1486,7 @@ public final class AnnotationBinder { } } bindManyToOne( - getCascadeStrategy( ann.cascade(), hibernateCascade ), + getCascadeStrategy( ann.cascade(), hibernateCascade, false), joinColumns, ann.optional(), ignoreNotFound, onDeleteCascade, @@ -1521,7 +1521,7 @@ public final class AnnotationBinder { } } bindOneToOne( - getCascadeStrategy( ann.cascade(), hibernateCascade ), + getCascadeStrategy( ann.cascade(), hibernateCascade, false), joinColumns, ann.optional(), getFetchMode( ann.fetch() ), @@ -1550,7 +1550,7 @@ public final class AnnotationBinder { joinColumn.setSecondaryTableName( join.getTable().getName() ); } } - bindAny( getCascadeStrategy( null, hibernateCascade ), //@Any has not cascade attribute + bindAny( getCascadeStrategy( null, hibernateCascade, false), //@Any has not cascade attribute joinColumns, onDeleteCascade, nullability, propertyHolder, inferredData, entityBinder, isIdentifierMapper, mappings ); @@ -1756,7 +1756,8 @@ public final class AnnotationBinder { collectionBinder.setTargetEntity( mappings.getReflectionManager().toXClass( oneToManyAnn.targetEntity() ) ); - collectionBinder.setCascadeStrategy( getCascadeStrategy( oneToManyAnn.cascade(), hibernateCascade ) ); + collectionBinder.setCascadeStrategy( + getCascadeStrategy( oneToManyAnn.cascade(), hibernateCascade, oneToManyAnn.orphanRemoval()) ); collectionBinder.setOneToMany( true ); } else if ( elementCollectionAnn != null @@ -1783,7 +1784,7 @@ public final class AnnotationBinder { collectionBinder.setTargetEntity( mappings.getReflectionManager().toXClass( manyToManyAnn.targetEntity() ) ); - collectionBinder.setCascadeStrategy( getCascadeStrategy( manyToManyAnn.cascade(), hibernateCascade ) ); + collectionBinder.setCascadeStrategy( getCascadeStrategy( manyToManyAnn.cascade(), hibernateCascade, false) ); collectionBinder.setOneToMany( false ); } else if ( property.isAnnotationPresent( ManyToAny.class ) ) { @@ -1791,7 +1792,7 @@ public final class AnnotationBinder { collectionBinder.setTargetEntity( mappings.getReflectionManager().toXClass( void.class ) ); - collectionBinder.setCascadeStrategy( getCascadeStrategy( null, hibernateCascade ) ); + collectionBinder.setCascadeStrategy( getCascadeStrategy( null, hibernateCascade, false) ); collectionBinder.setOneToMany( false ); } collectionBinder.setMappedBy( mappedBy ); @@ -2464,8 +2465,8 @@ public final class AnnotationBinder { } private static String getCascadeStrategy( - javax.persistence.CascadeType[] ejbCascades, Cascade hibernateCascadeAnnotation - ) { + javax.persistence.CascadeType[] ejbCascades, Cascade hibernateCascadeAnnotation, + boolean orphanRemoval) { EnumSet hibernateCascadeSet = convertToHibernateCascadeType( ejbCascades ); CascadeType[] hibernateCascades = hibernateCascadeAnnotation == null ? null : @@ -2475,6 +2476,11 @@ public final class AnnotationBinder { hibernateCascadeSet.addAll( Arrays.asList( hibernateCascades ) ); } + if ( orphanRemoval ) { + hibernateCascadeSet.add(CascadeType.DELETE_ORPHAN); + hibernateCascadeSet.add(CascadeType.REMOVE); + } + StringBuilder cascade = new StringBuilder(); for ( CascadeType aHibernateCascadeSet : hibernateCascadeSet ) { switch ( aHibernateCascadeSet ) { diff --git a/annotations/src/test/java/org/hibernate/test/annotations/entity/BasicHibernateAnnotationsTest.java b/annotations/src/test/java/org/hibernate/test/annotations/entity/BasicHibernateAnnotationsTest.java index cb673ec15a..71e1e4ba00 100644 --- a/annotations/src/test/java/org/hibernate/test/annotations/entity/BasicHibernateAnnotationsTest.java +++ b/annotations/src/test/java/org/hibernate/test/annotations/entity/BasicHibernateAnnotationsTest.java @@ -309,7 +309,55 @@ public class BasicHibernateAnnotationsTest extends TestCase { s.close(); } - + + public void testCascadedDeleteOfChildEntitiesBug2() { + // Relationship is one SoccerTeam to many Players. + // Create a SoccerTeam (parent) and three Players (child). + // Verify that the count of Players is correct. + // Clear the SoccerTeam reference Players. + // The orphanRemoval should remove the Players automatically. + // @OneToMany(mappedBy="name", orphanRemoval=true) + Session s = openSession(); + Transaction tx = s.beginTransaction(); + + SoccerTeam team = new SoccerTeam(); + int teamid = team.getId(); + Player player1 = new Player(); + player1.setName("Shalrie Joseph"); + team.addPlayer(player1); + + Player player2 = new Player(); + player2.setName("Taylor Twellman"); + team.addPlayer(player2); + + Player player3 = new Player(); + player3.setName("Steve Ralston"); + team.addPlayer(player3); + s.persist(team); + tx.commit(); + s.close(); + + s = openSession(); + tx = s.beginTransaction(); + team = (SoccerTeam)s.merge(team); + int count = ( (Long) s.createQuery( "select count(*) from Player" ).iterate().next() ).intValue(); + assertEquals("expected count of 3 but got = " + count, count, 3); + + // clear references to players, this should orphan the players which should + // in turn trigger orphanRemoval logic. + team.getPlayers().clear(); +// count = ( (Long) s.createQuery( "select count(*) from Player" ).iterate().next() ).intValue(); +// assertEquals("expected count of 0 but got = " + count, count, 0); + tx.commit(); + s.close(); + + s = openSession(); + tx = s.beginTransaction(); + count = ( (Long) s.createQuery( "select count(*) from Player" ).iterate().next() ).intValue(); + assertEquals("expected count of 0 but got = " + count, count, 0); + tx.commit(); + s.close(); + } public void testFilter() throws Exception { Session s; @@ -581,7 +629,9 @@ public class BasicHibernateAnnotationsTest extends TestCase { Topic.class, Narrative.class, Drill.class, - PowerDrill.class + PowerDrill.class, + SoccerTeam.class, + Player.class }; } diff --git a/annotations/src/test/java/org/hibernate/test/annotations/entity/Player.java b/annotations/src/test/java/org/hibernate/test/annotations/entity/Player.java new file mode 100644 index 0000000000..4c85cb7b4e --- /dev/null +++ b/annotations/src/test/java/org/hibernate/test/annotations/entity/Player.java @@ -0,0 +1,65 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2009, Red Hat, Inc. and/or its affiliates 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.annotations.entity; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.ManyToOne; + + +@Entity +public class Player { + + private int id; + private String name; + private SoccerTeam team; + + @Id + @GeneratedValue + public int getId() { + return id; + } + public void setId(int id) { + this.id = id; + } + + @Column(name="name") + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + @ManyToOne + public SoccerTeam getTeam() { + return team; + } + public void setTeam(SoccerTeam team) { + this.team = team; + } +} \ No newline at end of file diff --git a/annotations/src/test/java/org/hibernate/test/annotations/entity/SoccerTeam.java b/annotations/src/test/java/org/hibernate/test/annotations/entity/SoccerTeam.java new file mode 100644 index 0000000000..21cc0990f6 --- /dev/null +++ b/annotations/src/test/java/org/hibernate/test/annotations/entity/SoccerTeam.java @@ -0,0 +1,63 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2009, Red Hat, Inc. and/or its affiliates 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.annotations.entity; + +import java.util.HashSet; +import java.util.Set; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.OneToMany; + +@Entity +public class SoccerTeam { + @Id + @GeneratedValue + private int id; + @OneToMany(mappedBy="team", + orphanRemoval=true, + cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH}) + private Set players = new HashSet(); + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public Set getPlayers() { + return players; + } + + public void addPlayer(Player val) { + players.add(val); + val.setTeam(this); + } + +} \ No newline at end of file