Wprowadzenie
Tak jak zapowiedziałem w poprzednim wpisie, w tym również będę kontynuował opisywanie biblioteki Entity Framework Plus, która rozszerza Entity Framework o przydatne funkcjonalności. Tym razem skupimy się na dwóch. Pierwszą będzie cache drugiego poziomu, natomiast drugą grupowanie wykonywania zapytań w jednej operacji na bazie z wykorzystaniem funkcji Future.
W przykładzie będziemy bazowali na demie z poprzedniego wpisu o filtrowaniu w Entity Framework Plus. Dlatego zachęcam Cię do jego przeczytania, jeśli tego jeszcze nie zrobiłeś(-łaś).
Cache w Entity Framework Plus
Domyślnie Entity Framework ma wbudowany tylko cache pierwszego poziomu, czyli zapisuje i wykorzystuje ponownie obiekty modelu wykorzystywane przez DataContext (DbContext). W przypadku cache’owania drugiego poziomu (który umożliwia zapisanie i ponowne wykorzystanie danych z całego zapytania) musimy posiłkować się dodatkową biblioteką. Entity Framework Plus jest właśnie takim dodatkowym narzędziem, które dostarcza nam cache drugiego poziomu.
W przykładzie zaczniemy od dwukrotnego pobrania listy aktywnych kategorii, aby zobaczyć, że na początku zapytanie wykonuje się dwa razy:
public class CacheDemo | |
{ | |
public void Run() | |
{ | |
WithoutCache(); | |
} | |
private void WithoutCache() | |
{ | |
using (var db = new DataContext()) | |
{ | |
var categories = db.Categories.Where(c => c.IsActive).ToList(); | |
Console.WriteLine($"Categories count: {categories.Count}"); | |
categories = db.Categories.Where(c => c.IsActive).ToList(); | |
Console.WriteLine($"Categories count: {categories.Count}"); | |
} | |
} | |
} |
W wyniku działania powyższego kodu na bazie wykonało się dwa razy zapytanie:
SELECT [Extent1].[Id] AS [Id], | |
[Extent1].[Name] AS [Name], | |
[Extent1].[IsActive] AS [IsActive] | |
FROM [dbo].[Categories] AS [Extent1] | |
WHERE [Extent1].[IsActive] = 1 |
Widać to w profilerze (przy okazji polecam wpis o profilowaniu zapytań w Entity Framework Profiler):
Aby skorzystać z drugiego poziomu cache z Entity Framework Plus, należy przed wywołaniem metody ToList (lub innej metody, która materializuje dane) wywołać metodę FromCache. Wtedy Entity Framework w pierwszej kolejności sprawdzi, czy ma zapisany wynik zapytania; jeśli tak, to go zwróci, a jeśli nie, to wykona zapytanie i zapisze jego wynik w cache.
Zmodyfikowany kod wygląda tak:
public class CacheDemo | |
{ | |
public void Run() | |
{ | |
WithCache(); | |
} | |
private void WithCache() | |
{ | |
using (var db = new DataContext()) | |
{ | |
var categories = db.Categories.Where(c => c.IsActive).FromCache().ToList(); | |
Console.WriteLine($"Categories count: {categories.Count}"); | |
categories = db.Categories.Where(c => c.IsActive).FromCache().ToList(); | |
Console.WriteLine($"Categories count: {categories.Count}"); | |
} | |
} | |
} |
W efekcie na bazie wykona się jedno zapytanie:
Ten mechanizm cache’owania możemy również konfigurować. Możemy na przykład przypisać tag dla takiego zapytania i później, w momencie gdy wiemy, że dane w bazie się zmieniły, możemy usunąć cache dla przypisanego taga. Podobnie jak to opisałem podczas pokazywania Cache Managera.
Możemy również określać, jak długo dane mają być zapisane w cache. Po więcej szczegółów zapraszam do dokumentacji – https://entityframework-plus.net/query-cache.
Future w Entity Framework Plus
Drugim ciekawym i czasami przydatnym mechanizmem, który opiszę w tym wpisie, jest wykorzystanie metody Future (https://entityframework-plus.net/query-future).
Entity Framework, w momencie gdy korzystamy z takich metod jak FirstOrDefault, ToList itd., od razu wykonuje takie zapytanie na bazie danych. W niektórych sytuacjach takie podejście może być nie do końca optymalne. Na przykład w sytuacji, gdy tworzymy jakiś bardziej rozbudowany obiekt, często wcześniej pobieramy powiązane obiekty za pomocą ich identyfikatorów – takie pobranie jest wykonywane w oddzielnej operacji na bazie. Gdy mamy pięć takich powiązanych obiektów, wykonujemy wtedy pięć operacji na bazie.
Metoda Future z Entity Framework Plus umożliwia nam grupowanie takich operacji poprzez odłożenie ich na przyszłość i wykonanie ich później w jednej operacji na bazie danych.
Najlepiej zobaczyć to na przykładzie. Poniżej znajduje się kod, który pobiera jedną kategorię oraz produkt na podstawie id w sposób standardowy:
public class FutureDemo | |
{ | |
public void Run() | |
{ | |
WithoutFuture(); | |
} | |
private void WithoutFuture() | |
{ | |
using (var db = new DataContext()) | |
{ | |
var categoryQuery = db.Categories.Where(c => c.Id == 1); | |
var productQuery = db.Products.Where(c => c.Id == 1); | |
var category = categoryQuery.FirstOrDefault(); | |
var product = productQuery.FirstOrDefault(); | |
Console.WriteLine($"Category: {category.Name}, Product: {product.Name}"); | |
} | |
} | |
} |
W wyniku działania powyższego kodu na bazie wykonają się dwa zapytania w dwóch operacjach:
Wykorzystanie metody Future jest dość proste: dodajemy jej wywołanie do zapytań, które mają zostać wykonane w jednej operacji na bazie. Później, podczas wykonywania pierwszego, automatycznie wykonają się wszystkie inne. W kodzie wygląda to tak:
public class FutureDemo | |
{ | |
public void Run() | |
{ | |
WithFuture(); | |
} | |
private void WithFuture() | |
{ | |
using (var db = new DataContext()) | |
{ | |
var categoryQuery = db.Categories.Where(c => c.Id == 1).Future(); | |
var productQuery = db.Products.Where(c => c.Id == 1).Future(); | |
var category = categoryQuery.FirstOrDefault(); | |
var product = productQuery.FirstOrDefault(); | |
Console.WriteLine($"Category: {category.Name}, Product: {product.Name}"); | |
} | |
} | |
} |
Natomiast w profilerze wygląda to tak:
Czyli w jednej operacji na bazie wykonywane są dwa zapytania. W przypadku grupowania większej liczby zapytań może to pozytywnie wpłynąć na obciążenie oraz efektywność systemu.
Przykład
Na githubie (https://github.com/danielplawgo/EFPlus) rozbudowałem przykład z wpisu o filtrowaniu w Entity Framework Plus. Dodałem w nim dodatkowe klasy z testami dla cache oraz Future. Po pobraniu przykładu należy ustawić w app.config poprawny connection string do bazy testowej.
Podsumowanie
Mam nadzieję, że po raz kolejny udało mi się pokazać Ci, że gdy używasz Entity Framework w swoich projektach, to warto również znać darmowe rozszerzenie Entity Framework Plus. Biblioteka ta powoduje, że praca z Entity Framework jest dużo bardziej przyjemna i efektywna. Wręcz nie wypada jej nie znać tej.
W jednym z przyszłych wpisów poruszę jeszcze temat płatnej biblioteki od ZZZ Projects – Entity Framework Extensions – https://entityframework-extensions.net.
1 thought on “Cache oraz Future z EF Plus”