Bagikan melalui


Evaluasi Penggunaan Klien vs. Server

Sebagai aturan umum, Entity Framework Core mencoba mengevaluasi kueri di server sebanyak mungkin. EF Core mengonversi bagian kueri menjadi parameter, yang dapat dievaluasi di sisi klien. Kueri lainnya (bersama dengan parameter yang dihasilkan) diberikan kepada penyedia database untuk menentukan kueri database yang setara untuk dievaluasi di server. EF Core mendukung evaluasi klien parsial pada proyeksi tingkat atas (pada dasarnya, ini adalah panggilan terakhir ke Select()). Jika proyeksi tingkat atas dalam kueri tidak dapat diterjemahkan ke server, EF Core akan mengambil data yang diperlukan dari server dan mengevaluasi bagian kueri yang tersisa pada klien. Jika EF Core mendeteksi ekspresi, di tempat mana pun selain proyeksi tingkat atas, yang tidak dapat diterjemahkan ke server, maka akan menghasilkan pengecualian saat runtime. Lihat Cara kerja kueri untuk memahami bagaimana EF Core menentukan apa yang tidak dapat diterjemahkan ke server.

Nota

Sebelum versi 3.0, Entity Framework Core mendukung evaluasi klien di mana saja dalam kueri. Untuk informasi selengkapnya, lihat bagian versi sebelumnya.

Petunjuk / Saran

Anda dapat melihat contoh artikel ini di GitHub.

Evaluasi klien dalam proyeksi tingkat atas

Dalam contoh berikut, metode pembantu digunakan untuk menstandarkan URL untuk blog, yang dikembalikan dari database SQL Server. Karena penyedia SQL Server tidak memiliki wawasan tentang bagaimana metode ini diterapkan, tidak mungkin untuk menerjemahkannya ke dalam SQL. Semua aspek lain dari kueri dievaluasi dalam database, dan pengiriman hasil yang dikembalikan melalui metode ini dilakukan di sisi klien.

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

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

    return url;
}

Evaluasi klien yang tidak didukung

Meskipun evaluasi klien berguna, terkadang dapat mengakibatkan performa yang buruk. Pertimbangkan kueri berikut, di mana metode bantu sekarang digunakan dalam filter 'where'. Karena filter tidak dapat diterapkan dalam database, semua data perlu ditarik ke dalam memori untuk menerapkan filter pada klien. Berdasarkan filter dan jumlah data di server, evaluasi klien dapat mengakibatkan performa yang buruk. Jadi Entity Framework Core memblokir evaluasi pada sisi klien tersebut dan menghasilkan pengecualian pada waktu proses.

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

Penilaian langsung klien

Anda mungkin perlu memaksa evaluasi klien secara eksplisit dalam kasus-kasus tertentu seperti berikut

  • Jumlah data kecil sehingga evaluasi pada klien tidak menyebabkan penurunan performa yang signifikan.
  • Operator LINQ yang digunakan tidak memiliki terjemahan sisi server.

Dalam kasus seperti itu, Anda dapat secara eksplisit memilih evaluasi klien dengan memanggil metode seperti AsEnumerable atau ToList (AsAsyncEnumerable atau ToListAsync untuk asinkron). Dengan menggunakan AsEnumerable Anda akan menampilkan hasilnya secara langsung, tetapi penggunaan ToList akan menimbulkan buffering karena membuat daftar, yang memerlukan memori tambahan. Meskipun jika Anda menghitung beberapa kali, maka menyimpan hasil dalam daftar akan lebih membantu karena hanya ada satu kueri ke database. Tergantung pada penggunaan tertentu, Anda harus mengevaluasi metode mana yang lebih berguna untuk kasus ini.

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

Petunjuk / Saran

Jika Anda menggunakan AsAsyncEnumerable dan ingin menyusun kueri lebih lanjut di sisi klien, maka Anda dapat menggunakan pustaka System.Interactive.Async yang menyediakan operator untuk enumerable asinkron. Untuk informasi selengkapnya, lihat operator linq sisi klien.

Potensi kebocoran memori dalam evaluasi klien

Karena terjemahan dan kompilasi kueri mahal, EF Core menyimpan cache rencana kueri yang dikompilasi. Delegasi yang di-cache dapat menggunakan kode klien saat melakukan evaluasi klien proyeksi tingkat atas. EF Core menghasilkan parameter untuk bagian pohon yang dievaluasi klien dan menggunakan kembali rencana kueri dengan mengganti nilai parameter. Tetapi konstanta tertentu di pohon ekspresi tidak dapat dikonversi menjadi parameter. Jika delegasi yang di-cache berisi konstanta tersebut, maka objek tersebut tidak dapat dikumpulkan karena masih direferensikan. Jika objek seperti itu berisi DbContext atau layanan lain di dalamnya, maka itu dapat menyebabkan penggunaan memori aplikasi tumbuh dari waktu ke waktu. Perilaku ini umumnya merupakan tanda kebocoran memori. EF Core melempar pengecualian setiap kali menemukan konstanta yang jenisnya tidak dapat dipetakan menggunakan penyedia basis data saat ini. Penyebab umum dan solusinya adalah sebagai berikut:

  • Menggunakan metode instans: Saat menggunakan metode instans dalam proyeksi klien, pohon ekspresi berisi konstanta instans. Jika metode Anda tidak menggunakan data apa pun dari instans, pertimbangkan untuk membuat metode statis. Jika Anda memerlukan data instans dalam isi metode, teruskan data tertentu sebagai argumen ke metode .
  • Meneruskan argumen konstanta ke metode: Kasus ini muncul umumnya dengan menggunakan this dalam argumen ke metode klien. Pertimbangkan untuk memisahkan argumen menjadi beberapa argumen skalar, yang dapat dipetakan oleh penyedia database.
  • Konstanta lain: Jika konstanta ditemukan dalam kasus lain, maka Anda dapat mengevaluasi apakah konstanta diperlukan dalam pemrosesan. Jika perlu memiliki konstanta, atau jika Anda tidak dapat menggunakan solusi dari kasus di atas, buat variabel lokal untuk menyimpan nilai dan menggunakan variabel lokal dalam kueri. EF Core akan mengonversi variabel lokal menjadi parameter.

Versi sebelumnya

Bagian berikut berlaku untuk versi EF Core sebelum 3.0.

Versi EF Core lama mendukung evaluasi klien di bagian mana pun dari kueri--bukan hanya proyeksi tingkat atas. Itulah sebabnya kueri yang mirip dengan kueri yang diposting di bawah bagian Evaluasi klien yang tidak didukung berfungsi dengan benar. Karena perilaku ini dapat menyebabkan masalah performa yang tidak diperhatikan, EF Core mencatat peringatan evaluasi klien. Untuk informasi selengkapnya tentang melihat output pengelogan, lihat Pengelogan.

Secara opsional EF Core memungkinkan Anda mengubah perilaku default untuk melemparkan pengecualian atau tidak melakukan apa pun saat melakukan evaluasi klien (kecuali dalam proyeksi). Perilaku melempar pengecualian akan membuatnya mirip dengan perilaku di 3.0. Untuk mengubah perilaku, Anda perlu mengonfigurasi peringatan saat menyiapkan opsi untuk konteks Anda - biasanya di DbContext.OnConfiguring, atau jika Startup.cs Anda menggunakan 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));
}