2

我正在一个新的 Grails 2.1.0 应用程序中编写调度功能。我正在从 Ruby on Rails 项目过渡,我的大部分查询策略都源自 Rails 风格。我有以下域类:

时间表.groovy

class Schedule {

    // Number of minutes between available appointment slots
    int defaultAppointmentInterval
    Time officeOpenStart
    Time officeOpenEnd
    Time lunchStart
    Time lunchEnd

    static hasMany = [inventorySlots: InventorySlot]

    static constraints = {
       // long validation rules
    }

    def boolean isAvailableAt(Date dateTime) {
        def isAvailable = true
        if (inventorySlots.isEmpty()) {
            isAvailable = false
        } else if (inventorySlotsSurroundingTime(dateTime).isEmpty()) {
            isAvailable = false
        }
        isAvailable
    }

    def inventorySlotsSurroundingTime(Date dateTime) {
        InventorySlot.surroundingTime(dateTime) {
            and {
                inventorySlot.schedule = this
            }
        }
    }
}

InventorySlot.groovy

class InventorySlot {

    Date startTime

    static belongsTo = [schedule: Schedule]

    static constraints = {
        startTime nullable: false, blank: false
    }

    static mapping = {
        tablePerHierarchy true
        schedule lazy: false
    }

    static namedQueries = {}

    def static surroundingTime(Date time) {
        [UnboundedInventorySlot.surroundingTime(time), BoundedInventorySlot.surroundingTime(time)].flatten()
    }

    def endTime() {
        return ((BoundedInventorySlot) this).endTime?: (UnboundedInventorySlot (this)).endTime()
    }
}

UnboundedInventorySlot.groovy

class UnboundedInventorySlot extends InventorySlot {

    static namedQueries = {
    //        surroundingTime { time ->
    //            le 'startTime', time
    //            ge 'startTime', time - 1
    //        }
    }

    @Override
    def static surroundingTime(Date time) {
        findAllByStartTimeLessThanEqualsAndStartTimeGreaterThanEquals(time, time - 1)
    }

    def Date endTime() {
        def endTime

        // If the office closing is defined, use that, otherwise use tonight @ 23:59:59
        endTime = schedule?.officeOpenEnd?: new DateTime(startTime + 1).withTimeAtStartOfDay().plusSeconds(-1).toDate()

        return endTime
    }
}

BoundedInventorySlot.groovy

class BoundedInventorySlot extends InventorySlot {

    Date endTime

    static constraints = {
        endTime nullable: false, blank: false, validator: {val, obj ->
            if (val.date != obj.startTime.date) { return ["invalid.differentDate", val.date] }
        }
    }

    static namedQueries = {
    //        surroundingTime { time ->
    //            le 'startTime', time
    //            ge 'endTime', time
    //        }
    }

    @Override
    def static surroundingTime(Date time) {
        findAllByStartTimeLessThanEqualsAndEndTimeGreaterThanEquals(time, time)
    }


    @Override
    def Date endTime() {
        endTime
    }
}

我想做的是实现 Schedule#isAvailableAt(Date) 方法,如下所示:

def boolean isAvailableAt(Date dateTime) {
    def isAvailable = true

    if (inventorySlots.isEmpty()) {
        isAvailable = false
    } else if (inventorySlots.surroundingTime(dateTime).isEmpty()) {
        isAvailable = false
    }

    isAvailable
}

其中inventorySlots.surroundingTime()调用本质上是InventorySlot.surroundingTime()但不是查询 InventorySlots 的宇宙,它仅对与计划实例关联的实例进行预过滤。这在 Rails 中很常见,但是在 Grails 中对“链式查询”或“集合查询”的任何搜索似乎都没有提供好的文档。谢谢你的帮助。

4

3 回答 3

4

我可以想到两种可行的方法:

更复杂的动态查找器:

InventorySlots.findAllByScheduleAndStartTimeLessThanEqualsAndEndTimeGreaterThanEquals(this, time, time -1)

您可以将命名查询链接在一起,然后使用任何自动装配的查找器来运行实际查询,因此如果您取消注释命名查询:

static namedQueries = {
        surroundingTime { time ->
            le 'startTime', time
            ge 'startTime', time - 1
        }
}

您可以简单地调用:

InventorySlots.surroundingTime(time).findAllBySchedule(this)

如果您不喜欢标准构建器语法,您可能还想查看Grails 2 中的where查询。它们比标准查询更安全,并且可以以相同的方式链接。

更新:不幸的是,我不熟悉命名查询如何与多态性一起工作的内部工作原理,我认为这就是您将其注释掉的原因。我认为最坏的情况是,您可以像这样在父级上构建一个查询:

surroundingTime { time ->
            or {
                and {
                    eq('class', BoundedInventorySlot.name)
                    le 'startTime', time
                    ge 'startTime', time
                }
                and {
                    eq('class', UnboundedInventorySlot.name)
                    le 'startTime', time
                    ge 'startTime', time - 1
                }
            }
        }

***更新:您能否利用价差运算符来简化您的任务?即保留此代码,但删除 .flatten() 并将环境时间称为命名查询或 where 查询。

def static surroundingTime(Date time) {
        [UnboundedInventorySlot.surroundingTime(time), BoundedInventorySlot.surroundingTime(time)]
    }

然后你可以打电话: Schedule.surroundingTime(time)*.findAllBySchedule(this).flatten()

调用者需要知道组合结果并不理想,但可能是一种有趣的方法。

于 2012-08-25T01:54:51.357 回答
0

作为参考:

Grails 文档中的查询链:http: //grails.org/doc/latest/guide/GORM.html#querying

请参阅“查询组合”部分。

于 2014-09-03T14:06:41.990 回答
0

添加答案,因为这是第一个搜索结果。根据文档,where 子句是“分离标准”。

例子:

def query = Person.where {
     lastName == "Simpson"
}
def bartQuery = query.where {
     firstName == "Bart"
}
Person p = bartQuery.find()

Where 查询组合

于 2015-08-03T22:07:43.977 回答