2012-10-04 8 views
7

Mam użytkownika, który ma wiele ról. Użytkownik jest połączony z rolami za pomocą tabeli encji łączenia. Ustawiłem plik konfiguracyjny, aby kaskadowo usuwał elementy encji roli użytkownika, gdy użytkownik jest usuwany.Dlaczego funkcja Session.Evict w pliku OnPostUpdate powoduje wyjątek "Możliwy brak dostępu do sesji"?

W tej chwili używamy miękkiego usunięcia do usunięcia encji. Dodaliśmy detektor zdarzeń usuwania miękkiego, który jest wyzwalany przez usunięcie. Gdy obiekt jest usuwany, wyzwala zdarzenie DeleteEntity, które oznacza usuniętą jednostkę.

Mamy również zastąpić zdarzenie OnPostUpdate, aby usunąć elementy z pamięci podręcznej, wywołując Evict na encji.

Jeśli utworzę użytkownika bez żadnych ról, usuń go, wszystko działa poprawnie (działa również po wyłączeniu kaskady). Jednak jeśli mam użytkownika z co najmniej jedną rolą przypisaną i usuwam użytkownika, po wywołaniu Evict w OnPostUpdate, otrzymuję wyjątek NHibernate "NHibernate.AssertionFailure: Possible nonthreadsafe access to session".

Próbowałem, w OnPostUpdate, użyć sesji potomnej do eksmisji podmiotu, wyjątek nie jest wyrzucany, jednak jednostka nie jest eksmitowana.

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

Wszelkie pomysły na rozwiązanie problemu?

Odpowiedz

3

Znaleziono problem. Użycie opcji miękkiego usunięcia spowoduje wyzwolenie aktualizacji w celu ustawienia flagi isDeleted. Z powodu tej linii w mapowaniu

cascade="all" 

kaskada jest stosowana zarówno Update i Wykluczanie działań. Moja PostUpdate zostanie zwolniona 2 razy, ale w tym samym czasie Evict będzie próbował eksmitować dzieci.

Rozwiązaniem było usunięcie Evict z kaskady w pliku odwzorowania. Teraz jest:

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

dziękuję bardzo! – KeatsPeeks

1

wpadłem na ten sam problem, ale ponieważ używam Fluent mapowania nie ma opcji, aby wykluczyć Evict z kaskady. Moje rozwiązanie było uniknąć wywoływania Evict i po prostu usunąć jednostkę z pamięci podręcznej sesji:

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 Nie mogę uwierzyć, że hibernate wymaga takich shenaniganów ... – rogerdpack

11

Według https://forum.hibernate.org/viewtopic.php?p=2424890 inny sposób na uniknięcie tego jest w zasadzie nazwać

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

i że główny problem jest to, że "jeśli wyeksmitowałem obiekt z pamięci podręcznej, commit() go tam nie odnajdzie" (tj. nie jest to w ogóle kwestia bezpieczeństwa wątków, to zmodyfikowany problem z pamięcią podręczną).

+0

To był także mój problem, chociaż używałem Hibernate przez interfejs JPA i zajmowałem się em.persist (...), em.flush() i em.detach (...). – kilo

+3

Tak jest w przypadku "Nowo utworzony podmiot został odłączony (eksmitowany) od sesji, zanim został zapisany do DB" – Lu55

Powiązane problemy