@@ -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+ /**
11751192w * Binds a simple value to the Hibernate metamodel. A simple value is
11761193 * any type within the Hibernate type system
11771194 *
0 commit comments