Śledzenie a zapytania bez śledzenia
Śledzenie kontroli zachowania, jeśli program Entity Framework Core przechowuje informacje o wystąpieniu jednostki w swoim monitorze zmian. Jeśli jednostka jest śledzona, wszelkie zmiany wykryte w jednostce są utrwalane w bazie danych podczas .SaveChanges
Program EF Core naprawia również właściwości nawigacji między jednostkami w wyniku zapytania śledzenia a jednostkami, które znajdują się w monitorze zmian.
Uwaga
Typy jednostek bez klucza nigdy nie są śledzone. Wszędzie tam, gdzie w tym artykule wymieniono typy jednostek, odnosi się do typów jednostek, które mają zdefiniowany klucz.
Napiwek
Przykład z tego artykułu można zobaczyć w witrynie GitHub.
Śledzenie zapytań
Domyślnie zapytania zwracające typy jednostek śledzą. Zapytanie śledzące oznacza, że wszelkie zmiany wystąpień jednostki są utrwalane przez SaveChanges
element . W poniższym przykładzie zmiana klasyfikacji blogów jest wykrywana i utrwalana w bazie danych podczas :SaveChanges
var blog = context.Blogs.SingleOrDefault(b => b.BlogId == 1);
blog.Rating = 5;
context.SaveChanges();
Gdy wyniki są zwracane w zapytaniu śledzenia, program EF Core sprawdza, czy jednostka jest już w kontekście. Jeśli program EF Core znajdzie istniejącą jednostkę, zwracane jest to samo wystąpienie, które może potencjalnie używać mniejszej ilości pamięci i być szybsze niż zapytanie bez śledzenia. Program EF Core nie zastępuje bieżących i oryginalnych wartości właściwości jednostki we wpisie z wartościami bazy danych. Jeśli jednostka nie zostanie znaleziona w kontekście, program EF Core utworzy nowe wystąpienie jednostki i dołączy go do kontekstu. Wyniki zapytania nie zawierają żadnej jednostki, która jest dodawana do kontekstu, ale nie jest jeszcze zapisywana w bazie danych.
Zapytania bez śledzenia
Zapytania śledzenia nie są przydatne, gdy wyniki są używane w scenariuszu tylko do odczytu. Zazwyczaj są one szybsze do wykonania, ponieważ nie ma potrzeby konfigurowania informacji śledzenia zmian. Jeśli jednostki pobrane z bazy danych nie muszą być aktualizowane, należy użyć zapytania bez śledzenia. Dla pojedynczego zapytania można ustawić brak śledzenia. Zapytanie bez śledzenia daje również wyniki na podstawie tego, co znajduje się w bazie danych, pomijając wszelkie lokalne zmiany lub dodane jednostki.
var blogs = context.Blogs
.AsNoTracking()
.ToList();
Domyślne zachowanie śledzenia można zmienić na poziomie wystąpienia kontekstu:
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
var blogs = context.Blogs.ToList();
W następnej sekcji wyjaśniono, kiedy zapytanie bez śledzenia może być mniej wydajne niż zapytanie śledzenia.
Rozpoznawanie tożsamości
Ponieważ zapytanie śledzenia używa monitora zmian, program EF Core wykonuje rozpoznawanie tożsamości w zapytaniu śledzenia. Podczas materializowania jednostki program EF Core zwraca to samo wystąpienie jednostki z monitora zmian, jeśli jest już śledzone. Jeśli wynik zawiera tę samą jednostkę wiele razy, to samo wystąpienie jest zwracane dla każdego wystąpienia. Zapytania bez śledzenia:
- Nie używaj monitora zmian i nie rób rozpoznawania tożsamości.
- Zwróć nowe wystąpienie jednostki nawet wtedy, gdy ta sama jednostka jest zawarta w wyniku wiele razy.
Śledzenie i brak śledzenia można połączyć w tym samym zapytaniu. Oznacza to, że możesz mieć zapytanie bez śledzenia, które wykonuje rozpoznawanie tożsamości w wynikach. Podobnie jak AsNoTracking operator z możliwością wykonywania zapytań dodaliśmy inny operator AsNoTrackingWithIdentityResolution<TEntity>(IQueryable<TEntity>). W wyliczenie QueryTrackingBehavior dodano również skojarzony wpis. Gdy zapytanie do używania rozpoznawania tożsamości jest skonfigurowane bez śledzenia, autonomiczny monitor zmian jest używany w tle podczas generowania wyników zapytania, więc każde wystąpienie jest zmaterializowane tylko raz. Ponieważ ten monitor zmian różni się od tego w kontekście, wyniki nie są śledzone przez kontekst. Gdy zapytanie zostanie w pełni wyliczone, śledzenie zmian wykracza poza zakres i wyrzucanie pamięci zgodnie z potrzebami.
var blogs = context.Blogs
.AsNoTrackingWithIdentityResolution()
.ToList();
Konfigurowanie domyślnego zachowania śledzenia
Jeśli zmienisz zachowanie śledzenia dla wielu zapytań, możesz zamiast tego zmienić wartość domyślną:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFQuerying.Tracking;Trusted_Connection=True;ConnectRetryCount=0")
.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
}
Dzięki temu wszystkie zapytania domyślnie nie śledzą. Możesz nadal dodawać AsTracking , aby śledzić określone zapytania.
Śledzenie i projekcje niestandardowe
Nawet jeśli typ wyniku zapytania nie jest typem jednostki, program EF Core będzie domyślnie śledzić typy jednostek zawarte w wynikach. W poniższym zapytaniu, które zwraca typ anonimowy, będą śledzone wystąpienia Blog
zestawu wyników.
var blog = context.Blogs
.Select(
b =>
new { Blog = b, PostCount = b.Posts.Count() });
Jeśli zestaw wyników zawiera typy jednostek pochodzące z kompozycji LINQ, program EF Core będzie je śledzić.
var blog = context.Blogs
.Select(
b =>
new { Blog = b, Post = b.Posts.OrderBy(p => p.Rating).LastOrDefault() });
Jeśli zestaw wyników nie zawiera żadnych typów jednostek, śledzenie nie jest wykonywane. W poniższym zapytaniu zwracamy typ anonimowy z niektórymi wartościami z jednostki (ale nie ma wystąpień rzeczywistego typu jednostki). Nie ma śledzonych jednostek wychodzących z zapytania.
var blog = context.Blogs
.Select(
b =>
new { Id = b.BlogId, b.Url });
Program EF Core obsługuje ocenę klienta w projekcji najwyższego poziomu. Jeśli program EF Core zmaterializuje wystąpienie jednostki na potrzeby oceny klienta, zostanie ono śledzone. W tym miejscu, ponieważ przekazujemy blog
jednostki do metody StandardizeURL
klienta, program EF Core będzie również śledzić wystąpienia blogu.
var blogs = context.Blogs
.OrderByDescending(blog => blog.Rating)
.Select(
blog => new { Id = blog.BlogId, Url = StandardizeUrl(blog) })
.ToList();
public static string StandardizeUrl(Blog blog)
{
var url = blog.Url.ToLower();
if (!url.StartsWith("http://"))
{
url = string.Concat("http://", url);
}
return url;
}
Program EF Core nie śledzi wystąpień jednostek bez klucza zawartych w wyniku. Jednak program EF Core śledzi wszystkie inne wystąpienia typów jednostek z kluczem zgodnie z powyższymi regułami.
Poprzednie wersje
Przed wersją 3.0 platforma EF Core miała pewne różnice w sposobie śledzenia. Istotne różnice są następujące:
Jak wyjaśniono na stronie Ocena klienta i serwera , program EF Core obsługiwał ocenę klienta w dowolnej części zapytania przed wersją 3.0. Ocena klienta spowodowała materializację jednostek, które nie były częścią wyniku. W związku z tym program EF Core przeanalizował wynik, aby wykryć, co należy śledzić. Ten projekt miał pewne różnice w następujący sposób:
Ocena klienta w projekcji, która spowodowała materializację, ale nie zwróciła zmaterializowanego wystąpienia jednostki, nie została śledzona. Poniższy przykład nie śledził
blog
jednostek.var blogs = context.Blogs .OrderByDescending(blog => blog.Rating) .Select( blog => new { Id = blog.BlogId, Url = StandardizeUrl(blog) }) .ToList();
Program EF Core nie śledził obiektów wychodzących z kompozycji LINQ w niektórych przypadkach. Poniższy przykład nie śledził
Post
.var blog = context.Blogs .Select( b => new { Blog = b, Post = b.Posts.OrderBy(p => p.Rating).LastOrDefault() });
Za każdym razem, gdy wyniki zapytania zawierały typy jednostek bez klucza, całe zapytanie zostało wykonane bez śledzenia. Oznacza to, że typy jednostek z kluczami, które są w wyniku, nie były śledzone.
Program EF Core służy do rozwiązywania problemów z tożsamościami w zapytaniach bez śledzenia. Użyto słabych odwołań, aby śledzić jednostki, które zostały już zwrócone. Dlatego jeśli zestaw wyników zawiera tę samą jednostkę wiele razy, otrzymasz to samo wystąpienie dla każdego wystąpienia. Chociaż jeśli poprzedni wynik z tą samą tożsamością wyszedł z zakresu i odebrano śmieci, program EF Core zwrócił nowe wystąpienie.