NHibernate ISession Flush: gdzie i kiedy go używać i dlaczego?

187

Jedną z rzeczy, które całkowicie mnie zdezorientowały, jest użycie session.Flushw połączeniu z session.Commiti session.Close.

Czasami session.Closedziała, np. Zatwierdza wszystkie zmiany, których potrzebuję. Wiem, że muszę użyć zatwierdzenia, gdy mam transakcję lub jednostkę pracy z kilkoma tworzeniami / aktualizacjami / usuwaniem, aby móc wybrać wycofanie w przypadku wystąpienia błędu.

Ale czasami naprawdę przeszkadza mi logika, która za tym stoi session.Flush. Widziałem przykłady, w których masz a, session.SaveOrUpdate()po którym następuje kolor, ale kiedy usuwam Flush, i tak działa dobrze. Czasami napotykam błędy w oświadczeniu Flush, które mówią, że sesja przekroczyła limit czasu, a usunięcie go zapewniło, że nie napotkam tego błędu.

Czy ktoś ma dobrą wskazówkę, gdzie i kiedy używać koloru? Sprawdziłem dokumentację NHibernate na ten temat, ale nadal nie mogę znaleźć prostej odpowiedzi.

Jon Limjap
źródło

Odpowiedzi:

236

Krótko:

  1. Zawsze używaj transakcji
  2. Nie używaj Close(), zamiast tego zawijaj wywołania w instrukcji ISessionwewnętrznej usinglub zarządzaj cyklem życia swojej ISession w innym miejscu .

Z dokumentacji :

Od czasu do czasu ISessionbędzie wykonywał instrukcje SQL potrzebne do synchronizacji stanu połączenia ADO.NET ze stanem obiektów przechowywanych w pamięci. Ten proces, opróżnianie, występuje domyślnie w następujących punktach

  • z niektórych wywołań Find()orEnumerable()
  • z NHibernate.ITransaction.Commit()
  • z ISession.Flush()

Instrukcje SQL są wydawane w następującej kolejności

  1. wszystkie wstawienia elementów, w tej samej kolejności, przy użyciu którego zostały zapisane odpowiednie obiekty ISession.Save()
  2. wszystkie aktualizacje encji
  3. wszystkie usunięcia kolekcji
  4. wszystkie usunięcia, aktualizacje i wstawienia elementów kolekcji
  5. wszystkie wstawki do kolekcji
  6. wszystkie usunięcia jednostek w tej samej kolejności, w których odpowiadające im obiekty zostały usunięte za pomocą ISession.Delete()

(Wyjątkiem jest to, że obiekty korzystające z natywnego generowania identyfikatorów są wstawiane podczas zapisywania).

Z wyjątkiem sytuacji, gdy jest to jednoznaczne Flush(), nie ma absolutnie żadnych gwarancji, kiedy sesja wykona wywołania ADO.NET, a jedynie kolejność, w jakiej są wykonywane . Jednak NHibernate gwarantuje, że ISession.Find(..)metody nigdy nie zwrócą nieaktualnych danych; ani nie zwrócą niewłaściwych danych.

Można zmienić domyślne zachowanie, aby spłukiwanie występowało rzadziej. FlushModeKlasa definiuje trzy różne tryby: przemywać tylko popełnić czasu (i tylko wtedy, gdy NHibernate ITransactionjest używane API), równo automatycznie za pomocą wyjaśnił rutyna, albo nigdy równo chyba Flush()nazywa się jawnie. Ostatni tryb jest przydatny w przypadku długo działających jednostek pracy, w których jest ISessionon otwarty i odłączony przez długi czas.

...

Zapoznaj się również z tą sekcją :

Zakończenie sesji obejmuje cztery różne fazy:

  • opróżnij sesję
  • zatwierdzić transakcję
  • zamknij sesję
  • obsługi wyjątków

Opróżnianie sesji

Jeśli korzystasz z ITransactioninterfejsu API, nie musisz się martwić o ten krok. Zostanie wykonany niejawnie, gdy transakcja zostanie zatwierdzona. W przeciwnym razie należy zadzwonić, ISession.Flush()aby upewnić się, że wszystkie zmiany są zsynchronizowane z bazą danych.

Zatwierdzenie transakcji bazy danych

Jeśli używasz NHibernate ITransaction API, wygląda to tak:

tx.Commit(); // flush the session and commit the transaction

Jeśli samodzielnie zarządzasz transakcjami ADO.NET, należy ręcznie Commit()wykonać transakcję ADO.NET.

sess.Flush();
currentTransaction.Commit();

Jeśli zdecydujesz się nie zatwierdzać zmian:

tx.Rollback();  // rollback the transaction

lub:

currentTransaction.Rollback();

Jeśli wycofasz transakcję, powinieneś natychmiast zamknąć i odrzucić bieżącą sesję, aby upewnić się, że stan wewnętrzny NHibernate jest spójny.

Zamknięcie ISession

Wezwanie do ISession.Close()oznaczenia końca sesji. Główną konsekwencją metody Close () jest to, że połączenie ADO.NET zostanie porzucone przez sesję.

tx.Commit();
sess.Close();

sess.Flush();
currentTransaction.Commit();
sess.Close();

Jeśli podałeś własne połączenie, Close()zwraca do niego odwołanie, aby można było je ręcznie zamknąć lub zwrócić do puli. W przeciwnym razie Close()zwraca go do puli.

Matt Hinze
źródło
2
dla mnie kluczem był ten wiersz: „Główną implikacją metody Close () jest to, że połączenie ADO.NET zostanie porzucone przez sesję”. jeśli nie wywołasz ISession.Close (), twoje połączenia zostaną zapełnione, dopóki nie pojawią się limity czasu db. : o
Dave Thieben
Zwykle: sesja otwarta sesja.BeginTransaction () praca ... sesja.Transaction.Commit () sesja.BeginTransaction () praca ... sesja.Transaction.Commit () sesja.BeginTransaction () praca .. sesja.Transaction.Commit () usuń sesję.
Agile Jedi
Genialny zapis i +1 itd. - jednak myślę, że może być wymagana edycja, ponieważ na górze mówisz „Nigdy nie używaj zamknięcia”, a później „Jeśli cofniesz transakcję, powinieneś natychmiast zamknąć i odrzucić bieżącą sesję”
SpaceBison
Czy można zmienić kolejność instrukcji SQL. Mam na myśli, że muszę wykonać aktualizację na obiekcie jednostki, a następnie wstawić, ponieważ mam ograniczenie w odpowiedniej tabeli.
bob_saginowski
14

Począwszy od NHibernate 2.0 transakcje są wymagane do operacji DB. Dlatego ITransaction.Commit()wywołanie zajmie się każdym koniecznym spłukiwaniem. Jeśli z jakiegoś powodu nie korzystasz z transakcji NHibernate, automatyczne opróżnianie sesji nie będzie możliwe.

Sean Carpenter
źródło
1

Od czasu do czasu ISession będzie wykonywał instrukcje SQL potrzebne do synchronizacji stanu połączenia ADO.NET ze stanem obiektów przechowywanych w pamięci.

I zawsze używaj

 using (var transaction = session.BeginTransaction())
 {
     transaction.Commit();
 }

po zatwierdzeniu zmian niż te zmiany do zapisania w bazie danych używamy transaction.Commit ();

ganders
źródło
0

Oto dwa przykłady mojego kodu, w których nie udałoby się to bez sesji.Flush ():

http://www.lucidcoding.blogspot.co.uk/2012/05/changing-type-of-entity-persistence.html

na końcu możesz zobaczyć sekcję kodu, w której włączam wstawianie tożsamości, zapisuję jednostkę, a następnie opróżniam, a następnie wyłączam wstawianie tożsamości. Bez tego spłukiwania wydawało się, że włącza i wyłącza wstawianie tożsamości, a następnie zapisuje jednostkę.

Użycie Flush () dało mi większą kontrolę nad tym, co się dzieje.

Oto kolejny przykład:

Wysyłanie wiadomości NServiceBus wewnątrz TransactionScope

Nie do końca rozumiem, dlaczego w tym przypadku, ale Flush () zapobiegła wystąpieniu mojego błędu.

Paul T. Davies
źródło