Umgang mit Parallelitätskonflikten in Entity Framework

Die Parallelitätsbehandlung kann verwendet werden, um die Datenintegrität und Datenkonsistenz aufrechtzuerhalten, wenn mehrere Benutzer gleichzeitig auf dieselbe Ressource zugreifen. Parallelitätsverletzungen können auftreten, wenn Sie voneinander abhängige Transaktionen haben, dh Transaktionen, die voneinander abhängig sind und versuchen, auf dieselbe Ressource zuzugreifen.

Behandeln von Parallelitätskonflikten in Entity Framework

Lassen Sie uns nun verstehen, wie jede dieser Strategien in Entity Framework funktioniert. In der pessimistischen Parallelität werden beim Aktualisieren eines bestimmten Datensatzes alle anderen gleichzeitigen Aktualisierungen desselben Datensatzes angehalten, bis der aktuelle Vorgang abgeschlossen ist und die Steuerung zurückgegeben wird, damit andere gleichzeitige Vorgänge fortgesetzt werden können. Im optimistischen Parallelitätsmodus "gewinnt" der zuletzt gespeicherte Datensatz. In diesem Modus wird davon ausgegangen, dass Ressourcenkonflikte aufgrund gleichzeitiger Zugriffe auf eine gemeinsam genutzte Ressource unwahrscheinlich, aber nicht unmöglich sind.

Im Übrigen bietet Entity Framework standardmäßig Unterstützung für optimistische Parallelität. Entity Framework bietet keine sofort einsatzbereite Unterstützung für pessimistische Parallelität. Lassen Sie uns nun verstehen, wie Entity Framework Parallelitätskonflikte löst, wenn Sie in der optimistischen Parallelität arbeiten (Standardmodus).

Wenn Sie mit einem optimistischen Parallelitätsbehandlungsmodus arbeiten, möchten Sie normalerweise Daten in Ihrer Datenbank speichern, vorausgesetzt, die Daten haben sich seit dem Laden in den Speicher nicht geändert. Beachten Sie, dass beim Versuch, Änderungen an der Datenbank mithilfe der SaveChanges-Methode in Ihrer Datenkontextinstanz zu speichern, eine DbUpdateConcurrencyException ausgelöst wird. Lassen Sie uns nun verstehen, wie wir dies beheben können.

Um auf Parallelitätsverletzungen zu prüfen, können Sie ein Feld in Ihre Entitätsklasse aufnehmen und es mit dem Timestamp-Attribut markieren. Beziehen Sie sich auf die unten angegebene Entitätsklasse.

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

   }

Jetzt unterstützt Entity Framework zwei Parallelitätsmodi: Keine und Fest. Während Ersteres impliziert, dass beim Aktualisieren der Entität keine Parallelitätsprüfungen durchgeführt werden, impliziert Letzteres, dass der ursprüngliche Wert der Eigenschaft bei der Ausführung von WHERE-Klauseln zum Zeitpunkt der Aktualisierung oder Löschung von Daten berücksichtigt wird. Wenn Sie eine Eigenschaft haben, die mit Timestamp markiert ist, wird der Parallelitätsmodus als fest betrachtet, was wiederum impliziert, dass der ursprüngliche Wert der Eigenschaft in der WHERE-Klausel für Aktualisierungen oder Löschungen von Daten für diese bestimmte Entität berücksichtigt wird.

Um optimistische Parallelitätskonflikte zu lösen, können Sie die Reload-Methode verwenden, um die aktuellen Werte in Ihrer Entität im Speicher mit den neuesten Werten in der Datenbank zu aktualisieren. Nach dem erneuten Laden der aktualisierten Daten können Sie versuchen, Ihre Entität erneut in der Datenbank zu speichern. Das folgende Codefragment zeigt, wie dies erreicht werden kann.

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

         }

}

Beachten Sie, dass Sie die Entries-Methode für die DbUpdateConcurrencyException-Instanz verwenden können, um die Liste der DbEntityEntry-Instanzen abzurufen, die den Entitäten entsprechen, die nicht aktualisiert werden konnten, als eine SaveChanges-Methode aufgerufen wurde, um die Entitäten in der Datenbank beizubehalten.

Der soeben diskutierte Ansatz wird häufig als "gespeicherte Gewinne" oder "Datenbankgewinne" bezeichnet, da die in der Entität enthaltenen Daten durch die in der Datenbank verfügbaren Daten überschrieben werden. Sie können auch einen anderen Ansatz verfolgen, der als "Client Wins" bezeichnet wird. Bei dieser Strategie werden die Daten aus der Datenbank abgerufen, um die Entität zu füllen. Im Wesentlichen werden die aus der zugrunde liegenden Datenbank abgerufenen Daten als ursprüngliche Werte für die Entität festgelegt. Das folgende Codefragment zeigt, wie dies erreicht werden kann.

try

{

     dbContext.SaveChanges();

}

catch (DbUpdateConcurrencyException ex)

{

   var data = ex.Entries.Single();

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

}

Sie können auch überprüfen, ob die Entität, die Sie aktualisieren möchten, bereits von einem anderen Benutzer gelöscht wurde oder bereits von einem anderen Benutzer aktualisiert wurde. Das folgende Codefragment zeigt, wie Sie dies tun können.

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

   }

}

Wenn Ihre Datenbanktabelle keine Zeitstempelspalte oder Zeilenversion enthält, können Sie das ConcurrencyCheck-Attribut verwenden, um Parallelitätskonflikte bei Verwendung von Entity Framework zu erkennen. So wird diese Eigenschaft verwendet.

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

}

Dabei würde SQL Server automatisch AuthorName einschließen, wenn Aktualisierungs- oder Löschanweisungen in der Datenbank ausgeführt werden.