什么时候应该使用grails域类中的N:1关系?

时间:2010-06-29 14:59:44

标签: hibernate grails orm grails-domain-class

在grails中,我可以实现这样的N:1关系:

class Parent { hasMany = [children:Child] }
class Child  { belongsTo = [parent:Parent] }

现在(如果总是正确使用addTo和removeFrom)我可以通过parent.children获得父母的孩子。

但我也可以在没有hasMany的情况下做到:

class Parent { }
class Child  { belongsTo = [parent:Parent] }

然后我必须使用Child.findAllByParent(parent)来获取所有孩子。

我的问题:如果能以第二种方式查询父母的孩子,我有什么理由可以使用hasMany吗?

我猜它有时更容易(也许更快,如果与父母一起急切地获取?)只是引用parent.children,但另一方面,当有几个孩子时,这个List会变得相当长。而我不喜欢的事情还有很多,你总是需要注意addTo或removeFrom,或者在添加一个带有Parent的新Child后清除会话,以便grails自动执行此操作...

如果有很少的孩子,你应该简单地使用hasMany,如果有很多孩子而没有使用它(出于性能原因),或者它背后有更多吗?

2 个答案:

答案 0 :(得分:8)

使用hasMany与belongsTo更相关的是在发生更新/删除时要指定的级联行为。在第二个示例中,级联在子端设置为ALL,在父端设置为NONE。如果删除子项,则父项不会发生任何事情。如果删除父项,则会自动删除所有子项。

在您的第一个示例中,级联在父端设置为ALL,在子端设置为SAVE-UPDATE。所以现在你可以这样做:

parent.addToChildren(child1)
parent.addToChildren(child2)
parent.addToChildren(child3)
parent.save(flush:true)

当你保存父母时,所有孩子都会被更新。

触摸你没有问过的东西,你可能也会有类似的东西:

class Parent { hasMany = [children:Child] }
class Child  { Parent parent }

如果以这种方式定义从Child到Parent的关系,则需要在删除父*时手动管理引用父对象的Child对象。 (*这纠正了之前证明不准确的陈述)

因此,hasMany / belongsTo有两个主要考虑因素:

  1. 您希望在更新/删除时执行什么类型的级联策略
  2. 如果您希望为父母检索一组子项,那么您最有可能访问数据,拥有parent.getChildren()方法非常方便。
  3. <强>更新

    我还想澄清一下,当你使用hasMany时,GORM不会急于获取;默认情况下,GORM使用延迟提取策略,因此在尝试访问parent.children之前不会获取子进程

    如果您希望默认情况下急切地获取关联,则可以指定适当的映射:

    class Parent { 
      hasMany = [children:Child]
      static mapping = {
        children lazy:false
      }
    }
    

    最后,你提到你不喜欢你不得不担心hasMany方面的addTo / removeFrom。如果使用flush:true保存,则不必执行此操作。

    def parent = Parent.get(id)
    def child = new Child(name:'child1', parent:parent)
    if(child.save(flush:true)) {
      // both sides of the relationship should be good now
    } 
    

    编辑:修正了子/父级联默认值的逆序并纠正了关于gorm如何处理没有belongsTo的关系的误解

答案 1 :(得分:0)

很好的问题,目前接受的答案是好的。还有一个重要的性能考虑因素,即添加和保存新孩子时会发生的情况。在第一个示例中,默认情况下,Grails必须在将新的子项插入Set之前从数据库中加载整个子项列表,以保证唯一性。在第二种情况下,它没有,这导致更好的性能。您可以在第一个示例中通过根据http://grails.org/doc/latest/guide/single.html#sets,ListsAndMaps将子项定义为“集合”来解决此问题