2009-09-24 14 views
9

Występują problemy z moją ISessions w NHibernate. Wciąż otrzymuję "Sesja zamknięta!" błędy. Czy ktoś może mi pokazać poprawny wzór zawierający definicję następujących metod i kiedy używać każdego:Jak prawidłowo używać obiektu NHibernate ISession - Sesja jest zamknięta! błędy

ISession.Close() 
ISession.Dispose() 
ISession.Disconnect() 

Oto mój problem. Mam konfigurację oddzwaniania, aby odpalić proces, który co kilka minut przyznaje graczom odznaki. Jednak wciąż otrzymuję "Sesja zamknięta!" błędy lub błędy związane z brakiem możliwości powiązania kolekcji.

Oto mój Repozytorium:

public class NHibernateRepository : IRepository 
{ 
#region Fields 

private ISession _session; 
private readonly ISessionFactory _sessionFactory; 
#endregion 

#region Constructors 

public NHibernateRepository(ISessionFactory sessionFactory) 
{ 
    _sessionFactory = sessionFactory; 
} 

#endregion 

#region IRepository Implementation 

public ISession OpenSession() 
{ 
    _session = _sessionFactory.OpenSession(); 
    return _session; 
} 

public IQueryable<TModel> All<TModel>() 
{ 
    return _session.Linq<TModel>(); 
} 

public void Save<TModel>(TModel model) 
{ 
    _session.Save(model); 
} 
public void Update<TModel>(TModel model) 
{ 
    _session.Update(model); 
} 
public void Delete<TModel>(TModel model) 
{ 
    _session.Delete(model); 
} 

public ITransaction BeginTransaction() 
{ 
    return _session.BeginTransaction(); 
} 
public void Flush() 
{ 
    _session.Flush(); 
} 
#endregion 

} 

Oto mój zwyczaj. Repozytorium jest wstrzykiwane za pomocą mapy struktury

private Object _awardBadgesLock = new object(); //In case the callback happens again before the previous one completes 

public void AwardBadges() 
{ 

    lock (_awardBadgesLock) 
    { 
     using(session = _repository.OpenSession()) 
     { 
      foreach (var user in _repository.All<User>().ToList()) 
      { 
       var userPuzzles = _repository.All<Puzzle>().ByUser(user.Id).ToList(); 
       var userVotes = _repository.All<Vote>().Where(x => x.UserId == user.Id).ToList(); 
       var userSolutions = _repository.All<Solution>().ByUser(user.Id).ToList().Where(x => !userPuzzles.Select(y => y.Id).Contains(x.PuzzleId)); 
       var ledPuzzles = GetPuzzlesLedByUser(user.Id); 

       AwardPlayerBadge(user, userSolutions); 
       AwardCriticBadge(user, userVotes); 
       AwardCreatorBadge(user, userPuzzles); 
       AwardRidlerBadge(user, userPuzzles); 
       AwardSupporterBadge(user, userVotes); 
       AwardPopularBadge(user, userPuzzles); 
       AwardNotableBadge(user, userPuzzles); 
       AwardFamousBadge(user, userPuzzles); 
       AwardLeaderBadge(user, ledPuzzles); 

       using (var tx = _repository.BeginTransaction()) 
       { 
        _repository.Update(user); 
        tx.Commit(); 
       } 
      } 
     } 
    } 

} 
+0

czy to jest aplikacja internetowa? – mxmissile

+0

Tak, nie jest to aplikacja internetowa, ale nie integruję sesji NHibernate z sesją internetową. – Micah

+3

Czy to _repository używane są gdziekolwiek indziej?Ponieważ inne wywołanie OpenSession() straciłoby pierwsze. – dotjoe

Odpowiedz

0

Kwestia polega na tym, że ISession nie jest bezpieczna dla wątków. W osobnych wątkach uruchamiano wiele metod, które stworzyły instancję ISession. Problem polegał na tym, że wszyscy oni dzielili tę samą SessionFactory. Obraz obu tych metod są wystrzelone na oddzielnych wątków:

ISessionFactory _sessionFactory; 

void MethodOne() 
{ 
    using(ISession session = _sessionFactory.OpenSession()) 
    { 
     //Do something with really quick with the session 
     //Then dispose of it 
    } 
} 

void MethodTwo() 
{ 
    //OpenSession() actually returns the same instance used in the 
    //previous method that has already disposed of the object; 
    using(ISession session = _sessionFactory.OpenSession()) 
    { 
     //Do something with a session that has already been disposed 
     //throws errors 

    } 
} 

Jak Naprawiłem to w zasadzie wodowania NHibernate w tych scenariuszach i nazwał przechowywane procs zamiast. Wydaje mi się, że i tak okazało się bardziej skuteczne w mojej sytuacji.

+2

Interesujące - z jakiej implementacji 'ISessionFactory' korzystasz? [Dokumentacja interfejsu] (https://nhibernate.svn.sourceforge.net/svnroot/nhibernate/trunk/nhibernate/src/NHibernate/ISessionFactory.cs) mówi: "Implementatory muszą być threadafe." –

+0

To jest dokładnie problem. "Implementatory muszą być bezpieczne dla wątków", ponieważ SessionFactory nie jest bezpieczny dla wątków. – Micah

+5

Dobrze, ale * jakie * konkretne wdrożenie 'ISessionFactory'? 'SessionFactoryImpl'? Jestem pewien, że możesz odtworzyć problem (lub jeszcze lepiej zlokalizować błąd [w kodzie źródłowym] (https://nhibernate.svn.sourceforge.net/svnroot/nhibernate/trunk/nhibernate/src/NHibernate/Impl /SessionFactoryImpl.cs)), zespół NHibernate byłby zainteresowany słuchaniem o tym. –

13

Powinieneś zawsze używać session.Dispose(); Drugim są dla bardzo dziwnych wystąpień

+4

Używam instrukcji "using", która wywołuje dispose. Nadal dostaję błąd i nie zdarza się to cały czas. Tylko trochę czasu. – Micah

6

I rada do zapoznania się z dokumentacją ISession na https://nhibernate.svn.sourceforge.net/svnroot/nhibernate/trunk/nhibernate/src/NHibernate/ISession.cs

Anyway właściwy sposób, aby oczyścić po zakończeniu z sesji jest go wyrzucać (lub lepiej, otaczaj użycie za pomocą instrukcji). W tym przypadku "używanie" zamyka sesję i blokuje finalizator, tj. Zapobiega niepotrzebnemu zachowaniu obiektu sesji podczas następnego zbierania śmieci i zapisaniu pamięci.

Jeśli połączenie jest już zamknięte, usunięcie go nie spowoduje wyjątku. Z drugiej strony zamykanie po wyrzuceniu (lub po zamknięciu) zgłasza wyjątek.

Dokumentacja zaleca wywoływanie rozłączania zamiast zamykania, ponieważ powoduje to zwolnienie połączenia z pulą połączeń. Powinieneś zadzwonić do Reconnect przed użyciem rozłączonej sesji.

Dla moich potrzeb zawsze używam "używania", który nazywa się "usuwaj" i nigdy nie korzystałem z dwóch funkcji.

+2

Ale on używa "używania", prawda? ... using (session = _repository.OpenSession()) – UpTheCreek

0

O problemie, twoja metoda blokowania jest odpowiednia, o ile pozbędziesz się sesji, ale prawdopodobnie błąd leży pod inną częścią twoich kodów. przy okazji na temat projektu, to lepiej, że do zmiennej sesji do repozytoriów, ponieważ jednostki realizacji prac sesji i transakcji kruszywo roota tak:

using (ISession session = SessionFactory.OpenSession()) 
{ 
    Repository1 rep1 = new Repository1(session); 
    Repository2 rep1 = new Repository2(session); 
    Repository3 rep1 = new Repository3(session); 

    // some logics 

    using (var tx = session.BeginTransaction()) 
     tx.Commit(); 
} 

. . .

Powiązane problemy