Widzę coś, co nazwałbym błędem w NHibernate z buforowaniem zapytań i klauzulami ORDER BY ...
Po uruchomieniu następującego zapytania ...
SELECT this_.Id as y0_,
this_.Name as y1_
FROM Products this_
WHERE this_.IsActive = 1
ORDER BY this_.IsPremium desc
... NHibernate z powodzeniem buforuje wyniki, jeśli mam włączone buforowanie zapytań i każę buforować to zapytanie (używając np. criteria.SetCacheable(true)
).
Niestety, jak cudownie NHProf mówi mi, że NHibernate używa wyników zapytania w pamięci podręcznej również podczas uruchamiania tego zapytania:
SELECT this_.Id as y0_,
this_.Name as y1_
FROM Products this_
WHERE this_.IsActive = 1
ORDER BY this_.IsPremium desc,
this_.Name
Czy ktoś może wyjaśnić dlaczego lub wskazać mi dogłębną dokumentację na temat tej „funkcji”? Lub, jeszcze lepiej, czy ktoś ma rozwiązanie na problem?
Odpowiedzi:
0 dla odpowiedzi № 1NHibernate używa buforowania pierwszego poziomu (implementowanego przez mapę tożsamości) do buforowania każdego obiektu, o który pytasz. NHibernate działa na pojedynczych jednostkach, nawet jeśli przeszukujesz listę obiektów.
Pozwól mi wyjaśnić kilka rzeczy:
pytasz, jeśli wykonasz to zapytanie i spróbujesz uzyskać encję o identyfikatorze 1:
session.get<SomeEntity>(1);
NHibernate sprawdzi pamięć podręczną, aby zobaczyć, czy tozawiera już identyfikator 1. Jeśli tak, buforowany obiekt zostanie zwrócony i nie uruchomi zapytania. jeśli nie, zapytanie zostanie wykonane po wybraniu rekordu, włóż go do pamięci podręcznej i zwróć do Ciebie. Jeśli ponownie wykonasz zapytanie, zostanie ono zapisane w pamięci podręcznej, a obiekt zostanie zwrócony bez nowego zapytania.
teraz, jeśli zapytasz taką listę:
session.QueryOver<SomeEntity>().List();
nhibernate nie wie, jakie będą identyfikatorypobrane, w ten sposób przeszukuje wszystkie rekordy i sprawdza wyniki względem pamięci podręcznej jeden po drugim, nawet jeśli zapytanie zostanie uruchomione dwukrotnie. Powiedzmy, że masz 2 rekordy (id 1 i 2) w bazie danych. Pobierasz je za pomocą zapytania, gdy pamięć podręczna jest nadal pusta. oba rekordy są pobierane, umieszczane w pamięci podręcznej i zwracane do Ciebie. teraz wstawiasz rekordy 3, 4 i 5, a gdy jesteś przy nim, zaktualizujesz również rekord 1. Teraz, jeśli ponownie uruchomisz zapytanie, odczyta wszystkie 5 rekordów, ale teraz również cache 3, 4 i 5. Otrzymasz listę z 5 obiektami, z których 3, 4, 5 to te właśnie przeczytane, ale zwracane są wersje 1 i 2 w pamięci podręcznej. nie otrzymasz zaktualizowanej wersji identyfikatora 1.
aby odpowiedzieć na twoje pytanie: zmiana kolejności według nie ma znaczenia. Twoje zapytanie spowoduje zestaw rekordów, które są sprawdzane względem bufora jeden po drugim, a jeśli jeden z nich już istnieje, ta buforowana wersja jest zwracana.
Rozwiązaniami problemów mogą być:
- using session.Refresh (obj); jeśli wiesz, które zostały zaktualizowane.
- eksmitować niektóre lub wszystkie podmioty z sesji (co oznacza, że „zostaną one wyrzucone z pamięci podręcznej i mogą zostać ponownie wygenerowane za pomocą zapytania). Uwaga: jeśli je wyrzucisz, zmiany nie zostaną zapisane.
- możesz użyć sesji bezstanowej, która - jak sugeruje nazwa bezstanowa - nie ma pamięci podręcznej.