8

我有一个具有多个角色的用户。用户使用链接实体表链接到角色。我已将配置文件设置为在删除用户时级联删除用户角色链接实体。

我们目前正在使用软删除来删除实体。我们添加了一个由删除触发的软删除事件侦听器。当一个实体被删除时,它会触发将该DeleteEntity实体标记为已删除的事件。

我们还通过OnPostUpdate在实体上调用 Evict 来覆盖事件以从缓存中删除实体。

如果我创建一个没有任何角色的用户,然后将其删除,一切正常(如果级联禁用它也可以)。但是,如果我有一个分配了至少一个角色的用户并且我删除了该用户,那么在调用 Evict in 之后OnPostUpdate,我会收到一个 NHibernate 异常“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"

级联适用于Update 和 Evict操作。我的 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 回答