Grails <where> returns 包含所有条目的 DetachedCriteria

Grails <where> returns DetachedCriteria with all entries

Domain.where {
    1 == 0
}.count()

这 return 编辑了域 class 的所有元素。更一般的情况:

Domain.where {
    false
}.count()

将return所有元素;如果我使用其中一个字段并设置一个错误条件,则结果符合预期。

我的问题是为什么会发生这种情况(第一种情况)?如果这是一个太幼稚的问题,请建议阅读material。谢谢!

我使用的grails版本是2.3.6(新版本可能不一样?)

我不确定你想要达到什么目的,但这里有一个解释(可能因此有点笼统:)。

你传递给where方法的实际上是一个指定SQL条件的DSL,它只是使用正常的Groovy语法来假装更自然。但是,当您执行 someProperty != 5 && someOtherProperty == 6 时,它不会被直接评估,而是会转换为以 SQL 查询作为 select * from Domain where some_property != 5 and some_other_property = 6 结束。

由于您没有在您的标准 (1 == 0) 中传递对 属性 的任何引用,它会被分离的标准 DSL 评估器忽略,从而返回 select * from domain 的结果.例如,您可以尝试执行 id != id 以查看如何得到一个空列表作为结果。如果您再次检查生成的查询,您会看到包含 where id<>id

您可以了解有关 where 方法的更多信息:https://grails.github.io/grails-doc/latest/guide/GORM.html#whereQueries

请记住,您传递给 where 方法的是一个 Closure,因此其中的代码不会预先执行,并且不一定在声明它的上下文中进行计算。您可以 learn more about Groovy Closures. Also about creating DSLs with Groovy,尽管这是一个高级主题。

(我简化了 SQL 查询以使其更难以理解,如果您激活 Hibernate 的查询日志或您正在使用的 MySQL/other DB,您会看到它们更大)。

为了说明 Deigote 的解释,这里有一个 非常粗略的 WHERE 查询构建器(实际上只是 WHERE 子句)的实现,使用 criteria criteria格式:

class WhereBuilder {
    def conditions = []

    def eq(column, value) {
        conditions << [
            column: column, 
            operator: '=', 
            value: value]
    }

    def ne(column, value) {
        conditions << [
            column: column, 
            operator: '!=', 
            value: value]
    }

    String toString() {
        'WHERE ' << 
            conditions.collect { 
                "${it.column} ${it.operator} '${it.value}'"
            }.join(' AND ')
    }
}

def builder = new WhereBuilder()
builder.with {
    1 == 0
    false    
    eq 'firstName', 'John'
    ne 'lastName', 'Smith'
}

assert builder.toString() == "WHERE firstName = 'John' AND lastName != 'Smith'"

如您所见,表达式 1 == 0false 无效。