2010-09-15 13 views
7

Według NHProf, stosowanie ukrytych transakcji jest odradzane:Jak zachować IQueryable <> w transakcji przy użyciu wzorca repozytorium?

http://nhprof.com/Learn/Alerts/DoNotUseImplicitTransactions

Jednakże NHibernate LINQ zwraca IQueryable<> podczas odczytu obiektów z bazy danych, a to leniwie oceniany. Mam tej metody w repozytorium:

public IQueryable<T> GetAll<T>() 
{ 
    using (var transaction = _session.BeginTransaction()) 
    { 
     var data = _session.Linq<T>(); 
     transaction.Commit(); 
     return data; 
    } 
} 

Problem jest to, że metoda zatwierdzania transakcji przed data jest oceniany. Czy istnieje sposób na użycie wzorca repozytorium i zachowanie IQueryable<> w transakcji jawnej? Czy jest akceptowalne, aby operacje odczytu używały transakcji niejawnych?

+4

Dlaczego chcesz transakcji wokół operacji odczytu? –

+3

Ah, z artykułu: "Nawet jeśli czytamy tylko dane, powinniśmy użyć transakcji, ponieważ korzystanie z transakcji zapewnia uzyskanie spójnych wyników z bazy danych NHibernate zakłada, że ​​cały dostęp do bazy danych odbywa się w ramach transakcji, oraz zdecydowanie zniechęca do korzystania z sesji bez transakcji. " Nadal jednak nie rozumiem, dlaczego autor robi tę deklamację. –

Odpowiedz

5

Repozytorium powinny nie utworzyć transakcję. To odpowiedzialność oddzielnej warstwy (która zależy od typu aplikacji).

+0

Zgadzam się, domyślam się, że twoje wyjaśnienie, dlaczego uważasz, że to jest odpowiedzialność oddzielnej warstwy jest coś takiego: Granice transakcji powinny być zdefiniowane przez użytkownika lub inne aplikacje wchodzące w interakcje z aplikacją. Przykład aplikacji internetowych na żądanie, dla usług na wywołanie usługi, dla aplikacji Windows na "kliknięcie przycisku", dla gier na ruch itp. Gdy transakcje są tworzone przez repozytorium, znacznie trudniej będzie stworzyć repozytorium niezależnie od sposobu interakcji aplikacji z nią, a także może utrudnić korzystanie z niej w ogóle. – Paco

3

Chciałbym to zmienić, aby umożliwić kontrolę transakcji zewnętrznych. Repozytorium nie może znać zakresu jednostki pracy, której częścią są różne wywołania odczytu/zapisu, chyba że kod wywołujący je wywoła. Rozważ ustawienie schematu "jednostki pracy": bez ujawniania konkretnych szczegółów implementacji magazynu danych, zezwól obiektom zależnym od repozytorium, aby określały, że zaczynają, przerywają lub kończą "jednostkę pracy".

public interface IRepository 
{ 
    public UnitOfWork BeginUnitOfWork() 

    public void CommitUOW(UnitOfWork unit) 

    public void AbortUOW(UnitOfWork unit) 

    public IQueryable<T> GetAll<T>(UnitOfWork unit) 

    public List<T> GetAll<T>() 

    public void Store<T>(T theObject, UnitOfWork unit) 

    public void Store<T>(T theObject) 
} 

repozytorium pewnie zaimplementować to poprzez utrzymywanie prywatną Słownik transakcji SQL, każdy włączył do obiektu UnitOfWork (może to być tak proste, jak pustym chwilowe klasy, czy może ona dostarczyć ramową-agnostyk informacji o stanie lub metryki). Podczas wykonywania operacji DB, twoi rozmówcy najpierw poprosią o rozpoczęcie UU, a otrzymają token, który wykorzystają do identyfikacji kontekstu, w którym wykonują połączenie DB. Obiekt pobierający token może przekazać go innym klasom, które muszą wykonać operacje DB w tym samym kontekście operacyjnym. Jednostka pracy pozostanie otwarta, dopóki klasa zależna nie powie repozytorium, że jest ona skończona, pozwalając na leniwy ładunek i procedury wielozadaniowości atomowej.

zauważyć, że istnieją przeciążenia, które nie wymagają jednostek pracy. Możliwe i być może konieczne jest wykonywanie prostych połączeń bez wyraźnego uruchamiania jednostki pracy. W takich przypadkach Twoje repozytorium może utworzyć wewnętrzny UOW, wykonać żądaną operację i zwrócić wyniki. Jednak w tych przypadkach załadunek w trybie leniwym będzie trudny lub niemożliwy; będziesz musiał pobrać cały zestaw wyników do listy przed zakończeniem wewnętrznej wersji UU.

1

jestem z Diego na ten - repozytorium nie może znać zakres transakcji.

Mam też obawy o powrót IQueryable - jak rozumiem, ma mnóstwo dodatkowych metod zapytań, które mogą być bardzo trudne do testów jednostkowych. Wolę powracać IEnumerable i enkapsulować bardziej złożone kwerendy w metodach repozytoriów. W przeciwnym razie musisz przetestować wszystkie rodzaje odmian zapytań na wynik GetAll().

+1

Czy Twoim zadaniem jest testowanie wszystkich metod na IQueryable? Czy nie powinieneś być tylko kodem testów jednostkowych, który napisałeś? – Gabe

+0

@Gabe: Moją obawą nie jest testowanie jednostkowe IQueryable, to jednostka testująca wyniki n8wrl

Powiązane problemy