首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >无法使嵌入类ref上的级联保存或删除生效

无法使嵌入类ref上的级联保存或删除生效
EN

Stack Overflow用户
提问于 2017-02-06 00:18:47
回答 4查看 497关注 0票数 0

我已经创建了两个简单的Grails V3域类,其中location嵌入了父场所中的属性类型,如下所示

代码语言:javascript
复制
import java.time.LocalDate

class Venue {

    String name
    LocalDate dateCreated
    LocalDate lastVisited
    LocalDate lastUpdated
    GeoAddress location

    static hasOne = [location:GeoAddress]

    static embedded =['location']

    static constraints = {
        lastVisited nullable:true
        location    nullable:true
    }
    static mapping = {
        location cascade: "all-delete-orphan", lazy:false  //eager fetch strategy

    }
}


class   GeoAddress {

    String addressLine1
    String addressLine2
    String addressLine3
    String town
    String county
    String country = "UK"
    String postcode

    static belongsTo = Venue

    static constraints = {
        addressLine1 nullable:true
        addressLine2 nullable:true
        addressLine3 nullable:true
        town         nullable:true
        county       nullable:true
        country      nullable:true
        postcode     nullable:true
    }
}

然而,当我写一个集成测试时-我发现为位置创建的级联不起作用(我必须在传递到地点之前保存它不再是瞬态的位置。

此外,当我在启用了flush:true的情况下对地点运行delete操作时,查询地址仍然会得到返回的嵌入式地址-我认为使用flush:true会看到GeoAddress级联删除,但我的测试失败了,因为在使用GeoAddress.get(loc.id)时没有像我预期的那样得到null

代码语言:javascript
复制
@Integration
@Rollback
class VenueIntegrationSpec extends Specification {
  void "test venue with an address" () {
        when: "create a venue and an address using transitive save on embedded "
            GeoAddress address = new GeoAddress (addressLine1: "myhouse", town: "Ipswich", county: "suffolk", postcode : "IP4 2TH")
            address.save()  //have to save first - else Venue save fails

            Venue v = new Venue (name: "bistro", location: address)
            def result = v.save()

        then: "retrieve venue and check its location loaded eagerly "
            Venue lookupVenue = Venue.get(v.id)
            GeoAddress loc = lookupVenue.location
            loc.postcode == "IP4 2TH"
            loc.town == "Ipswich"

        when: " we delete the venue, it deletes the embedded location (Address)"
            v.delete (flush:true)
            GeoAddress lookupLoc = GeoAddress.get (loc.id)

        then: "address should disppear"
            lookupLoc == null
    }

我以为我已经正确地设置了它,但是很明显我没有,为什么我的Venue.save()和delete()的级联操作不能级联到我的嵌入式位置(GeoAddress)条目?

EN

回答 4

Stack Overflow用户

发布于 2017-02-06 18:12:53

如果我没理解错的话

cascade: "all-delete-orphan"

仅当您有hasMany=[something:Something]时才需要

在您的例子中,如果我创建这样一个关系,hasOneGeoAddress location可能是更好的设置。我知道两者之间有一点不同。

无论如何,你的测试都是理论上的。我认为你首先需要捕获错误,以找出为什么它没有级联预期的行为。所以要么

代码语言:javascript
复制
if (!v.delete(flush:true) { 
  println "---  ${v.errors}" 
}

或者把它包起来

try catch块

。我在hasMany关系中遇到了类似的问题,这是由于底层hasMany表关系本身的设置而导致与其他表共享记录。诀窍就是从对象本身中删除条目:

lookupVenue .removeFromLocation(loc)

正如我所说的,这是一个hasMany关系

票数 0
EN

Stack Overflow用户

发布于 2017-02-08 06:48:47

非常奇怪,而且太累了,现在想不出来了。我尝试了外部实体和嵌入式-请参阅下面的调整模型。

我写了太多新的测试,两个都能用--但是原来的测试不能。我正在做一些奇怪的事情--只是没有发现它。这两个新的测试做了相同的流程-只是变量不同-两者都有效。所以问题出在第一个测试上。

修改后的测试

代码语言:javascript
复制
@Integration
@Rollback
class VenueIntegrationSpec extends Specification {

    def setup() {
    }

    def cleanup() {
    }

    //original test -  this fails, have to explicitly delete loc to make it work 
    void "test venue with an address" () {
        when: "create a venue and an address using transitive save on embedded "
            GeoAddress address = new GeoAddress (addressLine1: "myhouse", town: "Ipswich", county: "suffolk", postcode : "IP4 2TH")
            address.save()
            Venue v = new Venue (name: "bistro", location: address)
            def result = v.save(flush:true)

        then: "retrieve venue and check its location loaded eagerly "
            Venue lookupVenue = Venue.get(v.id)
            GeoAddress loc = lookupVenue.location
            loc.postcode == "IP4 2TH"
            loc.town == "Ipswich"

        when: " we delete the venue, it deletes the embedded location (Address)"
            //loc.delete(flush:true)
            v.delete (flush:true)
            if (v.hasErrors())
                println "errors: $v.errors"

            GeoAddress lookupLoc = GeoAddress.get (loc.id)

        then: "address should disppear"
            Venue.get (v.id) == null
            lookupLoc == null
    }

    //new test - external entity - works 
    void "test with tempLocation" () {
        when: ""
            TempLocation temp = new TempLocation(name:"will")
            Venue v = new Venue (name: "bistro", temp: temp)
            assert v.save(flush:true)

            Venue lookupVenue = Venue.get(v.id)

            TempLocation t = lookupVenue.temp
            assert t.name == "will"

            //try delete
            v.delete (flush:true)


        then : " retrieve temp"
            TempLocation.findAll().size() == 0
    }

    //new test - reuse embedded  entity - works 
    void "test with GeoLocation" () {
        when: ""
        GeoAddress a = new GeoAddress(town:"ipswich")
        Venue v = new Venue (name: "bistro", location: a)
        assert v.save(flush:true)

        Venue lookupVenue = Venue.get(v.id)

        GeoAddress ta = lookupVenue.location
        assert ta.town == "ipswich"

        //try delete
        v.delete (flush:true)


        then : " retrieve temp"
        GeoAddress.findAll().size() == 0
    }
}

修改了测试中的主题-使用emebbed的Venue.groovy

代码语言:javascript
复制
class Venue {

    String name
    LocalDate dateCreated
    LocalDate lastVisited
    LocalDate lastUpdated
    GeoAddress location
    Collection posts

    //test behaviour
    TempLocation temp

    static hasOne = [location:GeoAddress, temp:TempLocation]
    static hasMany = [posts:Post]
    static embedded =['location']

    static constraints = {
        lastVisited nullable:true
        location    nullable:true, unique:true
        posts       nullable:true
        temp        nullable:true //remove later
    }
    static mapping = {
        location cascade: "all-delete-orphan", lazy:false, unique:true  //eager fetch strategy
        posts    sorted: "desc"
        temp     cascade: "all-delete-orphan", lazy:false, unique:true //remove later
    }
}


class   GeoAddress {

    String addressLine1
    String addressLine2
    String addressLine3
    String town
    String county
    String country = "UK"
    String postcode

    static belongsTo = Venue

    static constraints = {
        addressLine1 nullable:true
        addressLine2 nullable:true
        addressLine3 nullable:true
        town         nullable:true
        county       nullable:true
        country      nullable:true
        postcode     nullable:true
    }
}

用于黑客攻击的地址/位置的新外部版本。带有相同beongsTo/约束逻辑的geoAddress的简化版本

代码语言:javascript
复制
class TempLocation {

    String name

    //setup birdiectional one to one, cascade owned on venue
    static belongsTo = [venue:Venue]

    static constraints = {
        name nullable:true
    }
}

我将尝试在火车上重新阅读-不确定为什么第一次测试失败,但下两次工作正常……上床睡觉--太累了

票数 0
EN

Stack Overflow用户

发布于 2017-02-10 07:26:38

我认为这是一个错误的配置。Embedded意味着实体被嵌入到domainclass中。通常这是一个普通的POJO,放在domainclass文件夹之外(在src/groovy文件夹中)。嵌入实体的所有字段都被包括在嵌入实体的表中。hasone设置两个domainclass实体之间的关系。因此,要么使用embedded,要么使用hasOne,但不要同时使用这两种方法。

此外,存在级联保存深度嵌套实体的问题,这在3.2.5中得到了解决。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42054344

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档