Cara menangani konflik konkurensi dalam Entity Framework

Penanganan konkurensi dapat digunakan untuk menjaga integritas data dan konsistensi data saat beberapa pengguna mengakses sumber daya yang sama secara bersamaan. Pelanggaran konkurensi dapat terjadi ketika Anda memiliki transaksi yang saling bergantung, yaitu transaksi yang bergantung satu sama lain dan mencoba mengakses sumber daya yang sama.

Menangani konflik konkurensi dalam Entity Framework

Sekarang mari kita pahami bagaimana masing-masing strategi ini bekerja dalam Entity Framework. Dalam konkurensi pesimistis, saat rekaman tertentu sedang diperbarui, semua pembaruan serentak lainnya pada rekaman yang sama akan ditunda hingga operasi saat ini selesai dan kontrol dilepaskan kembali sehingga operasi bersamaan lainnya dapat dilanjutkan. Dalam mode konkurensi optimis, rekaman terakhir yang disimpan, "menang". Dalam mode ini, diasumsikan bahwa konflik sumber daya karena akses bersamaan ke sumber daya bersama tidak mungkin terjadi, tetapi, bukan tidak mungkin.

Secara kebetulan, Entity Framework menyediakan dukungan untuk konkurensi optimis secara default. Entity Framework tidak memberikan dukungan untuk konkurensi pesimistis. Sekarang mari kita pahami bagaimana Entity Framework menyelesaikan konflik konkurensi saat bekerja dalam konkurensi optimis (mode default).

Saat bekerja dengan mode penanganan konkurensi yang optimis, Anda biasanya ingin menyimpan data ke database Anda dengan asumsi bahwa data tidak berubah sejak dimuat di memori. Perhatikan bahwa ketika Anda mencoba untuk menyimpan perubahan ke database menggunakan metode SaveChanges pada contoh konteks data Anda, DbUpdateConcurrencyException akan dilempar. Sekarang mari kita pahami bagaimana kita bisa memperbaikinya.

Untuk memeriksa pelanggaran konkurensi, Anda dapat menyertakan kolom di kelas entitas Anda dan menandainya menggunakan atribut Timestamp. Lihat kelas entitas yang diberikan di bawah ini.

public class Author

   {

       public Int32 Id { get; set; }

       public string FirstName { get; set; }

       public string LastName { get; set; }

       public string Address { get; set; }

       [Timestamp]

       public byte[] RowVersion { get; set; }

   }

Sekarang, Entity Framework mendukung dua mode konkurensi: Tidak Ada dan Tetap. Sementara yang pertama menyiratkan bahwa tidak ada pemeriksaan konkurensi yang akan dilakukan saat memperbarui entitas, yang terakhir menyiratkan bahwa nilai asli properti akan dipertimbangkan saat menjalankan klausa WHERE pada saat pembaruan atau penghapusan data dilakukan. Jika Anda memiliki properti yang ditandai menggunakan Stempel Waktu, mode konkurensi dianggap sebagai Tetap yang pada gilirannya menyiratkan bahwa nilai asli properti akan dipertimbangkan dalam klausul WHERE dari setiap pembaruan atau penghapusan data untuk entitas tertentu itu.

Untuk mengatasi konflik konkurensi optimis, Anda dapat memanfaatkan metode Muat Ulang untuk memperbarui nilai saat ini di entitas Anda yang berada di memori dengan nilai terbaru dalam database. Setelah dimuat ulang dengan data yang diperbarui, Anda dapat mencoba mempertahankan entitas Anda lagi di database. Potongan kode berikut menggambarkan bagaimana hal ini dapat dicapai.

using (var dbContext = new IDBDataContext())

{

     Author author = dbContext.Authors.Find(12);

     author.Address = "Hyderabad, Telengana, INDIA";

       try

         {

             dbContext.SaveChanges();

         }

         catch (DbUpdateConcurrencyException ex)

         {

             ex.Entries.Single().Reload();

             dbContext.SaveChanges();

         }

}

Perhatikan bahwa Anda dapat memanfaatkan metode Entri pada contoh DbUpdateConcurrencyException untuk mengambil daftar contoh DbEntityEntry yang sesuai dengan entitas yang tidak dapat diperbarui ketika metode SaveChanges dipanggil untuk mempertahankan entitas ke database.

Sekarang, pendekatan yang baru saja kita diskusikan sering disebut "kemenangan yang disimpan" atau "kemenangan database" karena data yang terdapat dalam entitas ditimpa oleh data yang tersedia di database. Anda juga dapat mengikuti pendekatan lain yang disebut "kemenangan klien". Dalam strategi ini, data dari database diambil untuk mengisi entitas. Intinya, data yang diambil dari database yang mendasarinya ditetapkan sebagai nilai asli entitas. Potongan kode berikut menggambarkan bagaimana hal ini dapat dicapai.

try

{

     dbContext.SaveChanges();

}

catch (DbUpdateConcurrencyException ex)

{

   var data = ex.Entries.Single();

   data.OriginalValues.SetValues(data.GetDatabaseValues());

}

Anda juga dapat memeriksa apakah entitas yang Anda coba perbarui sudah dihapus oleh pengguna lain atau, telah diperbarui oleh pengguna lain. Cuplikan kode berikut menggambarkan bagaimana Anda dapat melakukan ini.

catch (DbUpdateConcurrencyException ex)

{

   var entity = ex.Entries.Single().GetDatabaseValues();

   if (entity == null)

   {

         Console.WriteLine("The entity being updated is already deleted by another user...");

   }

   else

   {

         Console.WriteLine("The entity being updated has already been updated by another user...");

   }

}

Jika tabel database Anda tidak memiliki kolom stempel waktu atau rowversion, Anda dapat memanfaatkan atribut ConcurrencyCheck untuk mendeteksi konflik konkurensi saat menggunakan Entity Framework. Begini cara properti ini digunakan.

[Table("Authors"]

public class Author

{

   public Author() {}

   [Key]

   public int Id { get; set; }

   [ConcurrencyCheck]

   public string FirstName { get; set; }

   public string LastName { get; set; }

   public string Address { get; set; }

}

Dalam melakukan, SQL Server akan secara otomatis menyertakan AuthorName saat menjalankan pembaruan atau menghapus pernyataan dalam database.