【问题标题】:How do you bulk delete records in Grails/GORM?如何批量删除 Grails/GORM 中的记录?
【发布时间】:2011-01-15 00:19:35
【问题描述】:

我有一个表,其中包含需要根据一组标准定期清除的记录。

我原以为我可以使用标准构建器来删除记录,但由于标准上没有 delete 方法而失败了...

def c = Agency.createCriteria()
c.delete
{
    eq("agency", "XXX")  
}

所以我想也许我先查询该集合然后删除它...

def c = Agency.createCriteria()
def deletions = c
{
    eq("agency", "XXX")  
}
deletions.delete

这也因同样的原因而失败,不同的对象。

那么正确的方法是什么?我必须遍历整个结果集,在每个项目上调用delete(),这似乎有点过分(不正常)。

我知道我可以形成一个查询以直接在 HQL 或 SQL 中执行,但这也感觉不对。标准构建器是否仅用于检索?

谢谢

【问题讨论】:

    标签: hibernate grails grails-orm


    【解决方案1】:

    在 Grails 2.0 中,您可以像这样使用分离查询:

    Agency.where { }.deleteAll()
    

    请注意,您不会执行侦听器和其他操作,但它会执行到数据库,并且它与模拟的域内容兼容,如下所示:

    void testWhatever() {
        mockDomain(Agency, [])
        saveABunchOfAgencies() // saves 10 of 'em
        assert Agency.count() == 10
    
        Agency.where { }.deleteAll()
    
        assert Agency.count() == 0   // Joy!
    }
    

    话虽如此,GORM 单元测试模拟有很多陷阱,但总的来说非常简洁。

    【讨论】:

    • 这似乎是最好的。我正在使用它。
    • Jesper,我完全同意“GORM 单元测试模拟有很多陷阱”。它们记录在什么地方?
    • 正如我所尝试的那样,此解决方案运行良好且可靠。
    【解决方案2】:

    来自User Guide about deleting objects

    请注意,Grails 不提供 删除数据的 deleteAll 方法是 气馁,通常可以避免 通过布尔标志/逻辑。

    如果确实需要批量删除 可以使用 executeUpdate 的数据 批量 DML 语句的方法:

    Customer.executeUpdate("delete Customer c where c.name = :oldName", [oldName:"Fred"])
    

    【讨论】:

    • 是的,我就是这样做的,但是我不能使用标准有点疯狂。 DELETE 是查询语义的有效部分,并受到所有 RDBMS 的支持,并且是一件完全有效的事情,尽管 Hibernate/GORM 作者可能会这么想。在我的情况下,将过期记录留在表中是非常糟糕的做法。
    • 作为 JesperSM 引用:现在 Grails 2+ 在 DetachedCriteria 上有一个 deleteAll()。
    • 这行得通。但是太糟糕了,它不会级联删除子表中的行。然后它给出一个Integrity constraint violation。在2.3.7 中对此进行了测试。
    • 我们遇到了与@Guus 相同的问题。在内部,JDBCPreparedStatement 用于执行更新,这显然不符合 Hibernate 或其实体关系的级联规则。
    【解决方案3】:

    如果你想避免 HQL,我建议使用 GORM list()、delete() 和 Groovy 的扩展运算符:

    def agentList = Agency.createCriteria().list { eq("机构", "XXX") } 代理列表*.delete()

    【讨论】:

    • 哇!那个流浪*做什么?我尝试了这个但没有 * 并得到一个编译器错误......
    • *.是 Groovy 扩展运算符 groovy.codehaus.org/Operators#Operators-SpreadOperator(.) 在 Sbglasius 的示例中,它对返回的集合中的项目调用 delete() 方法。
    • 我在使用此方法时遇到了 java.util.ConcurrentModificationException...所以我停止使用扩展运算符并使用迭代器创建了一个 while 循环,按照stackoverflow.com/questions/1816196/…中的解决方案@
    • 这样做的问题是您最终会获取整个集合,并线性删除它们中的每一个。这意味着整个表都进入了堆,这对于玩具模型来说不是问题,但对于真正的大容量数据来说可能是个问题。
    • 也解决了我的问题:当我们使用 uses.FindAllBy* 获取列表时,要删除所有用户,您需要 user *.delete() 谢谢@sbglasius
    猜你喜欢
    • 2020-08-17
    • 1970-01-01
    • 1970-01-01
    • 2013-12-06
    • 1970-01-01
    • 2015-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多