В этом примере я заставлю свой класс User обрабатывать его метод delete() как мягкое удаление, установив атрибут lowDate с фактической датой, когда delete() вызывается для экземпляра User. Идея состоит в том, что пользователи с lowDate != null будут игнорироваться запросами GORM.
1) Установите плагин Hibernate Filter. Найдите зависимость на странице плагина: 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
}
Но когда save() вызывается внутри beforeDelete, вызывается метод сохранения beforeDelete и так далее, создавая 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'
}
}
Надеюсь, что это поможет!
person
Tomas Romero
schedule
17.09.2012