Kueri Pelacakan vs. Tanpa Pelacakan

Melacak kontrol perilaku jika Entity Framework Core menyimpan informasi tentang instans entitas di pelacak perubahannya. Jika entitas dilacak, setiap perubahan yang terdeteksi dalam entitas dipertahankan ke database selama SaveChanges. EF Core juga memperbaiki properti navigasi antara entitas dalam hasil kueri pelacakan dan entitas yang ada di pelacak perubahan.

Catatan

Jenis entitas tanpa kunci tidak pernah dilacak. Di mana pun artikel ini menyebutkan jenis entitas, artikel ini mengacu pada jenis entitas yang memiliki kunci yang ditentukan.

Tip

Anda dapat melihat contoh artikel ini di GitHub.

Kueri pelacakan

Secara default, kueri yang mengembalikan jenis entitas sedang dilacak. Kueri pelacakan berarti setiap perubahan pada instans entitas dipertahankan oleh SaveChanges. Dalam contoh berikut, perubahan pada peringkat blog terdeteksi dan bertahan pada database selama SaveChanges:

var blog = context.Blogs.SingleOrDefault(b => b.BlogId == 1);
blog.Rating = 5;
context.SaveChanges();

Ketika hasil dikembalikan dalam kueri pelacakan, EF Core memeriksa apakah entitas sudah dalam konteks. Jika EF Core menemukan entitas yang ada, maka instans yang sama dikembalikan, yang berpotensi menggunakan lebih sedikit memori dan lebih cepat daripada kueri tanpa pelacakan. EF Core tidak menimpa nilai properti entitas saat ini dan asli dalam entri dengan nilai database. Jika entitas tidak ditemukan dalam konteks, EF Core membuat instans entitas baru dan melampirkannya ke konteks. Hasil kueri tidak berisi entitas apa pun yang ditambahkan ke konteks tetapi belum disimpan ke database.

Kueri tanpa pelacakan

Kueri tanpa pelacakan berguna saat hasilnya digunakan dalam skenario baca-saja. Mereka umumnya lebih cepat untuk dijalankan karena tidak perlu menyiapkan informasi pelacakan perubahan. Jika entitas yang diambil dari database tidak perlu diperbarui, maka kueri tanpa pelacakan harus digunakan. Kueri individual dapat diatur menjadi tanpa pelacakan. Kueri tanpa pelacakan juga memberikan hasil berdasarkan apa yang ada dalam database yang mengacuhkan perubahan lokal atau entitas tambahan.

var blogs = context.Blogs
    .AsNoTracking()
    .ToList();

Perilaku pelacakan default dapat diubah pada tingkat instans konteks:

context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;

var blogs = context.Blogs.ToList();

Bagian berikutnya menjelaskan kapan kueri tanpa pelacakan mungkin kurang efisien daripada kueri pelacakan.

Resolusi identitas

Karena kueri pelacakan menggunakan pelacak perubahan, EF Core melakukan resolusi identitas dalam kueri pelacakan. Saat mewujudkan entitas, EF Core mengembalikan instans entitas yang sama dari pelacak perubahan jika sudah dilacak. Jika hasilnya berisi entitas yang sama beberapa kali, instans yang sama dikembalikan untuk setiap kemunculan. Kueri tanpa pelacakan:

  • Jangan gunakan pelacak perubahan dan jangan lakukan resolusi identitas.
  • Mengembalikan instans baru entitas bahkan ketika entitas yang sama terkandung dalam hasil beberapa kali.

Pelacakan dan tanpa pelacakan dapat digabungkan dalam kueri yang sama. Artinya, Anda dapat memiliki kueri tanpa pelacakan, yang melakukan resolusi identitas dalam hasil. Sama seperti AsNoTracking operator yang dapat dikueri, kami telah menambahkan operator AsNoTrackingWithIdentityResolution<TEntity>(IQueryable<TEntity>)lain . Ada juga entri terkait yang ditambahkan dalam QueryTrackingBehavior enum. Saat kueri untuk menggunakan resolusi identitas dikonfigurasi tanpa pelacakan, pelacak perubahan yang berdiri sendiri digunakan di latar belakang saat menghasilkan hasil kueri sehingga setiap instans hanya diwujudkan sekali. Karena pelacak perubahan ini berbeda dari yang ada dalam konteks, hasilnya tidak dilacak oleh konteks. Setelah kueri dijumlahkan sepenuhnya, pelacak perubahan keluar dari cakupan dan sampah yang dikumpulkan sesuai kebutuhan.

var blogs = context.Blogs
    .AsNoTrackingWithIdentityResolution()
    .ToList();

Mengonfigurasi perilaku pelacakan default

Jika Anda menemukan diri Anda mengubah perilaku pelacakan untuk banyak kueri, Anda mungkin ingin mengubah default sebagai gantinya:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder
        .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFQuerying.Tracking;Trusted_Connection=True")
        .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
}

Ini membuat semua kueri Anda tidak melacak secara default. Anda masih dapat menambahkan AsTracking untuk membuat pelacakan kueri tertentu.

Pelacakan dan proyeksi kustom

Bahkan jika jenis hasil kueri bukan jenis entitas, EF Core masih akan melacak jenis entitas yang terkandung dalam hasil secara default. Dalam kueri berikut, yang mengembalikan jenis anonim, instans dalam tataan Blog hasil akan dilacak.

var blog = context.Blogs
    .Select(
        b =>
            new { Blog = b, PostCount = b.Posts.Count() });

Jika kumpulan hasil berisi jenis entitas yang keluar dari komposisi LINQ, EF Core akan melacaknya.

var blog = context.Blogs
    .Select(
        b =>
            new { Blog = b, Post = b.Posts.OrderBy(p => p.Rating).LastOrDefault() });

Jika kumpulan hasil tidak berisi jenis entitas apa pun, maka tidak ada pelacakan yang dilakukan. Dalam kueri berikut, kami mengembalikan jenis anonim dengan beberapa nilai dari entitas (tetapi tidak ada instans dari jenis entitas aktual). Tidak ada entitas terlacak yang keluar dari kueri.

var blog = context.Blogs
    .Select(
        b =>
            new { Id = b.BlogId, b.Url });

EF Core mendukung melakukan evaluasi klien dalam proyeksi tingkat atas. Jika EF Core mewujudkan instans entitas untuk evaluasi klien, EF Core akan dilacak. Di sini, karena kami meneruskan blog entitas ke metode StandardizeURLklien, EF Core juga akan melacak instans blog.

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;
}

EF Core tidak melacak instans entitas tanpa kunci yang terkandung dalam hasilnya. Tetapi EF Core melacak semua instans jenis entitas lainnya dengan kunci sesuai dengan aturan di atas.

Versi sebelumnya

Sebelum versi 3.0, EF Core memiliki beberapa perbedaan dalam cara pelacakan dilakukan. Perbedaan penting adalah sebagai berikut:

  • Seperti yang dijelaskan di halaman Evaluasi Klien vs Server, evaluasi klien yang didukung EF Core di bagian mana pun dari kueri sebelum versi 3.0. Evaluasi klien menyebabkan materialisasi entitas, yang bukan bagian dari hasilnya. Jadi EF Core menganalisis hasilnya untuk mendeteksi apa yang harus dilacak. Desain ini memiliki perbedaan tertentu sebagai berikut:

    • Evaluasi klien dalam proyeksi, yang menyebabkan materialisasi tetapi tidak mengembalikan instans entitas materialisasi tidak dilacak. Contoh berikut tidak melacak blog entitas.

      var blogs = context.Blogs
          .OrderByDescending(blog => blog.Rating)
          .Select(
              blog => new { Id = blog.BlogId, Url = StandardizeUrl(blog) })
          .ToList();
      
    • EF Core tidak melacak objek yang keluar dari komposisi LINQ dalam kasus tertentu. Contoh berikut tidak melacak Post.

      var blog = context.Blogs
          .Select(
              b =>
                  new { Blog = b, Post = b.Posts.OrderBy(p => p.Rating).LastOrDefault() });
      
  • Setiap kali hasil kueri berisi jenis entitas tanpa kunci, seluruh kueri dibuat sebagai non-pelacakan. Itu berarti bahwa jenis entitas dengan kunci, yang dalam hasilnya juga tidak dilacak.

  • EF Core digunakan untuk melakukan resolusi identitas dalam kueri tanpa pelacakan. Ini menggunakan referensi yang lemah untuk melacak entitas yang telah dikembalikan. Jadi, jika kumpulan hasil berisi beberapa kali entitas yang sama, Anda akan mendapatkan instans yang sama untuk setiap kemunculan. Meskipun jika hasil sebelumnya dengan identitas yang sama keluar dari cakupan dan mendapatkan sampah yang dikumpulkan, EF Core mengembalikan instans baru.