Entity Framework - ภาวะพร้อมกัน

นักพัฒนาด้านการเข้าถึงข้อมูลทุกคนประสบปัญหาในขณะที่ตอบคำถามเกี่ยวกับการทำงานพร้อมกันของข้อมูล "จะเกิดอะไรขึ้นถ้ามีคนมากกว่าหนึ่งคนแก้ไขข้อมูลเดียวกันในเวลาเดียวกัน"

  • ยิ่งโชคดีในหมู่พวกเราที่ต้องรับมือกับกฎทางธุรกิจที่บอกว่า“ ไม่มีปัญหาสุดท้ายก็ชนะ”

  • ในกรณีนี้การเกิดพร้อมกันไม่ใช่ปัญหา เป็นไปได้มากว่ามันไม่ง่ายอย่างนั้นและไม่มีกระสุนเงินที่จะแก้ปัญหาทุกสถานการณ์ในคราวเดียว

  • โดยค่าเริ่มต้น Entity Framework จะใช้เส้นทาง“ last one in wins” ซึ่งหมายความว่ามีการใช้การอัปเดตล่าสุดแม้ว่าจะมีผู้อื่นอัปเดตข้อมูลระหว่างเวลาที่ดึงข้อมูลและบันทึกข้อมูลเวลา

มาเป็นตัวอย่างให้เข้าใจกันดีกว่า ตัวอย่างต่อไปนี้จะเพิ่มคอลัมน์ใหม่ VersionNo ในตารางหลักสูตร

ไปที่นักออกแบบและคลิกขวาที่หน้าต่างนักออกแบบและเลือกรุ่นอัปเดตจากฐานข้อมูล ...

คุณจะเห็นว่ามีการเพิ่มคอลัมน์อื่นในเอนทิตีหลักสูตร

คลิกขวาที่คอลัมน์ที่สร้างขึ้นใหม่ VersionNo และเลือก Properties และเปลี่ยน ConcurrencyMode เป็น Fixed ดังที่แสดงในภาพต่อไปนี้

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

ลองมาดูสถานการณ์ง่ายๆ ผู้ใช้สองคนเรียกค้นหลักสูตรเดียวกันในเวลาเดียวกันและผู้ใช้ 1 เปลี่ยนชื่อวิชานั้นเป็นคณิตศาสตร์และบันทึกการเปลี่ยนแปลงก่อนผู้ใช้ 2 ในภายหลังเมื่อผู้ใช้ 2 เปลี่ยนชื่อของหลักสูตรนั้นซึ่งถูกดึงมาก่อนที่ผู้ใช้ 1 จะบันทึกการเปลี่ยนแปลง ผู้ใช้กรณีที่ 2 จะได้รับข้อยกเว้นการเกิดพร้อมกัน"User2: Optimistic Concurrency exception occured".

using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;

namespace DatabaseFirstDemo {

   class Program {

      static void Main(string[] args) {

         Course c1 = null;
         Course c2 = null;

         //User 1 gets Course

         using (var context = new UniContextEntities()) {
            context.Configuration.ProxyCreationEnabled = false;
            c1 = context.Courses.Where(s ⇒ s.CourseID == 1).Single();
         }

         //User 2 also get the same Course

         using (var context = new UniContextEntities()) {
            context.Configuration.ProxyCreationEnabled = false;
            c2 = context.Courses.Where(s ⇒ s.CourseID == 1).Single();
         }

         //User 1 updates Course Title
         c1.Title = "Edited from user1";

         //User 2 updates Course Title
         c2.Title = "Edited from user2";

         //User 1 saves changes first

         using (var context = new UniContextEntities()) {

            try {
               context.Entry(c1).State = EntityState.Modified;
               context.SaveChanges();
            } catch (DbUpdateConcurrencyException ex) {
               Console.WriteLine("User1: Optimistic Concurrency exception occurred");
            }
         }

         //User 2 saves changes after User 1.
         //User 2 will get concurrency exection
         //because CreateOrModifiedDate is different in the database

         using (var context = new UniContextEntities()) {

            try {
               context.Entry(c2).State = EntityState.Modified;
               context.SaveChanges();
            } catch (DbUpdateConcurrencyException ex) {
               Console.WriteLine("User2: Optimistic Concurrency exception occurred");
            }
         }
      }
   }
}