2012-03-21 24 views
6

Zastanawiam się nad wykonaniem własnej implementacji IUnitOfWork dla warstwy trwałości NHibernate.Czy w ramach jednej sesji w nhibernate można wykonać wiele transakcji? I czy to zły pomysł?

Wygląda na to, że właściwym sposobem jest utworzenie egzemplarza ISession i ITransaction w konstruktorze, a następnie umieszczenie w destruktorze lub metodzie Dispose().

Oczywiście, jeśli ktoś wywołuje metodę Save(), wówczas ISession będzie zaczerwieniona i ITransaction byłaby kompletna, więc po wywołaniu Save(), nie byłby ważny otwarty transakcji Save() znowu ... chyba że popełnione pierwsza transakcja i natychmiast otworzyła kolejną, nową transakcję. Ale czy to dobry pomysł?

Z punktu widzenia projektowania, ma sens wykonanie jednej operacji zatwierdzenia, ale niekoniecznie będę mieć kontrolę nad kodem, a inni programiści mogą być mniej zdyscyplinowani w związku ze wzorem UnitOfWork.

Czy mogę stracić/zyskać cokolwiek, starając się, aby UnitOfWork był odporny na wiele transakcji na sesję? Czy powinienem po prostu sprawdzić otwartą transakcję i wyrzucić wyjątek, jeśli został już zatwierdzony, zamiast dokonywać nowej transakcji?

+0

Web lub aplikacja na pulpicie? – Phill

+0

Jest przeznaczony do aplikacji internetowej. –

Odpowiedz

11

Aby odpowiedzieć na pierwsze pytanie: tak, możliwe jest posiadanie wielu transakcji w jednej sesji.

Czy to dobry pomysł? To zależy.

Problem polega na tym, że zmiana danych w pierwszej transakcji zostałaby zatwierdzona, podczas gdy nie jest pewne, czy cała jednostka pracy (sesja) zostanie zatwierdzona na końcu. Kiedy pojawi się, powiedzmy, wyjątek StaleObjectException w późniejszej transakcji, masz już pewne dane zatwierdzone. Zauważ, że ten rodzaj wyjątku sprawia, że ​​twoja sesja jest bezużyteczna i musiałaś ją zniszczyć. Wtedy trudno jest zacząć od nowa i spróbować ponownie.

Powiedziałbym, że działa dobrze w tych warunkach:

  • Jest to aplikacja UI
  • Zmiany są wypłukiwane tylko w ostatniej transakcji.

UI Application

Błędy są obsługiwane przez użytkownika interaktywnie.Oznacza to, że użytkownik może zobaczyć, co faktycznie jest przechowywane w przypadku błędu i powtarza zmiany, które wprowadził.

Zmiany są wypłukiwane tylko w ostatniej transakcji

Sesja wykonywanym NH opróżnia tylko zmiany na końcu lub na „w razie potrzeby”. Tak więc możliwe byłoby zachowanie zmian w pamięci, dopóki sesja nie zostanie zatwierdzona. Problem polega na tym, że NH musi opróżnić sesję przed każdym zapytaniem, które jest trudne do kontrolowania. Można go wyłączyć, co prowadzi do efektów ubocznych. Podczas pisania prostych transakcji możesz mieć to pod kontrolą. W złożonym systemie praktycznie niemożliwe jest upewnienie się, że nic nie idzie źle.

prosty sposób (tm)

pisałem warstwę utrzymywanie się dość dużym systemie klient-serwer. W takim systemie nie występują bezpośrednio błędy obsługi użytkownika. Musisz obsługiwać błędy w systemie i zwracać kontrolę do klienta w spójnym stanie.

Uproszyłem całą obsługę transakcji do absolutnego minimum, aby uczynić ją stabilną i "dowodem tożsamości". Zawsze mam sesję i transakcję stworzoną razem, która jest albo zatwierdzona, albo nie.

+0

Rozumiem, że wywołanie 'ITransaction.Commit()' spowoduje opróżnienie sesji. Tworzenie instancji nowej 'ITransaction' przy użyciu tej samej sesji i natychmiast po' Commit() ', jakie okoliczności wygenerowałoby' StaleObjectException'? –

+0

Zatwierdzenie transakcji powoduje zablokowanie. To sprawia, że ​​jest bardziej prawdopodobne, że uzyskasz StaleObjectExceptions. Ale i tak możesz je zdobyć, ponieważ dane mogą się zmienić w db, gdy zmieniasz je w pamięci. Optymistyczne blokowanie NH umożliwia przynajmniej wykrycie tych konfliktów. –

+1

Dzięki za szczegółową odpowiedź. –

2

Istnieje wiele opcji dostępnych do wdrożenia zagnieżdżonej transakcji nhibernate z jednostką pracy.

Tutaj używam wzorca polecenia dla jednostki pracy.

+0

Wystarczy wskazać kilka rzeczy: 1) Istnieje już System.Action , aby wprowadzić w błąd co do nazwy. 2) Twoja klasa Action nie określa, skąd pochodzi transakcja. 3) To nadal spowoduje te same błędy, co transakcje zagnieżdżone, które już występują w NHibernate (zatwierdzenie transakcji wewnętrznej spowoduje, że zewnętrzna transakcja wyrzuci wyjątek ObjectDisposedException). – rossisdead

0

Myślę, że rozwiązanie z jedną transakcją na jednostkę pracy jest zbyt restrykcyjne. W niektórych środowiskach może być potrzebna możliwość wykonania kilku transakcji na sesję. Ja osobiście zarządzam transakcjami i wydaje się, że jest to elastyczne rozwiązanie.

public interface IUnitOfWork: IDisposable 
{ 
    IGenericTransaction BeginTransaction(); 
} 

public interface IGenericTransaction: IDisposable 
{ 
    void Commit(); 

    void Rollback(); 
} 

public class NhUnitOfWork: IUnitOfWork 
{ 
    private readonly ISession _session; 

    public ISession Session 
    { 
     get { return _session; } 
    } 

    public NhUnitOfWork(ISession session) 
    { 
     _session = session; 
    } 

    public IGenericTransaction BeginTransaction() 
    { 
     return new NhTransaction(_session.BeginTransaction()); 
    } 

    public void Dispose() 
    { 
     _session.Dispose(); 
    } 
} 

public class NhTransaction: IGenericTransaction 
{ 
    private readonly ITransaction _transaction; 

    public NhTransaction(ITransaction transaction) 
    { 
     _transaction = transaction; 
    } 

    public void Commit() 
    { 
     _transaction.Commit(); 
    } 

    public void Rollback() 
    { 
     _transaction.Rollback(); 
    } 

    public void Dispose() 
    { 
     _transaction.Dispose(); 
    } 
} 

Użycie wygląda tak. Jest łatwo wbudowany w dowolny wzór.

public void Do(IUnitOfWork uow) 
{ 
    using (var tx = uow.BeginTransaction()) { 
    // DAL calls 
    tx.Commit(); 
    } 
} 
+0

To jest dokładnie to, co robimy, ale to nie działa w tym przypadku: nie można edytować kodu w komentarzu, chyba ... Ale jeśli masz inną transakcję tam, to nie działa. Ale powinno. Zagnieżdżone transakcje są realizowane w bazach danych bez ważnego powodu. – user2415376

Powiązane problemy