Grails 如何搜索对另一个域类实例的引用为空或与给定值匹配的域类实例?

Grails 如何搜索对另一个域类实例的引用为空或与给定值匹配的域类实例?,grails,gorm,Grails,Gorm,为了解释一个Grails示例,我试图获取一个没有作者的书籍列表。作者可以是匿名的,也可以只是未设置(null)。到目前为止,我可以按值搜索,也可以按null搜索,但我似乎无法同时执行这两项操作。以书和作者为例,假设我有以下几本书 马克·吐温的《汤姆·索耶历险记》 《O:总统小说》匿名作者 “贝奥武夫” 要通过“匿名”查找书籍,我可以这样做 Book.withCriteria { author { eq('name', 'Anonymous') } } Book.withCr

为了解释一个Grails示例,我试图获取一个没有作者的书籍列表。作者可以是匿名的,也可以只是未设置(null)。到目前为止,我可以按值搜索,也可以按null搜索,但我似乎无法同时执行这两项操作。以书和作者为例,假设我有以下几本书

  • 马克·吐温的《汤姆·索耶历险记》
  • 《O:总统小说》匿名作者
  • “贝奥武夫”
要通过“匿名”查找书籍,我可以这样做

Book.withCriteria {
  author {
    eq('name', 'Anonymous')
  }
}
Book.withCriteria {
  isNull('author')
}
返回“O:总统小说”

一切都很好。现在要找到没有作者的书,我可以这样做

Book.withCriteria {
  author {
    eq('name', 'Anonymous')
  }
}
Book.withCriteria {
  isNull('author')
}
返回“Beowulf”

那也很好。所以要把这两本书都拿来,我应该把它们放在一起

Book.withCriteria {
  or {
    isNull('author')
    author {
      eq('name', 'Anonymous')
    }
  }
}
返回“O:总统小说”

为什么这两本书都不还?我将Grails2.3.7与Hibernate 3.6.10.16结合使用

更新: 我发现了一个有效的查询,尽管我不知道它有什么不同

Book.withCriteria {
  or {
    isNull('author')
//  author {
//    eq('name', 'Anonymous')
//  }
    sqlRestriction('{alias}.author_id = (select author_id from authors where name = ?)', 'Anonymous')
  }
}

你有试着做什么吗?看来你只得到了第一个结果

def c = Book.createCriteria() 
def list = c.list{
    or {
        isNull('author')
        author {
            eq('name', 'Anonymous')
        }
    }
}

您的第三个查询结果是以下SQL语句(Grails 2.4.4,PostgreSQL):

因此Grails发出了一个内部连接,它消除了所有没有作者的书籍。我不知道Grails是否可能在这里发出一个外部连接


对于使用
sqlRestriction
的第四次查询,这将导致一个子选择:

select ...
  from book b 
  where (b.author_id is null or b.author_id = 
    (select author_id from author where name = $1))

这是可行的,但一般来说,子选择可能比内部/外部联接慢。

如另一个答案中所述,类似这样的关联查询会在SQL级别映射到内部联接。您可以改为使用
createAlias
执行左外部联接:

def list = c.list {
  createAlias('author', 'a', CriteriaSpecification.LEFT_JOIN)
  or {
    isNull('author')
    eq('a.name', 'Anonymous')
  }
}

是的,这就是问题所在。我不明白为什么它只返回第一个结果,而我希望它同时获取这两个结果。谢谢你的解释,Hibernate可能是一个神秘的野兽。我发现(在Oracle中),无论使用联接还是子查询,查询优化器都会构建相同的查询,我个人认为子查询更易于阅读。