วิธีจัดการความขัดแย้งพร้อมกันใน Entity Framework

การจัดการพร้อมกันสามารถใช้เพื่อรักษาความสมบูรณ์ของข้อมูลและความสอดคล้องของข้อมูลเมื่อผู้ใช้หลายคนเข้าถึงทรัพยากรเดียวกันพร้อมกัน การละเมิดพร้อมกันสามารถเกิดขึ้นได้เมื่อคุณมีธุรกรรมที่พึ่งพาซึ่งกันและกันนั่นคือธุรกรรมที่ต้องพึ่งพาซึ่งกันและกันและพยายามเข้าถึงทรัพยากรเดียวกัน

การจัดการความขัดแย้งพร้อมกันใน Entity Framework

ตอนนี้เรามาทำความเข้าใจว่าแต่ละกลยุทธ์เหล่านี้ทำงานอย่างไรใน Entity Framework ในภาวะพร้อมกันในแง่ร้ายเมื่อมีการอัปเดตเรกคอร์ดเฉพาะการอัปเดตพร้อมกันอื่น ๆ ทั้งหมดในเรกคอร์ดเดียวกันจะถูกพักไว้จนกว่าการดำเนินการปัจจุบันจะเสร็จสมบูรณ์และการควบคุมจะถูกยกเลิกกลับเพื่อให้การดำเนินการพร้อมกันอื่น ๆ สามารถดำเนินต่อไปได้ ในโหมดการเกิดพร้อมกันในแง่ดีบันทึกล่าสุดที่บันทึกไว้คือ "ชนะ" ในโหมดนี้สันนิษฐานว่าความขัดแย้งของทรัพยากรเนื่องจากการเข้าถึงทรัพยากรที่แชร์พร้อมกันไม่น่าจะเป็นไปได้ แต่ก็เป็นไปไม่ได้

อนึ่ง Entity Framework ให้การสนับสนุนสำหรับภาวะพร้อมกันในแง่ดีตามค่าเริ่มต้น Entity Framework ไม่ได้ให้การสนับสนุนสำหรับการใช้งานพร้อมกันในแง่ร้ายนอกกรอบ ตอนนี้เรามาทำความเข้าใจว่า Entity Framework แก้ไขความขัดแย้งพร้อมกันอย่างไรเมื่อทำงานในภาวะพร้อมกันในแง่ดี (โหมดเริ่มต้น)

เมื่อทำงานกับโหมดการจัดการพร้อมกันในแง่ดีโดยทั่วไปคุณจะต้องการบันทึกข้อมูลลงในฐานข้อมูลของคุณโดยสมมติว่าข้อมูลไม่ได้เปลี่ยนแปลงเนื่องจากถูกโหลดในหน่วยความจำ โปรดทราบว่าเมื่อคุณพยายามบันทึกการเปลี่ยนแปลงในฐานข้อมูลโดยใช้เมธอด SaveChanges บนอินสแตนซ์บริบทข้อมูลของคุณ DbUpdateConcurrencyException จะถูกโยนทิ้ง ตอนนี้เรามาทำความเข้าใจว่าเราจะแก้ไขปัญหานี้ได้อย่างไร

ในการตรวจสอบการละเมิดพร้อมกันคุณสามารถรวมฟิลด์ในคลาสเอนทิตีของคุณและทำเครื่องหมายโดยใช้แอตทริบิวต์การประทับเวลา อ้างถึงคลาสเอนทิตีที่ระบุด้านล่าง

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

   }

ตอนนี้ Entity Framework รองรับโหมดการทำงานพร้อมกันสองโหมด: ไม่มีและคงที่ แม้ว่าในอดีตจะบอกเป็นนัยว่าจะไม่มีการตรวจสอบการทำงานพร้อมกันเมื่ออัปเดตเอนทิตี แต่ประการหลังนี้หมายความว่าค่าดั้งเดิมของคุณสมบัติจะได้รับการพิจารณาในขณะที่เรียกใช้คำสั่ง WHERE ในเวลาที่มีการอัปเดตหรือลบข้อมูล หากคุณมีคุณสมบัติที่ถูกทำเครื่องหมายโดยใช้ Timestamp โหมดการทำงานพร้อมกันจะถือว่าเป็นแบบคงที่ซึ่งหมายความว่าค่าดั้งเดิมของคุณสมบัติจะได้รับการพิจารณาในส่วนคำสั่ง WHERE ของการอัปเดตหรือการลบข้อมูลสำหรับเอนทิตีนั้น ๆ

ในการแก้ไขความขัดแย้งในแง่ดีพร้อมกันคุณสามารถใช้ประโยชน์จากวิธีการโหลดซ้ำเพื่ออัปเดตค่าปัจจุบันในเอนทิตีของคุณที่อยู่ในหน่วยความจำด้วยค่าล่าสุดในฐานข้อมูล เมื่อโหลดข้อมูลที่อัปเดตใหม่แล้วคุณสามารถพยายามที่จะคงเอนทิตีของคุณอีกครั้งในฐานข้อมูล ข้อมูลโค้ดต่อไปนี้แสดงให้เห็นว่าสามารถทำได้อย่างไร

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();

         }

}

โปรดทราบว่าคุณสามารถใช้ประโยชน์จากเมธอด Entries บนอินสแตนซ์ DbUpdateConcurrencyException เพื่อดึงรายการของอินสแตนซ์ DbEntityEntry ที่สอดคล้องกับเอนทิตีที่ไม่สามารถอัพเดตได้เมื่อมีการเรียกเมธอด SaveChanges เพื่อคงเอนทิตีไปยังฐานข้อมูล

ตอนนี้แนวทางที่เราเพิ่งพูดถึงมักเรียกว่า "เก็บชัยชนะ" หรือ "ฐานข้อมูลชนะ" เนื่องจากข้อมูลที่มีอยู่ในเอนทิตีจะถูกเขียนทับโดยข้อมูลที่มีอยู่ในฐานข้อมูล คุณยังสามารถทำตามแนวทางอื่นที่เรียกว่า "client ชนะ" ในกลยุทธ์นี้ข้อมูลจากฐานข้อมูลจะถูกดึงมาเพื่อเติมข้อมูลเอนทิตี โดยพื้นฐานแล้วข้อมูลที่ดึงมาจากฐานข้อมูลพื้นฐานถูกตั้งค่าเป็นค่าดั้งเดิมสำหรับเอนทิตี ข้อมูลโค้ดต่อไปนี้แสดงให้เห็นว่าสามารถทำได้อย่างไร

try

{

     dbContext.SaveChanges();

}

catch (DbUpdateConcurrencyException ex)

{

   var data = ex.Entries.Single();

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

}

นอกจากนี้คุณยังตรวจสอบได้ด้วยว่าเอนทิตีที่คุณพยายามอัปเดตนั้นถูกลบโดยผู้ใช้รายอื่นหรือผู้ใช้รายอื่นได้รับการอัปเดตแล้ว ข้อมูลโค้ดต่อไปนี้แสดงให้เห็นว่าคุณสามารถทำสิ่งนี้ได้อย่างไร

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...");

   }

}

ถ้าตารางฐานข้อมูลของคุณไม่มีคอลัมน์การประทับเวลาหรือการเปลี่ยนแถวคุณสามารถใช้ประโยชน์จากแอ็ตทริบิวต์ ConcurrencyCheck เพื่อตรวจจับความขัดแย้งพร้อมกันเมื่อใช้ Entity Framework นี่คือวิธีใช้คุณสมบัตินี้

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

}

ในการดำเนินการ SQL Server จะรวม AuthorName โดยอัตโนมัติเมื่อดำเนินการอัพเดตหรือลบคำสั่งในฐานข้อมูล