Grails2.4.2:嵌套事务中奇怪的级联保存行为

Grails2.4.2:嵌套事务中奇怪的级联保存行为,grails,groovy,gorm,Grails,Groovy,Gorm,我有一些奇怪的行为,在我的对象图中不正确的存储级联。可能它与嵌套事务有关,但可能不是 以下是我的3个域类: 加油站 class Station { /** Dependency injected {@link de.hutapp.tapandknow.system.SettingsService}.*/ def settingsService static hasMany = [localizedStations: LocalizedStation, stationId

我有一些奇怪的行为,在我的对象图中不正确的存储级联。可能它与嵌套事务有关,但可能不是

以下是我的3个域类:

加油站

class Station {

  /** Dependency injected {@link de.hutapp.tapandknow.system.SettingsService}.*/
  def settingsService

  static hasMany = [localizedStations: LocalizedStation, 
    stationIdentifiers: AbstractStationIdentifier]

}
class LocalizedStation {

  /** Delete-cascade from the {@link Station} parent. */
  static belongsTo = [station : Station]

  /** An image that represents the LocalizedStation. */
  MediaFile headerImage

  /** The articles inside this LocalizedStation .*/
  List<Article> articles

  static hasMany = [articles: Article]

  static mapping = {
      headerImage cascade: 'all'
      articles cascade: 'all-delete-orphan'
  }
}
LocalizedStation.groovy

class Station {

  /** Dependency injected {@link de.hutapp.tapandknow.system.SettingsService}.*/
  def settingsService

  static hasMany = [localizedStations: LocalizedStation, 
    stationIdentifiers: AbstractStationIdentifier]

}
class LocalizedStation {

  /** Delete-cascade from the {@link Station} parent. */
  static belongsTo = [station : Station]

  /** An image that represents the LocalizedStation. */
  MediaFile headerImage

  /** The articles inside this LocalizedStation .*/
  List<Article> articles

  static hasMany = [articles: Article]

  static mapping = {
      headerImage cascade: 'all'
      articles cascade: 'all-delete-orphan'
  }
}
因此,对象图是Station->LocalizedStation->MediaFile

我使用以下服务方法保存/更新对象:

StationService.groovy

@Transactional
class StationService {

def mediaFileService

/**
 * Creates a new {@link Station} and saves it.
 * @return The newly created {@link Station} instance.
 */
Station createStation(LocalizedStation localizedStationInstance, InputStream headerImage, String originalFilename) {

    localizedStationInstance = updateLocalizedStation(localizedStationInstance, headerImage, originalFilename)

    Station stationInstance = new Station()
    stationInstance.addToLocalizedStations(localizedStationInstance)
    stationInstance.save()
    stationInstance.localizedStations[0].headerImage.save() // TODO: check why this is necessary

    return stationInstance
}

LocalizedStation updateLocalizedStation(LocalizedStation localizedStationInstance, InputStream headerSource, String originalFilename) {

    if (headerSource) {
        MediaFile headerFile = mediaFileService.createMediaFile(headerSource, originalFilename, "foobar") // TODO: add description
        localizedStationInstance.headerImage = headerFile
    }

    localizedStationInstance.save()
    return localizedStationInstance

}
}
@Transactional
class MediaFileService {

MediaFile createMediaFile(InputStream input, String originalFilename, String description) {

    MediaFile mediaFileInstance = new MediaFile(
            name: originalFilename,
            description: description)

    mediaFileInstance.save(flush: true) // flush for id
    mediaFileInstance.storeMediaFile(input, originalFilename)
    mediaFileInstance.save()

    return mediaFileInstance
}
}
MediaFileService.groovy

@Transactional
class StationService {

def mediaFileService

/**
 * Creates a new {@link Station} and saves it.
 * @return The newly created {@link Station} instance.
 */
Station createStation(LocalizedStation localizedStationInstance, InputStream headerImage, String originalFilename) {

    localizedStationInstance = updateLocalizedStation(localizedStationInstance, headerImage, originalFilename)

    Station stationInstance = new Station()
    stationInstance.addToLocalizedStations(localizedStationInstance)
    stationInstance.save()
    stationInstance.localizedStations[0].headerImage.save() // TODO: check why this is necessary

    return stationInstance
}

LocalizedStation updateLocalizedStation(LocalizedStation localizedStationInstance, InputStream headerSource, String originalFilename) {

    if (headerSource) {
        MediaFile headerFile = mediaFileService.createMediaFile(headerSource, originalFilename, "foobar") // TODO: add description
        localizedStationInstance.headerImage = headerFile
    }

    localizedStationInstance.save()
    return localizedStationInstance

}
}
@Transactional
class MediaFileService {

MediaFile createMediaFile(InputStream input, String originalFilename, String description) {

    MediaFile mediaFileInstance = new MediaFile(
            name: originalFilename,
            description: description)

    mediaFileInstance.save(flush: true) // flush for id
    mediaFileInstance.storeMediaFile(input, originalFilename)
    mediaFileInstance.save()

    return mediaFileInstance
}
}
如您所见,如果我调用stationService.createStation,我必须手动保存挂在LocalizedStation上的媒体文件。这只有在调用createStation时才会发生,createStation本身调用updateLocalizedStation。 然后,除非我将媒体文件显式保存在createStation中,否则它不会被持久化

如果我直接调用updateLocalizedStation,一切都会按预期进行

有什么想法或建议吗

更新:

如果我向createMediaFile方法添加@Transactionalpropagation=Propagation.REQUIRES_NEW,就会出现此问题


据我对文档的理解,这将创建一个新事务。但这并不是我真正想要的,我想要的是一个跨所有方法的事务。

我希望您最初所拥有的应该可以工作。我会打开事务日志,看看发生了什么。