Grails与索引属性的一对多关系

时间:2012-11-15 11:33:00

标签: grails groovy gorm

在我的Grails应用程序中,我有两个具有一对多关系的域类,例如

class Parent    
    static hasMany = [children: Child]
}

class Child {
    Integer index
    static belongsTo = [parent: Parent]
}

我希望index记录创建子项的相对顺序,这样父项的第一个子项将具有索引1,下一个将具有2,等等。索引没有是连续的,因为孩子可以被删除,但他们应该总是反映创造的相对顺序。

我考虑过做类似以下的事情来设置index属性

class Child {
    Integer index
    static belongsTo = [parent: Parent]

    def beforeValidate() {

        def maxIndex = Child.createCriteria().get {
            projections {
                max('index')
            }
            eq('parent', parent)
        }        

        this.index = maxIndex + 1 ?: 1
    }
}

但当然这不起作用,因为它会为两个瞬态Child实例分配相同的索引。维护此index属性的最简单方法是什么?

FWIW,我并不太关心阻止任何其他代码设置index但是如果有某种方法可以做到这一点,那就是奖金。

4 个答案:

答案 0 :(得分:1)

我以为你可以做到:

class Parent    
  List children
  static hasMany = [children: Child]
}

然后将子项保存在List中,因此隐式具有索引和顺序。我猜你真的希望元素有一个索引字段而不是这个隐含的顺序吗?

修改

这可行(似乎)但每次查询索引时都会命中数据库

class Child {
  def grailsApplication

  static belongsTo = [ parent: Parent ]

  Integer getIndex() {
    grailsApplication.mainContext.sessionFactory.currentSession.with { sess ->
      createSQLQuery( 'SELECT c.children_idx FROM child c where c.id = :id' )
        .setBigInteger( "id", this.id )
        .list()
        .head() + 1
    }
  }
  String toString() {
    "Child @$index"
  }
}

让我感到有些不安; - )

编辑2

当然,另一种选择是:

  Integer getIndex() {
    parent.children.indexOf( this ) + 1
  }

答案 1 :(得分:0)

使用带有自动增量的id ...一旦创建了一个子项,它将永远不会使用另一个id等于但更大......如果你只需要知道创建的顺序,你可以使用id或添加一个:

class Child{
    Date dateCreated;
    static belongsTo = [parent: Parent]
}

它会自动设置创建日期,您可以使用它来了解订单:)

答案 2 :(得分:0)

您应该能够使用为Grails中的任何域类自动创建的id属性。默认情况下,对于保存到DB的每个子项,此值将递增。所以......

parent.children.sort {a,b -> a.id <=> b.id}

将按照保存到数据库的顺序返回父项的子项。

如果您绝对需要名为“index”的属性,我相信您可以执行以下操作:

Integer index

static mapping = {
    id name: 'index'
}

但是,请注意,索引可能是许多数据库中的保留字,因此您将无法拥有名为index的列,这将失败。考虑一下您房产的不同名称。

答案 3 :(得分:0)

您可以使用indexColumn grails映射功能

https://docs.grails.org/latest/ref/Database%20Mapping/indexColumn.html

Class Parent(){

  static hasMany = [children: Child]
  List children // Generates column `book_idx` in table for Book.

  static mapping = {
      children indexColumn: [name: "index", type: Integer]
  }
}