Skip to content

Commit 5799c27

Browse files
author
graeme
committed
fix for GRAILS-1553
git-svn-id: https://svn.codehaus.org/grails/trunk@5345 1cfb16fd-6d17-0410-8ff1-b7e8e1e2867d
1 parent ec1c3a3 commit 5799c27

File tree

2 files changed

+126
-44
lines changed

2 files changed

+126
-44
lines changed

src/persistence/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsDomainBinder.java

Lines changed: 61 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,66 +1112,83 @@ private static void bindProperty(GrailsDomainClassProperty grailsProperty, Prope
11121112
prop.setUpdateable(true);
11131113
prop.setPropertyAccessorName( mappings.getDefaultAccess() );
11141114
prop.setOptional( grailsProperty.isOptional() );
1115-
// set to cascade all for the moment
1116-
if(grailsProperty.isAssociation()) {
1117-
1118-
// for a one-to-many relationship we cascade all updates if it is the owning side
1119-
// otherwise we cascade only saves and updates
1120-
if(grailsProperty.isOneToMany()) {
1121-
if(grailsProperty.isOwningSide())
1122-
prop.setCascade(CASCADE_ALL);
1115+
String cascadeStrategy = "none";
1116+
// set to cascade all for the moment
1117+
GrailsDomainClass domainClass = grailsProperty.getDomainClass();
1118+
if(grailsProperty.isAssociation()) {
1119+
GrailsDomainClass referenced = grailsProperty.getReferencedDomainClass();
1120+
1121+
if(grailsProperty.isOneToOne()) {
1122+
if(referenced!=null&&referenced.isOwningClass(domainClass.getClazz()))
1123+
cascadeStrategy = CASCADE_ALL;
1124+
}
1125+
else if(grailsProperty.isOneToMany()) {
1126+
if(referenced!=null&&referenced.isOwningClass(domainClass.getClazz()))
1127+
cascadeStrategy = CASCADE_ALL;
11231128
else
1124-
prop.setCascade(CASCADE_SAVE_UPDATE);
1129+
cascadeStrategy = CASCADE_SAVE_UPDATE;
11251130
}
1126-
// for many-to-many relationships we only cascade saves and updates from the owning side
11271131
else if(grailsProperty.isManyToMany()) {
1128-
if(grailsProperty.isOwningSide()) {
1129-
prop.setCascade(CASCADE_SAVE_UPDATE);
1130-
}
1132+
if(referenced!=null&&referenced.isOwningClass(domainClass.getClazz()))
1133+
cascadeStrategy = CASCADE_SAVE_UPDATE;
11311134
}
1132-
// in the case of a many-to-one which is implicitly bidirectional we check whether it is the
1133-
// owning side and if so cascade otherwise only merge to deal with transient or detached instances
11341135
else if(grailsProperty.isManyToOne()) {
1135-
GrailsDomainClass domainClass = grailsProperty.getDomainClass();
1136-
1137-
if(!domainClass.isOwningClass(grailsProperty.getType())) {
1138-
prop.setCascade(CASCADE_ALL);
1139-
}
1140-
else {
1141-
GrailsDomainClassProperty otherSide = grailsProperty.getOtherSide();
1142-
if(otherSide != null && otherSide.isOneToMany()) {
1143-
prop.setCascade(CASCADE_MERGE);
1144-
}
1145-
else if(grailsProperty.isOwningSide()) {
1146-
prop.setCascade(CASCADE_ALL);
1147-
}
1148-
}
1149-
}
1150-
// in a one-to-one we check if it is un-directional and the other side is an owning side and then cascade
1151-
// otherwise if is the ownside we cascade all
1152-
else if(grailsProperty.isOneToOne()) {
1153-
GrailsDomainClass domainClass = grailsProperty.getDomainClass();
1154-
if(!grailsProperty.isBidirectional() && domainClass.isOwningClass(grailsProperty.getType())) {
1155-
prop.setCascade(CASCADE_ALL);
1156-
}
1157-
else if(grailsProperty.isOwningSide()) {
1158-
prop.setCascade(CASCADE_ALL);
1159-
}
1136+
if(referenced!=null&&referenced.isOwningClass(domainClass.getClazz()))
1137+
cascadeStrategy = CASCADE_ALL;
1138+
else
1139+
cascadeStrategy = CASCADE_MERGE;
11601140
}
1141+
1142+
logCascadeMapping(grailsProperty, cascadeStrategy, referenced);
1143+
prop.setCascade(cascadeStrategy);
11611144
}
11621145
else if( Map.class.isAssignableFrom(grailsProperty.getType())) {
1163-
prop.setCascade(CASCADE_ALL);
1146+
GrailsDomainClass referenced = grailsProperty.getReferencedDomainClass();
1147+
if(referenced!=null&&referenced.isOwningClass(grailsProperty.getDomainClass().getClazz())) {
1148+
cascadeStrategy = CASCADE_ALL;
1149+
}
1150+
else {
1151+
cascadeStrategy = CASCADE_SAVE_UPDATE;
1152+
}
1153+
logCascadeMapping(grailsProperty, cascadeStrategy, referenced);
1154+
prop.setCascade(cascadeStrategy);
1155+
11641156
}
11651157

11661158

1167-
if(LOG.isTraceEnabled())
1168-
LOG.trace( "[GrailsDomainBinder] Set cascading strategy on property ["+grailsProperty.getName()+"] to ["+prop.getCascade()+"]" );
11691159
// lazy to true
11701160
prop.setLazy(true);
11711161

11721162
}
11731163

1174-
/**
1164+
private static void logCascadeMapping(GrailsDomainClassProperty grailsProperty, String cascadeStrategy, GrailsDomainClass referenced) {
1165+
if(LOG.isDebugEnabled()) {
1166+
String assType = getAssociationDescription(grailsProperty);
1167+
LOG.debug("Mapping cascade strategy for "+assType+" property "+grailsProperty.getDomainClass().getFullName()+"." + grailsProperty.getName() + " referencing type ["+referenced.getClazz()+"] -> [CASCADE: "+cascadeStrategy+"]");
1168+
}
1169+
}
1170+
1171+
private static String getAssociationDescription(GrailsDomainClassProperty grailsProperty) {
1172+
String assType = "unknown";
1173+
if(grailsProperty.isManyToMany()) {
1174+
assType = "many-to-many";
1175+
}
1176+
else if(grailsProperty.isOneToMany()) {
1177+
assType = "one-to-many";
1178+
}
1179+
else if(grailsProperty.isOneToOne()) {
1180+
assType = "one-to-one";
1181+
}
1182+
else if(grailsProperty.isManyToOne()) {
1183+
assType = "many-to-one";
1184+
}
1185+
else if(grailsProperty.isEmbedded()) {
1186+
assType = "embedded";
1187+
}
1188+
return assType;
1189+
}
1190+
1191+
/**
11751192
w * Binds a simple value to the Hibernate metamodel. A simple value is
11761193
* any type within the Hibernate type system
11771194
*
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* Class description here.
3+
4+
* @author Graeme Rocher
5+
* @since 0.4
6+
*
7+
* Created: Aug 29, 2007
8+
* Time: 7:36:48 PM
9+
*
10+
*/
11+
package org.codehaus.groovy.grails.orm.hibernate
12+
13+
import org.codehaus.groovy.grails.commons.GrailsDomainClass
14+
15+
class CascadingDeleteBehaviour3Tests extends AbstractGrailsHibernateTests {
16+
17+
18+
void testDeleteToOne() {
19+
def roleClass = ga.getDomainClass("Role")
20+
def userRoleClass = ga.getDomainClass("UserRole")
21+
22+
def r = roleClass.newInstance()
23+
r.name = "Administrator"
24+
r.save()
25+
26+
session.flush()
27+
def ur = userRoleClass.newInstance()
28+
29+
ur.role = r
30+
ur.username = "Fred"
31+
ur.save()
32+
33+
session.flush()
34+
session.clear()
35+
36+
ur = userRoleClass.clazz.get(1)
37+
ur.delete()
38+
session.flush()
39+
40+
r = roleClass.clazz.get(1)
41+
assert r
42+
43+
44+
}
45+
46+
47+
void onSetUp() {
48+
this.gcl.parseClass('''
49+
class Role {
50+
Long id
51+
Long version
52+
String name
53+
}
54+
55+
class UserRole {
56+
Long id
57+
Long version
58+
String username
59+
Role role
60+
static belongsTo = [ role: Role ]
61+
}
62+
'''
63+
)
64+
}
65+
}

0 commit comments

Comments
 (0)