3

我正在寻找一种方法来避免从数据库中删除我的用户,而是将它们标记为已删除并且不要将它们带回查询中。

我找到了这个插件http://grails.org/plugin/hibernate-filter,它是完成任务的好工具。

但是当我尝试实施我的解决方案时,我遇到了同样的问题,这些问题的解决方案在互联网上没有(或者我无法找到)。

所以,接下来,我描述一下我解决软删除问题的方法。

4

2 回答 2

5

在此示例中,我将让我的类 User 将其 delete() 方法作为软删除来处理,将属性 lowDate 设置为在 User 实例上调用 delete() 时的实际日期。这个想法是 GORM 查询将忽略具有 lowDate != null 的用户。

1)安装休眠过滤器插件。在插件页面查找依赖项:http: //grails.org/plugin/hibernate-filter。看看文档。

2)将以下内容添加到数据源:

import org.grails.plugin.hibernate.filter.HibernateFilterDomainConfiguration

environments {
    development {
    dataSource {
        ...    
        configClass = HibernateFilterDomainConfiguration
    }
    }
    test {
    dataSource {
        ...
        configClass = HibernateFilterDomainConfiguration
    }
    }
    production {
    dataSource {
        ...
        configClass = HibernateFilterDomainConfiguration
    }
    }   
}

3)在课堂上定义你的过滤器:

class User {
    ...
    String email
    Date lowDate
    static hibernateFilters = {
        deletedFilter(condition:'low_date is null', default:true)
    }
    static constraints = {
        ...
        lowDate nullable: true
    }
    ...
}

注意:看看我定义条件的方式。它接收到的值是 sql,因此请注意将属性命名为数据库上的属性,而不是类上的名称。

这将使 GORM 方法避免让 lowDate 不同于 null 的用户。

4)以一种避免物理删除的方式定义beforeDelele:

class User {
    ...
    def beforeDelete() {
        SecUser.executeUpdate("update SecUser su set lowDate = :lowDate where email = :email",
                                [lowDate: new Date(), email: email])
        return false
    }
}

注意:我尝试了一种更简单的方法来实现 beforeDelete()

def beforeDelete() {
    this.lowDate = new Date()
    this.save()
    return false
}

但是当在 beforeDelete 内部调用 save() 时,调用了 beforeDelete 的 save 方法等等,生成了 StackOverflow。我不知道为什么会这样。

5) 在 BootStrap 上启用过滤器:

class BootStrap {
    ...
    def init = { servletContext ->
        User.enableHibernateFilter('deletedFilter')
        environments {
            ...
        }
    }
...
}

就是这样,它现在显示工作。为了测试功能,这里有一些示例 spock 测试:

注意:'build' 方法来自 build-test-data 插件。

class UserIntegrationSpec extends IntegrationSpec {

    def 'it should not find users marked as deleted'(){
        given: 'some users with lowDate and some withOut lowDate (=null)'
            User.build(firstName:'delUser1', lowDate: new Date())
            User.build(firstName:'user1')
            User.build(firstName:'delUser2', lowDate: new Date())
            User.build(firstName:'user2')
            def users = User.list()
        expect: 'it should only find the ones with lowDate == null'
            users.size() == 2
            users.every { it.firstName == 'user1' || it.firstName == 'user2' }      
    }

    def 'it should only delete users logically' (){
        given: 'a persisted user'
            def user = User.build(firstName: 'logiDelUser')
        when: 'user.delete() is called'
            user.delete(failOnError:true, flush:true)
            def deletedUser
            def users 
            User.withoutHibernateFilters(){
                users = User.list()
                deletedUser = User.find { firstName == 'logiDelUser' }
            }
        then: 'it should not delete the user from the DB, but set a low date instead'
            users.size() != 0
            deletedUser.lowDate != null
            deletedUser.firstName == 'logiDelUser' 
    }
}

希望这会有所帮助!

于 2012-09-17T21:31:30.213 回答
1

在 GORM 中对实体进行软删除的另一种方法是使用以下插件:

http://grails.org/plugin/logical-delete

它使用“已删除”标志将实体标记为已删除,并且不会显示在查询中。此插件使用Hibernate 过滤器插件

于 2014-02-02T03:53:32.730 回答