in grails-data-mongodb/core/src/main/groovy/org/grails/datastore/mapping/mongo/engine/MongoCodecEntityPersister.groovy [262:373]
protected void processAssociations(MongoCodecSession mongoCodecSession, PersistentEntity entity, EntityAccess entityAccess, obj, ProxyFactory proxyFactory, boolean isUpdate) {
// now we must ensure that all cascades are handled and inserts / updates scheduled
for (association in entity.associations) {
def associatedEntity = association.associatedEntity
if (association instanceof ToOne) {
if (association instanceof Embedded) {
def propertyName = association.name
def value = entityAccess.getProperty(propertyName)
if (!proxyFactory.isInitialized(value)) {
continue
}
if (value != null) {
processAssociations(mongoCodecSession,
associatedEntity,
createEntityAccess(associatedEntity, value),
value,
proxyFactory,
isUpdate)
}
} else {
def propertyName = association.name
def value = entityAccess.getProperty(propertyName)
if (value != null) {
if (association.isBidirectional() && !isUpdate) {
def inverseAccess = createEntityAccess(associatedEntity, value)
def inverseSide = association.inverseSide
def inverseName = inverseSide.name
if (inverseSide instanceof ToOne) {
inverseAccess.setPropertyNoConversion(
inverseName,
obj
)
} else if (inverseSide instanceof OneToMany) {
if (isUpdate) continue
def inverseCollection = inverseAccess.getProperty(inverseName)
if (inverseCollection == null) {
inverseCollection = MappingUtils.createConcreteCollection(inverseSide.type)
inverseAccess.setPropertyNoConversion(
inverseName,
inverseCollection
)
}
if (inverseCollection instanceof Collection) {
def coll = (Collection) inverseCollection
if (!coll.contains(obj)) {
coll << obj
}
}
}
}
if (proxyFactory.isInitialized(value)) {
def dirtyCheckable = (DirtyCheckable) value
if (dirtyCheckable.hasChanged()) {
if (association.isOwningSide() || association.doesCascade(CascadeType.PERSIST)) {
mongoCodecSession.persist(value)
}
}
}
}
}
} else if ((association instanceof OneToMany) || (association instanceof ManyToMany)) {
def propertyName = association.name
def value = entityAccess.getProperty(propertyName)
boolean shouldPersist = false
if (value != null && association.doesCascade(CascadeType.PERSIST)) {
if (!isUpdate) {
shouldPersist = true
} else {
if (value instanceof DirtyCheckableCollection) {
def dirtyCheckingCollection = DirtyCheckingSupport.wrap((Collection) value, (DirtyCheckable) obj, propertyName)
if (((DirtyCheckingCollection) dirtyCheckingCollection).hasChanged()) {
shouldPersist = true
}
} else {
shouldPersist = true
}
}
if (shouldPersist) {
def associatedEntities = (Iterable) value
if (association.isBidirectional()) {
def inverseSide = association.inverseSide
def inverseName = inverseSide.name
if (inverseSide instanceof ToOne) {
for (ae in associatedEntities) {
createEntityAccess(associatedEntity, ae)
.setPropertyNoConversion(inverseName, obj)
}
}
}
def identifiers = mongoCodecSession.persist(associatedEntities)
mongoCodecSession.setAttribute(
obj,
"${association}.ids",
identifiers
)
def dirtyCheckingCollection = DirtyCheckingSupport.wrap((Collection) value, (DirtyCheckable) obj, propertyName)
entityAccess.setPropertyNoConversion(propertyName, dirtyCheckingCollection)
}
}
}
}
}