重构关闭条件以修复列表中表达式的最大数量为 1000
Refactor closure criteria to fix maximum number of expressions in a list is 1000
我在我必须维护的应用程序中发现了以下代码
def addCriteriaClosure = { criteriaList ->
criteriaList.inList('id', paketInstance.dateien.id)
}
def criteria = Datei.createCriteria()
def result = criteria.list() {
addCriteriaClosure.call(criteria)
}
遗憾的是,此调用导致以下错误:
java.sql.SQLSyntaxErrorException: ORA-01795: maximum number of expressions in a list is 1000
事实是 paketInstance.dateien
包含超过 1000 行/项目。
为避免此错误,我尝试了以下方法:
def addCriteriaClosure = { criteriaList ->
paketInstance.dateien.asList().collate(999).each {
criteriaList.inList('id', paketInstance.dateien.asList().collate(999).id)
}
}
但这会导致此错误:
java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.lang.Long
我知道解决方案是使用collate(999)
操作,但我不知道如何将它与初始方法结合以获得预期结果。
编辑 #1
很遗憾我无法编辑这部分实现:
def criteria = [Type].createCriteria()
def result = criteria.list() {
addCriteriaClosure.call(criteria)
}
将具体类型传递给方法的位置。
我只能编辑 addCriteriaClosure
的定义
例如:
def addCriteriaClosure = { criteriaList ->
criteriaList.inList('id', paketInstance.dateien.id)
}
编辑#2
当我像下面这样设计我的条件闭包时
def l = paketInstance.dateien.id.toList().collate(999)
def addCriteriaClosure = { criteriaList ->
l.each {
a -> criteriaList.inList("id", a.toList())
}
}
Hibernate 创建一个 SQL-Statement,它将列表拆分为单独的 in
WHERE 子句。但问题是这两个子句是用一个AND
链接起来的。为了获得正确的结果,我需要两个列表的 OR
,而不是生成的 sql
中的 AND
制作SQL:
select this_.id as id51_0_, this_.version as version51_0_, this_.aktualisiert_am as aktualis3_51_0_, this_.name as name51_0_, this_.nummer as nummer51_0_, this_.pfad as pfad51_0_, this_.status as status51_0_, this_.typ as typ51_0_ from datei this_ where this_.id in (?, ?, ?, ?, ?, ?....) and this_.id in (?, ?, ?, ?, ?, ?, ?....)
所以我需要 or this_.id in
而不是 and this_.id
如果你想限制 ID 列表不超过 999 项,你应该使用
def idList = paketInstance.dateien.asList().id[0..<999]
旁白
仅仅因为 Oracle 在 in
谓词中不允许超过 1000 个项目而丢弃一些要比较的 ID 似乎不是一个好的解决方案。假设此 ID 列表是从数据库中检索的,您应该能够使用 subquery/join 来执行比较。
试试这样的方法:
def manyThingsToFind = [...list of more than 1000 things...]
def clauseLimit = 999
def results = YourDomainObject.createCriteria().listDistinct {
or {
manyThingsToFind.collate(clauseLimit)?.each { collatedList ->
'in'("fieldToMatch", collatedList)
}
}
}
如果需要,您可以将实际条件分解为闭包,正如您已经完成的那样。
找到解决方案
def collatedFileList = paketInstance.dateien.id.toList().collate(999)
def addCriteriaClosure = { criteriaList ->
criteriaList.or {
collatedFileList.each {
l -> criteriaList.inList("id", l.toList())
}
}
}
- 解决了我不得不面对的问题
- 学到了很多关于闭包/标准的东西
我在我必须维护的应用程序中发现了以下代码
def addCriteriaClosure = { criteriaList ->
criteriaList.inList('id', paketInstance.dateien.id)
}
def criteria = Datei.createCriteria()
def result = criteria.list() {
addCriteriaClosure.call(criteria)
}
遗憾的是,此调用导致以下错误:
java.sql.SQLSyntaxErrorException: ORA-01795: maximum number of expressions in a list is 1000
事实是 paketInstance.dateien
包含超过 1000 行/项目。
为避免此错误,我尝试了以下方法:
def addCriteriaClosure = { criteriaList ->
paketInstance.dateien.asList().collate(999).each {
criteriaList.inList('id', paketInstance.dateien.asList().collate(999).id)
}
}
但这会导致此错误:
java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.lang.Long
我知道解决方案是使用collate(999)
操作,但我不知道如何将它与初始方法结合以获得预期结果。
编辑 #1
很遗憾我无法编辑这部分实现:
def criteria = [Type].createCriteria()
def result = criteria.list() {
addCriteriaClosure.call(criteria)
}
将具体类型传递给方法的位置。
我只能编辑 addCriteriaClosure
的定义
例如:
def addCriteriaClosure = { criteriaList ->
criteriaList.inList('id', paketInstance.dateien.id)
}
编辑#2
当我像下面这样设计我的条件闭包时
def l = paketInstance.dateien.id.toList().collate(999)
def addCriteriaClosure = { criteriaList ->
l.each {
a -> criteriaList.inList("id", a.toList())
}
}
Hibernate 创建一个 SQL-Statement,它将列表拆分为单独的 in
WHERE 子句。但问题是这两个子句是用一个AND
链接起来的。为了获得正确的结果,我需要两个列表的 OR
,而不是生成的 sql
AND
制作SQL:
select this_.id as id51_0_, this_.version as version51_0_, this_.aktualisiert_am as aktualis3_51_0_, this_.name as name51_0_, this_.nummer as nummer51_0_, this_.pfad as pfad51_0_, this_.status as status51_0_, this_.typ as typ51_0_ from datei this_ where this_.id in (?, ?, ?, ?, ?, ?....) and this_.id in (?, ?, ?, ?, ?, ?, ?....)
所以我需要 or this_.id in
and this_.id
如果你想限制 ID 列表不超过 999 项,你应该使用
def idList = paketInstance.dateien.asList().id[0..<999]
旁白
仅仅因为 Oracle 在 in
谓词中不允许超过 1000 个项目而丢弃一些要比较的 ID 似乎不是一个好的解决方案。假设此 ID 列表是从数据库中检索的,您应该能够使用 subquery/join 来执行比较。
试试这样的方法:
def manyThingsToFind = [...list of more than 1000 things...]
def clauseLimit = 999
def results = YourDomainObject.createCriteria().listDistinct {
or {
manyThingsToFind.collate(clauseLimit)?.each { collatedList ->
'in'("fieldToMatch", collatedList)
}
}
}
如果需要,您可以将实际条件分解为闭包,正如您已经完成的那样。
找到解决方案
def collatedFileList = paketInstance.dateien.id.toList().collate(999)
def addCriteriaClosure = { criteriaList ->
criteriaList.or {
collatedFileList.each {
l -> criteriaList.inList("id", l.toList())
}
}
}
- 解决了我不得不面对的问题
- 学到了很多关于闭包/标准的东西