Bagikan melalui


Menyimpan Data

Saat mengkueri memungkinkan Anda membaca data dari database, menyimpan data berarti menambahkan entitas baru ke database, menghapus entitas, atau memodifikasi properti entitas yang ada dalam beberapa cara. Entity Framework Core (EF Core) mendukung dua pendekatan mendasar untuk menyimpan data ke database.

Pendekatan 1: pelacakan perubahan dan SaveChanges

Dalam banyak skenario, program Anda perlu mengkueri beberapa data dari database, melakukan beberapa modifikasi di dalamnya, dan menyimpan modifikasi tersebut kembali; ini kadang-kadang disebut sebagai "unit kerja". Misalnya, mari kita asumsikan bahwa Anda memiliki sekumpulan Blog, dan Anda ingin mengubah Url properti salah satunya. Di EF, ini biasanya dilakukan sebagai berikut:

using (var context = new BloggingContext())
{
    var blog = context.Blogs.Single(b => b.Url == "http://example.com");
    blog.Url = "http://example.com/blog";
    context.SaveChanges();
}

Kode di atas melakukan langkah-langkah berikut:

  1. Ini menggunakan kueri LINQ reguler untuk memuat entitas dari database (lihat Data kueri). Kueri EF dilacak secara default, yang berarti bahwa EF melacak entitas yang dimuat dalam pelacak perubahan internalnya.
  2. Instans entitas yang dimuat dimanipulasi seperti biasa, dengan menetapkan properti .NET. EF tidak terlibat dalam langkah ini.
  3. Akhirnya, DbContext.SaveChanges() dipanggil. Pada titik ini, EF secara otomatis mendeteksi perubahan apa pun dengan membandingkan entitas dengan rekam jepret sejak dimuat. Setiap perubahan yang terdeteksi dipertahankan ke database; saat menggunakan database relasional, ini biasanya melibatkan pengiriman misalnya SQL UPDATE untuk memperbarui baris yang relevan.

Perhatikan bahwa hal di atas menjelaskan operasi pembaruan umum untuk data yang ada, tetapi prinsip serupa berlaku untuk menambahkan dan menghapus entitas. Anda berinteraksi dengan pelacak perubahan EF dengan memanggil DbSet<TEntity>.Add dan Remove, menyebabkan perubahan dilacak. EF kemudian menerapkan semua perubahan terlacak pada database ketika SaveChanges() dipanggil (misalnya melalui SQL INSERT dan DELETE saat menggunakan database relasional).

SaveChanges() menawarkan keuntungan berikut:

  • Anda tidak perlu menulis kode untuk melacak entitas dan properti mana yang diubah - EF melakukan ini secara otomatis untuk Anda, dan hanya memperbarui properti tersebut dalam database, meningkatkan performa. Bayangkan jika entitas yang dimuat terikat ke komponen UI, memungkinkan pengguna untuk mengubah properti apa pun yang mereka inginkan; EF menghilangkan beban mencari tahu entitas dan properti mana yang benar-benar diubah.
  • Menyimpan perubahan pada database terkadang bisa rumit! Misalnya, jika Anda ingin menambahkan Blog dan beberapa Posting untuk blog tersebut, Anda mungkin perlu mengambil kunci yang dihasilkan database untuk Blog yang disisipkan sebelum Anda dapat menyisipkan Postingan (karena mereka perlu merujuk ke Blog). EF melakukan semua ini untuk Anda, menghilangkan kompleksitas.
  • EF dapat mendeteksi masalah konkurensi, seperti ketika baris database telah dimodifikasi oleh orang lain antara kueri Anda dan SaveChanges(). Detail selengkapnya tersedia dalam konflik Konkurensi.
  • Pada database yang mendukungnya, SaveChanges() secara otomatis membungkus beberapa perubahan dalam transaksi, memastikan data Anda tetap konsisten jika terjadi kegagalan. Detail selengkapnya tersedia dalam Transaksi.
  • SaveChanges() juga mengumpulkan beberapa perubahan dalam banyak kasus, secara signifikan mengurangi jumlah perjalanan pulang-pergi database dan sangat meningkatkan performa. Detail selengkapnya tersedia dalam Pembaruan efisien.

Untuk informasi selengkapnya dan sampel kode tentang penggunaan dasar SaveChanges() , lihat SaveChanges Dasar. Untuk informasi selengkapnya tentang pelacakan perubahan EF, lihat Gambaran umum pelacakan perubahan.

Pendekatan 2: ExecuteUpdate dan ExecuteDelete ("pembaruan massal")

Catatan

Fitur ini diperkenalkan dalam EF Core 7.0.

Meskipun pelacakan perubahan dan SaveChanges() merupakan cara yang ampuh untuk menyimpan perubahan, mereka memang memiliki kelemahan tertentu.

Pertama, SaveChanges() mengharuskan Anda mengkueri dan melacak semua entitas yang akan Anda ubah atau hapus. Jika perlu, katakanlah, hapus semua Blog dengan peringkat di bawah ambang batas tertentu, Anda harus mengkueri, mewujudkan, dan melacak jumlah baris yang DELETE berpotensi besar, dan telah SaveChanges() menghasilkan pernyataan untuk masing-masing dan setiap baris. Database relasional menyediakan alternatif yang jauh lebih efisien: satu DELETE perintah dapat dikirim, menentukan baris mana yang akan dihapus melalui WHERE klausul, tetapi SaveChanges() model tidak memungkinkan untuk menghasilkannya.

Untuk mendukung skenario "pembaruan massal" ini, Anda dapat menggunakan ExecuteDelete sebagai berikut:

context.Blogs.Where(b => b.Rating < 3).ExecuteDelete();

Ini memungkinkan Anda untuk mengekspresikan pernyataan SQL DELETE melalui operator LINQ reguler - mirip dengan kueri LINQ biasa - menyebabkan SQL berikut dijalankan terhadap database:

DELETE FROM [b]
FROM [Blogs] AS [b]
WHERE [b].[Rating] < 3

Ini dijalankan dengan sangat efisien dalam database, tanpa memuat data apa pun dari database atau melibatkan pelacak perubahan EF. Demikian pula, ExecuteUpdate memungkinkan Anda untuk mengekspresikan pernyataan SQL UPDATE .

Bahkan jika Anda tidak mengubah entitas secara massal, Anda mungkin tahu persis properti entitas mana yang ingin Anda ubah. Menggunakan API pelacakan perubahan untuk melakukan perubahan bisa terlalu kompleks, membutuhkan pembuatan instans entitas, melacaknya melalui Attach, membuat perubahan Anda dan akhirnya memanggil SaveChanges(). Untuk skenario seperti itu, ExecuteUpdate dan ExecuteDelete dapat menjadi cara yang jauh lebih sederhana untuk mengekspresikan operasi yang sama.

Akhirnya, pelacakan perubahan dan SaveChanges() sendiri memberlakukan overhead runtime tertentu. Jika Anda menulis aplikasi berkinerja tinggi, ExecuteUpdate dan ExecuteDelete memungkinkan Anda untuk menghindari komponen-komponen ini dan secara efisien menghasilkan pernyataan yang Anda inginkan.

Namun, perhatikan bahwa ExecuteUpdate dan ExecuteDelete juga memiliki batasan tertentu:

  • Metode ini segera dijalankan, dan saat ini tidak dapat di-batch dengan operasi lain. Di sisi lain, SaveChanges(), dapat mengumpulkan beberapa operasi bersama-sama.
  • Karena pelacakan perubahan tidak terlibat, Anda bertanggung jawab untuk mengetahui dengan tepat entitas dan properti mana yang perlu diubah. Ini mungkin berarti pelacakan kode tingkat rendah yang lebih manual yang perlu diubah dan apa yang tidak.
  • Selain itu, karena pelacakan perubahan tidak terlibat, metode ini tidak secara otomatis menerapkan Kontrol Konkurensi saat mempertahankan perubahan. Namun, Anda masih dapat secara eksplisit menambahkan Where klausul untuk menerapkan kontrol konkurensi sendiri.
  • Hanya memperbarui dan menghapus yang saat ini didukung; penyisipan harus dilakukan melalui DbSet<TEntity>.Add dan SaveChanges().

Untuk informasi selengkapnya dan sampel kode, lihat ExecuteUpdate dan ExecuteDelete.

Ringkasan

Berikut adalah beberapa panduan kapan harus menggunakan pendekatan mana. Perhatikan bahwa ini bukan aturan absolut, tetapi berikan aturan praktis yang berguna:

  • Jika Anda tidak tahu terlebih dahulu perubahan mana yang akan terjadi, gunakan SaveChanges; perubahan tersebut akan secara otomatis mendeteksi perubahan mana yang perlu diterapkan. Contoh skenario:
    • "Saya ingin memuat Blog dari database dan menampilkan formulir yang memungkinkan pengguna untuk mengubahnya"
  • Jika Anda perlu memanipulasi grafik objek (yaitu beberapa objek yang saling terhubung), gunakan SaveChanges; itu akan mencari tahu urutan perubahan yang tepat dan cara menautkan semuanya bersama-sama.
    • "Saya ingin memperbarui blog, mengubah beberapa postingannya dan menghapus yang lain"
  • Jika Anda ingin mengubah sejumlah besar entitas berdasarkan beberapa kriteria, gunakan ExecuteUpdate dan ExecuteDelete. Contoh skenario:
    • "Saya ingin memberi semua karyawan kenaikan gaji"
    • "Saya ingin menghapus semua blog yang namanya dimulai dengan X"
  • Jika Anda sudah tahu persis entitas mana yang ingin Anda ubah dan bagaimana Anda ingin mengubahnya, gunakan ExecuteUpdate dan ExecuteDelete. Contoh skenario:
    • "Saya ingin menghapus blog yang namanya 'Foo'"
    • "Saya ingin mengubah nama blog dengan Id 5 menjadi 'Bar'"