Entity Framework - Parallelität

Jeder Datenzugriffsentwickler hat Schwierigkeiten bei der Beantwortung der Frage zur Datengleichzeitigkeit: "Was passiert, wenn mehr als eine Person dieselben Daten gleichzeitig bearbeitet?"

  • Die Glücklicheren unter uns beschäftigen sich mit Geschäftsregeln, die besagen: "Kein Problem, der letzte gewinnt."

  • In diesem Fall ist Parallelität kein Problem. Wahrscheinlicher ist es nicht so einfach und es gibt keine Silberkugel, um jedes Szenario auf einmal zu lösen.

  • Standardmäßig verwendet das Entity Framework den Pfad "Letzter Gewinn". Dies bedeutet, dass das neueste Update auch dann angewendet wird, wenn jemand anderes die Daten zwischen dem Abrufen der Daten und dem Speichern der Zeitdaten aktualisiert hat.

Nehmen wir ein Beispiel, um es besser zu verstehen. Im folgenden Beispiel wird eine neue Spalte VersionNo in der Kurstabelle hinzugefügt.

Gehen Sie zum Designer, klicken Sie mit der rechten Maustaste auf das Designerfenster und wählen Sie Modell aus Datenbank aktualisieren aus.

Sie werden sehen, dass eine weitere Spalte in der Kursentität hinzugefügt wird.

Klicken Sie mit der rechten Maustaste auf die neu erstellte Spalte VersionNo, wählen Sie Eigenschaften und ändern Sie den ConcurrencyMode in Fest, wie in der folgenden Abbildung dargestellt.

Wenn der ConcurrencyMode von Course.VersionNo auf Fixed gesetzt ist, sucht der Befehl Update bei jeder Aktualisierung eines Kurses mithilfe seines EntityKey und seiner VersionNo-Eigenschaft nach dem Kurs.

Schauen wir uns ein einfaches Szenario an. Zwei Benutzer rufen denselben Kurs zur gleichen Zeit ab, und Benutzer 1 ändert den Titel dieses Kurses in Mathematik und speichert Änderungen vor Benutzer 2. Später, wenn Benutzer 2 den Titel dieses Kurses ändert, der abgerufen wurde, bevor Benutzer 1 seine Änderungen darin speichert Fall Benutzer 2 erhält eine Parallelitätsausnahme"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");
            }
         }
      }
   }
}