如何在 Grails/Groovy 中清除和替换一对多关系中的集合

How do I clear and replace a collection in a one-to-many relationship in Grails/Groovy

提问人:Simon 提问时间:1/15/2010 更新时间:4/25/2019 访问量:15318

问:

这个问题分为两部分,第一部分是关于清除列表,第二部分是关于为对象分配所有者。

我在 Grails 的模型中有两个域对象之间有一对多的关系。关系是这样的......

class Person {

    static hasMany = [authorities: Role, locations: Location]
}

class Location {

    static belongsTo = Person

}

在我的应用中,列表会完全刷新,并替换为用户操作上的新列表。更重要的是,我得到了独立于关联的对象列表。我通过检索当前登录的用户来确定将它们应用于哪个人,我调用该用户并且对我的目的很好。locationsPersonLocationPersonactivePerson

我想做的是删除所有现有位置并插入所有新位置,将它们与我进行时关联。我有一堆属性,我不想在这一点上保留这些属性,所以我想避免仅仅因为子对象的位置发生了变化而保存整个父对象。activePersonactivePersonPerson

我想遍历列表并逐个删除它们,并依靠 GORM/Hibernate 将查询批处理在一起并在最后刷新。这似乎是蛮力,尽管它可能有效。我本来以为会有一种方法或类似的东西,但我找不到。activePerson.locationsclearLocations

如果我只是用新列表替换 并调用 ,GORM 会处理现有行的删除吗?activePerson.locationsactivePerson.save(flush:true)

其次,我想把新对象放到 .同样,我可以填充并保存整个内容,但如果可以的话,我想避免这种情况。我可以单独保存它们,但是如何在进行时设置每个对象?LocationactivePersonactivePerson.locationsbelongsToLocation

所以回顾一下:

  1. 如何清除一对多集合的多端列表?
  2. 如何将独立对象与父对象关联并单独持久化它们?

谢谢

grails grails-orm

评论


答:

10赞 Burt Beckwith 1/16/2010 #1

对于 #1,您可以清除集合(默认情况下为 Set):

activePerson.locations.clear()

对于 #2,请使用 addToLocations:

activePerson.addToLocations(location)

当您保存此人员时,位置<>关系将更新。

评论

0赞 Simon 1/16/2010
@Burt,再次感谢您的回答,我欠你一杯啤酒。然而,这确实意味着我必须保留 Person 对象,这是我试图避免的。有没有明智的替代方案,或者我应该忍受更新一个没有真正改变的记录?
0赞 Dan Tanner 4/7/2012
除了 Burt 的答案之外,您可能还需要在集合对象上实现 equals 和哈希码,并在集合的映射上指定 cascade: “all-delete-orphan”。
2赞 Athlan 10/27/2013
activePerson.locations.clear()在集合上不起作用。尝试:activePerson.locations.collect().each { item.removeFromLocations(it) }
0赞 FrancescoDS 6/23/2015
如果我在两个域类之间定义了一个连接表,如下所示: 类 Person_Location { Person person;位置位置;int customField;}?我需要定义什么样的级联才能使用清除位置集合?请注意,就我而言,我在 Location 类中没有 belongsTo
11赞 Athlan 10/27/2013 #2

清算方法对我不起作用:Collection

activePerson.locations.clear()

只需尝试通过调用以下命令来迭代集合并避免:ConcurrentModificationExceptioncollect()

activePerson.locations.collect().each {
    item.removeFromLocations(it)
}

之后保存实体以执行 SQL 语句:

activePerson.save flush:true

链接到文章以了解更多信息:http://spring.io/blog/2010/07/02/gorm-gotchas-part-2/

评论

0赞 Mahakala 11/20/2013
直到我在实体上指定orphanRemoval=true之前,它对我不起作用 @OneToMany(..., orphanRemoval=true)
2赞 Salvador Valencia 6/25/2015
'item' 不应该是 'activePerson' 吗?这样我们就可以调用 removeFromLocations(it)?
8赞 jstricker 5/28/2014 #3

虽然这是一个较老的问题,但我遇到了一个非常相似的情况,我想更新一组子记录。这是我选择解决它的方式。为简单起见,我将使用与提问者相同的对象/关系名称。

  1. 在父域的块中,添加:mapping

    static mapping = {
        locations(cascade: "all-delete-orphan")
    }
    
  2. 在子域中,添加注释(以防万一有另一个潜伏,我指的是)。@EqualsAndHashCodegroovy.transform.EqualsAndHashCode

  3. 使用 Grails 方法(例如)将所有子元素添加到父域中,然后保存父域。addToaddToLocations

虽然这种方法确实需要保存父域(提问者不想这样做),但考虑到模型中的明确定义,这似乎是最合适的方法。因此,我会这样回答提问者的编号问题:belongsTo

  1. 与其手动执行此操作,不如让 Grails/Hibernate 通过指定关系上的级联行为来清除记录。all-delete-oprhan

  2. 不要尝试直接保存子记录,而是保存父对象以匹配 Grails 似乎期望的内容。

0赞 Neal 4/25/2019 #4

这是对我有用的东西:

activePerson.locations.clear()
activePerson.properties = params

...

activePerson.save()

这将清除一组位置,然后仅添加当前在参数中选择的位置。