Klient a ocena serwera

Ogólnie rzecz biorąc, platforma Entity Framework Core próbuje ocenić zapytanie na serwerze, jak najwięcej. Program EF Core konwertuje części zapytania na parametry, które można ocenić po stronie klienta. Pozostała część zapytania (wraz z wygenerowanymi parametrami) jest podawana dostawcy bazy danych w celu określenia równoważnego zapytania bazy danych do oceny na serwerze. Program EF Core obsługuje częściową ocenę klienta w projekcji najwyższego poziomu (zasadniczo ostatnie wywołanie metody ).Select() Jeśli projekcja najwyższego poziomu w zapytaniu nie może zostać przetłumaczona na serwer, program EF Core pobierze wszystkie wymagane dane z serwera i oceni pozostałe części zapytania na kliencie. Jeśli program EF Core wykryje wyrażenie, w dowolnym miejscu innym niż projekcja najwyższego poziomu, którego nie można przetłumaczyć na serwer, zgłasza wyjątek środowiska uruchomieniowego. Zobacz Jak działają zapytania, aby zrozumieć, jak program EF Core określa, czego nie można przetłumaczyć na serwer.

Uwaga

Przed wersją 3.0 program Entity Framework Core obsługuje ocenę klienta w dowolnym miejscu w zapytaniu. Aby uzyskać więcej informacji, zobacz sekcję poprzednich wersji.

Napiwek

Przykład z tego artykułu można zobaczyć w witrynie GitHub.

Ocena klienta w projekcji najwyższego poziomu

W poniższym przykładzie metoda pomocnika służy do standaryzacji adresów URL dla blogów, które są zwracane z bazy danych programu SQL Server. Ponieważ dostawca programu SQL Server nie ma wglądu w sposób implementacji tej metody, nie można go przetłumaczyć na język SQL. Wszystkie inne aspekty zapytania są oceniane w bazie danych, ale przekazanie zwróconej URL metody odbywa się na kliencie.

var blogs = context.Blogs
    .OrderByDescending(blog => blog.Rating)
    .Select(
        blog => new { Id = blog.BlogId, Url = StandardizeUrl(blog.Url) })
    .ToList();
public static string StandardizeUrl(string url)
{
    url = url.ToLower();

    if (!url.StartsWith("http://"))
    {
        url = string.Concat("http://", url);
    }

    return url;
}

Nieobsługiwana ocena klienta

Chociaż ocena klienta jest przydatna, czasami może to spowodować niską wydajność. Rozważ następujące zapytanie, w którym metoda pomocnika jest teraz używana w filtrze where. Ponieważ nie można zastosować filtru w bazie danych, wszystkie dane należy ściągnąć do pamięci, aby zastosować filtr na kliencie. Na podstawie filtru i ilości danych na serwerze ocena klienta może spowodować niską wydajność. Dlatego program Entity Framework Core blokuje taką ocenę klienta i zgłasza wyjątek środowiska uruchomieniowego.

var blogs = context.Blogs
    .Where(blog => StandardizeUrl(blog.Url).Contains("dotnet"))
    .ToList();

Jawna ocena klienta

Może być konieczne wymusienie jawnej oceny klienta w niektórych przypadkach, takich jak następujące

  • Ilość danych jest niewielka, aby ocena na kliencie nie ponosiła ogromnej kary za wydajność.
  • Używany operator LINQ nie ma tłumaczenia po stronie serwera.

W takich przypadkach można jawnie wyrazić zgodę na ocenę klienta, wywołując metody takie jak AsEnumerable lub ToList (AsAsyncEnumerable lub ToListAsync asynchroniczne). Dzięki użyciu AsEnumerable polecenia można przesyłać strumieniowo wyniki, ale użycie ToList spowoduje buforowanie przez utworzenie listy, która również pobiera dodatkową pamięć. Chociaż jeśli wyliczasz wiele razy, przechowywanie wyników na liście pomaga bardziej, ponieważ istnieje tylko jedno zapytanie do bazy danych. W zależności od konkretnego użycia należy ocenić, która metoda jest bardziej przydatna w danym przypadku.

var blogs = context.Blogs
    .AsEnumerable()
    .Where(blog => StandardizeUrl(blog.Url).Contains("dotnet"))
    .ToList();

Napiwek

Jeśli używasz AsAsyncEnumerable polecenia i chcesz utworzyć zapytanie dalej po stronie klienta, możesz użyć biblioteki System.Interactive.Async, która definiuje operatory dla asynchronicznych wyliczenia. Aby uzyskać więcej informacji, zobacz Operatory linq po stronie klienta.

Potencjalny wyciek pamięci w ocenie klienta

Ponieważ tłumaczenie i kompilacja zapytań są kosztowne, program EF Core buforuje skompilowany plan zapytania. Buforowany delegat może używać kodu klienta podczas oceny klienta projekcji najwyższego poziomu. Program EF Core generuje parametry dla części drzewa ocenianego przez klienta i ponownie używa planu zapytania, zastępując wartości parametrów. Jednak niektórych stałych w drzewie wyrażeń nie można przekonwertować na parametry. Jeśli buforowany delegat zawiera takie stałe, nie można odzyskać pamięci tych obiektów, ponieważ są one nadal przywoływane. Jeśli taki obiekt zawiera obiekt DbContext lub inne usługi, może to spowodować wzrost użycia pamięci aplikacji w czasie. To zachowanie jest zazwyczaj oznaką przecieku pamięci. Program EF Core zgłasza wyjątek za każdym razem, gdy występuje stałe typu, którego nie można zamapować przy użyciu bieżącego dostawcy bazy danych. Typowe przyczyny i ich rozwiązania są następujące:

  • Przy użyciu metody wystąpienia: w przypadku używania metod wystąpienia w projekcji klienta drzewo wyrażeń zawiera stałą wystąpienia. Jeśli metoda nie używa żadnych danych z wystąpienia, rozważ utworzenie metody statycznej. Jeśli potrzebujesz danych wystąpienia w treści metody, przekaż określone dane jako argument do metody.
  • Przekazywanie argumentów stałych do metody: ten przypadek występuje zazwyczaj przy użyciu this argumentu do metody klienta. Rozważ podzielenie argumentu na wiele argumentów skalarnych, które mogą być mapowane przez dostawcę bazy danych.
  • Inne stałe: jeśli stała występuje w każdym innym przypadku, możesz ocenić, czy stała jest potrzebna w przetwarzaniu. Jeśli konieczne jest posiadanie stałej lub jeśli nie możesz użyć rozwiązania z powyższych przypadków, utwórz zmienną lokalną do przechowywania wartości i użyj zmiennej lokalnej w zapytaniu. Program EF Core przekonwertuje zmienną lokalną na parametr.

Poprzednie wersje

Poniższa sekcja dotyczy wersji programu EF Core przed wersją 3.0.

Starsze wersje programu EF Core obsługują ocenę klienta w dowolnej części zapytania — nie tylko projekcja najwyższego poziomu. Dlatego zapytania podobne do jednego opublikowanego w sekcji Nieobsługiwane oceny klienta działały prawidłowo. Ponieważ to zachowanie może powodować niezauważone problemy z wydajnością, program EF Core zarejestrował ostrzeżenie dotyczące oceny klienta. Aby uzyskać więcej informacji na temat wyświetlania danych wyjściowych rejestrowania, zobacz Rejestrowanie.

Opcjonalnie program EF Core umożliwia zmianę domyślnego zachowania w taki sposób, aby zgłaszał wyjątek lub nie robił nic podczas oceny klienta (z wyjątkiem projekcji). Wyjątek zgłaszający zachowanie będzie podobny do zachowania w wersji 3.0. Aby zmienić zachowanie, należy skonfigurować ostrzeżenia podczas konfigurowania opcji kontekstu — zazwyczaj w DbContext.OnConfiguringsystemie lub, Startup.cs jeśli używasz ASP.NET Core.

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder
        .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFQuerying;Trusted_Connection=True;")
        .ConfigureWarnings(warnings => warnings.Throw(RelationalEventId.QueryClientEvaluationWarning));
}