8

いくつかの役割を持つユーザーがいます。ユーザーは、リンクエンティティテーブルを使用してロールにリンクされます。ユーザーが削除されたときにユーザーロールリンクエンティティをカスケード削除するように構成ファイルを設定しました。

現在、ソフト削除を使用してエンティティを削除しています。削除によってトリガーされるソフト削除イベントリスナーを追加しました。DeleteEntityエンティティが削除されると、エンティティを削除済みとしてマークするイベントがトリガーされます。

OnPostUpdateエンティティでEvictを呼び出すことにより、キャッシュからエンティティを削除するイベントをオーバーライドすることもできます。

ロールのないユーザーを作成してから削除すると、すべてが正常に機能します(カスケードが無効になっている場合も機能します)。ただし、少なくとも1つのロールが割り当てられているユーザーがいて、そのユーザーを削除すると、でEvictを呼び出した後、OnPostUpdateNHibernate例外「NHibernate.AssertionFailure:セッションへのスレッドセーフでないアクセスの可能性」が発生します。

OnPostUpdateで、子セッションを使用してエンティティを削除しようとしましたが、例外はスローされませんが、エンティティは削除されません。

public void UserDelete(.....)
{
    var user = repository.Fetch<User>(id);

    repository.Remove(user);
    repository.Connection.Commit();
}


// soft delete event listener
protected override void DeleteEntity(NHibernate.Event.IEventSource session, object entity, ..)
{               
    var repositoryEntity = entity as deletableentity;
    if (repositoryEntity != null)
    {
        if (!repositoryEntity.IsDeleted)
        {
            // this marks the entity as deleted
            repositoryEntity.isDeleted = true;

            // cascade delete
            this.CascadeBeforeDelete(session, persister, repositoryEntity, entityEntry, transientEntities);
            this.CascadeAfterDelete(session, persister, repositoryEntity, transientEntities);          
        }
    }
}

public void OnPostUpdate(PostUpdateEvent @event)
{
    if (@event == null) throw new ArgumentNullException("event");

    var entity = @event.Entity as deletableentity;

    // Evict any entities that have been set as deleted from first level cache.
    if (entity != null && entity.IsDeleted)
    {
        @event.Session.Evict(entity);
    }
}

それを解決する方法について何かアイデアはありますか?

4

3 に答える 3

14

https://forum.hibernate.org/viewtopic.php?p=2424890によると、これを回避する別の方法は、基本的に

          session.save(s);
          session.flush(); // allow evict to work
          session.evict(s);

問題の根本は、「エンティティをキャッシュから削除した場合、commit()はそこに見つからない」ことです(つまり、スレッドセーフの問題ではなく、キャッシュが変更された問題です)。

于 2013-01-15T00:55:35.190 に答える
3

問題が何であるかを見つけました。ソフト削除を使用すると、実際に更新がトリガーされ、isDeletedフラグが設定されます。マッピングのこの行のため

  cascade="all"

カスケードは、更新アクションと削除アクションの両方に適用されます。私のpostUpdateは2回起動されますが、同時にEvictは子エンティティを削除しようとします。

解決策は、マッピングファイルのカスケードからEvictを削除することでした。今では:

  cascade="persist, merge, save-update, delete, lock, refresh"
于 2012-10-05T09:47:39.433 に答える
1

同じ問題が発生しましたが、Fluentマッピングを使用しているためEvict、カスケードから除外するオプションはありません。私の解決策は、呼び出しを避けEvict、セッションキャッシュからエンティティを削除することでした。

public void OnPostUpdate(PostUpdateEvent @event)
{
    var entity = @event.Entity as ISoftDeletable;
    if (entity != null && entity.Deleted)
    {
        IEventSource session = @event.Session;
        IEntityPersister persister = @event.Persister;

        var key = new EntityKey(@event.Id, persister, session.EntityMode);
        session.PersistenceContext.RemoveEntity(key);
        session.PersistenceContext.RemoveProxy(key);
    }
}
于 2012-12-17T23:32:55.997 に答える