【问题标题】:Grails deleting childGrails删除孩子
【发布时间】:2014-01-22 18:38:02
【问题描述】:

我有一个类,DigitalObject,它基本上是一个 url 和上次修改日期的容器。

class DigitalObject {
  String url
  Date lastUpdated
}

我有两个类使用 DigitalObjects 来引用与其相关的不同 url

class Video {
   DigitalObject englishVersion
   DigitalObject frenchVersion
}

class Image {
   DigitalObject thumbnailImage
   DigitalObject fullSizeImage
}

我在正确映射时遇到了很多麻烦。

我希望能够删除一个 DigitalObject 并让 GORM 负责将其从其父级中删除。

如果我在尝试删除 digitalObject 时将其保留为上述方式,则会违反外键约束。

如果我在父端添加 hasOne 映射,我会收到一条错误消息,指出要指定关系的另一端,但我不清楚在哪里执行此操作,因为 DigitalObject 可以属于图像或视频。像这样。

class Video {
   static hasOne = [englishVersion: DigitalObject, frenchVersion: DigitalObject]
}

在子类中添加belongsTo会导致同样的外键约束错误。像这样。

class DigitalObject {
  String url
  Date lastUpdated

  static belongsTo = [Image, Video]
}

我将不得不放弃并手动将其从其父级中删除吗?

在此先感谢您的帮助,如果此问题得到解答,我深表歉意,尽管我确信这不可能不常见的用例。

2014 年 1 月 24 日编辑

尝试 Andrew 的建议,我的实际域类比我使用的示例复杂得多,因此我的 beforeDelete() 最终如下所示,这非常难看,可能很难维护。

def beforeDelete() {
    DigitalObject.withNewSession {
        def imageThumbnailImages = Image.findAllByThumbnailImage(this)
        if (imageThumbnailImages) {
            imageThumbnailImages.each { image ->
                image.thumbnailImage = null
                image.save(flush: true)
            }
        }
        def imagePreviewImages = Image.findAllByPreviewImage(this)
        if (imagePreviewImages) {
            imagePreviewImages.each { image ->
                image.previewImage = null
                image.save(flush: true)
            }
        }
        def imageFullImages = Image.findAllByFullImage(this)
        if (imageFullImages) {
            imageFullImages.each { image ->
                image.fullImage = null
                image.save(flush: true)
            }
        }
        def videoThumbnailImages = Video.findAllByThumbnailImage(this)
        if (videoThumbnailImages) {
            videoThumbnailImages.each { image ->
                image.thumbnailImage = null
                image.save(flush: true)
            }
        }
        def videoPreviewImages = Video.findAllByPreviewImage(this)
        if (videoPreviewImages) {
            videoPreviewImages.each { image ->
                image.previewImage = null
                image.save(flush: true)
            }
        }
        def videoFullVideosEng = Video.findAllByFullVideoEng(this)
        if (videoFullVideosEng) {
            videoFullVideosEng.each { video ->
                video.fullVideoEng = null
                video.save(flush: true)
            }
        }
        def videoFullVideosFra = Video.findAllByFullVideoFra(this)
        if (videoFullVideosFra) {
            videoFullVideosFra.each { video ->
                video.fullVideoFra = null
                video.save(flush: true)
            }
        }
        def captionsEngVideos = Video.findAllByCaptionsEng(this)
        if (captionsEngVideos) {
            captionsEngVideos.each { videos ->
                videos.captionsEng = null
                videos.save(flush: true)
            }
        }
        def captionsFraVideos = Video.findAllByCaptionsFra(this)
        if (captionsFraVideos) {
            captionsFraVideos.each { video ->
                video.captionsFra = null
                video.save(flush: true)
            }
        }
        def signLanguageEngVideos = Video.findAllBySignLanguageEng(this)
        if (signLanguageEngVideos) {
            signLanguageEngVideos.each { video ->
                video.signLanguageEng = null
                video.save(flush: true)
            }
        }
        def signLanguageFraVideos = Video.findAllBySignLanguageEng(this)
        if (signLanguageFraVideos) {
            signLanguageFraVideos.each { video ->
                video.signLanguageFra = null
                video.save(flush: true)
            }
        }
    }

【问题讨论】:

  • 这不完全是您所追求的,但一个快速(且未经测试)的想法是将beforeDelete 处理程序添加到DigitalObjcet(使用您的原始类定义)。处理程序可以找到所有父对象(使用您最喜欢的 GORM 查询风格)并清空(?)相关的 DigitalObject 引用。
  • 已根据您的建议使用 beforeDelete() 示例编辑问题。虽然它有效并且是我目前唯一有效的解决方案,但我希望有更好的方法来做到这一点。
  • 是的,当然是一种繁琐的方法。我想知道您是否会发现调整整体模型更容易?也许像将type(可能还有language)限定符添加到DigitalObject,将对象指定为预览、缩略图等简单的事情。然后,ImageVideo 可以保存一个简单的集合.
  • 由于该模型不属于我,而且我的项目不是唯一使用它的项目,因此我犹豫是否要进行如此剧烈的更改。我在下面提供了我的解决方案,可能不是最好的方法,但在这种情况下我可以开始工作的最好方法。

标签: grails grails-orm grails-2.0 grails-domain-class


【解决方案1】:

我有一个类似的域类,可以由不同的父母拥有,我的级联删除按预期工作。所以用你的课,你有没有试过这个:

class DigitalObject {
    String url
    Date lastUpdated

    Image image
    Video video

    static belongsTo = [
         image: Image, 
         video: Video
    ]

编辑:从下面的约束中删除方括号!

    static constraints = {
        image( nullable : true )
        video( nullable : true )
    }

}

不确定是否需要您的 hasOne on Image/Video。但无论有无尝试。

【讨论】:

  • 感谢您为我指明这个方向。我将不得不多玩一点,看看我能不能让它工作。我目前遇到一个错误,指出 image_id 不能为空,即使我已根据您的示例将其设置为可为空。当我有更多时间调查时会更新。
  • 尝试从约束中删除方括号(我将编辑我的答案以反映这一点)。
【解决方案2】:

这很丑陋,可能不是最好的方法,但是因为我无法让建议的其他方法可靠地工作,并且由于我想对域类进行尽可能少的更改,因为我的project 并不是唯一使用它们的项目。

我在我的 DigitalObjectController 中添加了以下方法。

def deleteFromMediaAsset(Long id, String parentClass, String parentProperty, String parentId) {
    def digitalObjectInstance = DigitalObject.get(id)
    if (!digitalObjectInstance) {
        flash.message = message(code: 'default.not.found.message', args: [
            message(code: 'digitalObject.label', default: 'DigitalObject'),
            id
        ])
        redirect(controller: parentClass, action: 'edit', id: parentId)
        return
    }

    try {
        def classOfParent = grailsApplication.domainClasses.find {
            it.clazz.simpleName == parentClass.capitalize()
        }.clazz

        def parentInstance = classOfParent.get(parentId)
        parentInstance.setProperty(parentProperty, null)
        digitalObjectInstance.delete(flush: true)
        flash.message = message(code: 'default.deleted.message', args: [
            message(code: 'digitalObject.label', default: 'DigitalObject'),
            id
        ])
        redirect(controller: parentClass, action: 'edit', id: parentId)
    }
    catch (DataIntegrityViolationException e) {
        flash.message = message(code: 'default.not.deleted.message', args: [
            message(code: 'digitalObject.label', default: 'DigitalObject'),
            id
        ])
        redirect(controller: parentClass, action: 'edit', id: parentId)
    }
}

基本上,我传递父 Image 或 Video 类和 ID,以及 DigitalObject 引用的属性和我希望删除的 DigialObject 的 ID。我在父对象上将属性设置为 null,然后删除 DigitalObject。

很丑,但它现在有效,祝我好运。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-18
    • 2011-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多