2012-10-04 70 views
7

Tengo un usuario que tiene varios roles. El usuario está vinculado a los roles usando una tabla de entidades de enlace. He configurado el archivo de configuración para que elimine en cascada las entidades de enlace de funciones de usuario cuando se elimina un usuario.¿Por qué Session.Evict en OnPostUpdate causa la excepción de "Posible acceso sin acceso a la sesión"?

Actualmente estamos utilizando la eliminación de software para eliminar entidades. Hemos agregado un detector de eventos de eliminación suave que se activa mediante una eliminación. Cuando se elimina una entidad, desencadena el evento DeleteEntity que marca la entidad como eliminada.

También tenemos que anular el evento OnPostUpdate para eliminar las entidades del caché llamando a Desalojar en la entidad.

Si creo un usuario sin ningún rol, lo elimino, todo funciona bien (también funciona si la cascada está deshabilitada). Sin embargo, si tengo un usuario con al menos un rol asignado y borro al usuario, después de la llamada a Desalojar en OnPostUpdate, aparece una excepción de NHibernate "NHibernate.AssertionFailure: Posible acceso a la sesión que no es de seguridad".

He intentado, en OnPostUpdate, usar la sesión secundaria para Desalojar a la entidad, la excepción no se produce, sin embargo, la entidad no se desaloja.

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); 
    } 
} 

¿Tienes alguna idea de cómo resolverlo?

Respuesta

3

Encontrado cuál era el problema. El uso de la eliminación suave activará la actualización para establecer el indicador isDeleted. Debido a esta línea en un mapeo

cascade="all" 

se aplica la cascada para ambos Actualización y Desalojar acciones. Mi postUpdate se disparará 2 veces, pero al mismo tiempo Evict intentará desalojar a las entidades secundarias.

La solución fue eliminar Evict de la cascada en el archivo de mapeo. Ahora bien, es:

cascade="persist, merge, save-update, delete, lock, refresh" 
+0

muchas gracias! – KeatsPeeks

1

me encontré con el mismo problema, pero ya que estoy usando Fluent asignaciones no hay opción para excluir Evict de la cascada. Mi solución fue la de evitar llamar Evict y basta con retirar la entidad de la sesión de caché:

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); 
    } 
} 
+0

wow No puedo creer que hibernate requiera tales engaños ... – rogerdpack

11

Según https://forum.hibernate.org/viewtopic.php?p=2424890 otra manera de evitar esto es llamar básicamente

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

y que la raíz del problema es que "si he desalojado a la entidad de la memoria caché, la confirmación() no la encontrará allí" (es decir, no es un problema de seguridad de subprocesos, es un problema de caché modificado).

+0

Este también fue mi problema, aunque estaba usando Hibernate a través de la interfaz JPA y estaba tratando con em.persist (...), em.flush() y em.detach (...). – kilo

+3

Entonces, el caso es "La entidad recién creada se separó (desalojó) de la sesión antes de que se guardara en DB" – Lu55

Cuestiones relacionadas