ユーザーを DB から削除しないようにする方法を探していましたが、代わりに削除済みとしてマークし、クエリに戻さないようにしました。
このプラグインhttp://grails.org/plugin/hibernate-filterを見つけました。これは、タスクに最適なツールでした。
しかし、解決策を実装しようとしたとき、解決策がインターネット上にない (または見つけることができなかった) 同じ問題に合格しました。
そこで、次に、ソフト削除の問題を解決する方法について説明します。
ユーザーを DB から削除しないようにする方法を探していましたが、代わりに削除済みとしてマークし、クエリに戻さないようにしました。
このプラグインhttp://grails.org/plugin/hibernate-filterを見つけました。これは、タスクに最適なツールでした。
しかし、解決策を実装しようとしたとき、解決策がインターネット上にない (または見つけることができなかった) 同じ問題に合格しました。
そこで、次に、ソフト削除の問題を解決する方法について説明します。
この例では、User インスタンスで delete() が呼び出されたときに属性 lowDate を実際の日付に設定して、その delete() メソッドをソフト削除として処理するようにクラス User を作成します。lowDate != null を持つユーザーは GORM クエリによって無視されるという考え方です。
1) Hibernate Filter Plugin をインストールします。プラグインのページで依存関係を探します: 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 内で呼び出されると、save メソッドが beforeDelete を呼び出すなどして、StackOverflow が生成されます。なぜこれが起こるのかわかりません。
5) BootStrap でフィルターを有効にします。
class BootStrap {
...
def init = { servletContext ->
User.enableHibernateFilter('deletedFilter')
environments {
...
}
}
...
}
以上で、動作するようになりました。機能をテストするために、いくつかのサンプル スポック テストを次に示します。
注: 「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'
}
}
それが役立つことを願っています!
GORM でエンティティのソフト削除を行う別の方法は、次のプラグインを使用することです。
http://grails.org/plugin/logical-delete
「削除済み」フラグを使用してエンティティを削除済みとしてマークし、クエリには表示されません。このプラグインはHibernate フィルター プラグインを使用します