Datenzugriffskonflikte bei Entity Framework Core 20.07.2017, 00:00 Uhr

Datenzugriffskonflikte bei Entity Framework Core: Der Schlichter

Es gibt mehrere Lösungen, um Laufzeitfehler bei Änderungskonflikten zu vermeiden.
In der letzten Ausgabe dieser Kolumne ging es darum, Entity Framework (EF) Core so einzustellen, dass es Konflikte bei Datenänderungen durch verschiedene Prozesse erkennt. Das Erkennen ist nur der eine Teil, danach muss eine Anwendung mit einem solchen Konflikt auch noch zum Wohle des Anwenders umgehen [1].
Listing 1 (Teil 1): Konflikt erkennen und lösen mit Entity Framework Core
public static void EF_Konflikt_BeiFlug()

{

  CUI.MainHeadline(nameof(EF_Konflikt_BeiFlug));

  Console.WriteLine("Prozess.ID=" + System.Diagnostics.Process.GetCurrentProcess().Id);

  Console.Title = nameof(EF_Konflikt_BeiFlug) + ": Prozess-ID=" + System.Diagnostics.Process.GetCurrentProcess().Id;

  int flugNr = 151;



  // Kontext instanzieren

  using (WWWingsContext ctx = new WWWingsContext())

  {

    // --- Flug laden

    Flug flug = ctx.FlugSet.SingleOrDefault(x => x.FlugNr == flugNr);

    Console.WriteLine(DateTime.Now.ToLongTimeString() + ": Freie Plätze VORHER: " + flug.FreiePlaetze);



    short zuBuchendePlaetze = 0;

    string eingabe = "";

    do

    {

      Console.WriteLine("Wieviele Plätze?");

      eingabe = Console.ReadLine(); // Warten (zum Starten eines zweiten Prozesses!)

    } while (!short.TryParse(eingabe, out zuBuchendePlaetze));



    // --- Änderung

    flug.FreiePlaetze -= zuBuchendePlaetze;

    Console.WriteLine(DateTime.Now.ToLongTimeString() + ": Freie Plätze NEU: " + flug.FreiePlaetze);



    try

    {

      // --- Speicherversuch

      ITVisions.EFCore.EFC_Util.PrintChangedProperties(ctx.Entry(flug));

      var anz = ctx.SaveChanges();

      Console.WriteLine("SaveChanges: Gespeicherte Änderungen: " + anz);

    }

    catch (DbUpdateConcurrencyException ex)

    {

      Console.ForegroundColor = ConsoleColor.Red;

      CUI.PrintError(DateTime.Now.ToLongTimeString() + ": Fehler: Ein anderer Benutzer hat bereits den Datensatz geändert!");



      CUI.Print("Konflikte bei folgenden Eigenschaften:");

      ITVisions.EFCore.EFC_Util.PrintChangedProperties(ex.Entries.Single());



      // --- Nachfrage beim Nutzer

      Console.WriteLine("Was möchten Sie tun?");

      Console.WriteLine("Taste 1: Werte des anderen Benutzer übernehmen");

      Console.WriteLine("Taste 2: Werte des anderen Benutzer überschreiben");

      Console.WriteLine("Taste 3: Werte für ‚FreiePlaetze‘ verrechnen");



      ConsoleKeyInfo key = Console.ReadKey();

      switch(key.Key)

      {

        case ConsoleKey.D1: // Werte des anderen Nutzers übernehmen

        {

          Console.WriteLine("Sie haben gewählt: Option 1: übernehmen");

          ctx.Entry(flug).Reload();

          break;

        }

        case ConsoleKey.D2: // Werte des anderen Nutzers überschreiben

        {

          Console.WriteLine("Sie haben gewählt: Option 2: überschreiben");

          // Werte des anderen Nutzers überschreiben

          ctx.Entry(flug).OriginalValues.SetValues(ctx.Entry(flug).GetDatabaseValues());

          // wie RefreshMode.ClientWins bei ObjectContext

          ITVisions.EFCore.EFC_Util.PrintChangeInfo(ctx);

          int anz = ctx.SaveChanges();

          Console.WriteLine("SaveChanges: Gespeicherte Änderungen: " + anz);

          break;

        }

        case ConsoleKey.D3: // Werte des anderen Benutzers überschreiben

        {



          Console.WriteLine("Sie haben gewählt: Option 3: verrechnen");

          var freiePlaetzeOrginal = ctx.Entry(flug).OriginalValues.GetValue<short?>("FreiePlaetze");

          var freiePlaetzeNun = flug.FreiePlaetze.Value;

          var freiePlaetzeInDB = ctx.Entry(flug).GetDatabaseValues().GetValue<short?>("FreiePlaetze");

          flug.FreiePlaetze = (short) (freiePlaetzeOrginal - (freiePlaetzeOrginal - freiePlaetzeNun) - (freiePlaetzeOrginal - freiePlaetzeInDB));

          ITVisions.EFCore.EFC_Util.PrintChangeInfo(ctx);

          ctx.Entry(flug).OriginalValues.SetValues(ctx.Entry(flug).GetDatabaseValues());

          int anz = ctx.SaveChanges();

          Console.WriteLine("SaveChanges: Gespeicherte Änderungen: " + anz);

          break;

        }

      }

    }

    Console.WriteLine(DateTime.Now.ToLongTimeString() + ": Freie Plätze NACHHER: " + flug.FreiePlaetze);



    // --- Gegenprobe des nun gültigen Zustandes

    using (WWWingsContext ctx2 = new WWWingsContext())

    {

      var f = ctx.FlugSet.Where(x => x.FlugNr == flugNr).SingleOrDefault();

      Console.WriteLine(DateTime.Now.ToLongTimeString() + ": Freie Plätze GEGENPROBE: " + f.FreiePlaetze);



    } // Ende using-Block -> Dispose() wird aufgerufen

  }

}

Diesen Artikel lesen Sie exklusiv als dotnetproPlus Abonnent

Sie wollen zukünftig auch von den Vorteilen eines plus-Abos profitieren? Werden Sie jetzt dotnetpro-plus-Kunde
  • 2 Monate Gratis testen
  • Über 4.000 qualifizierte Fachartikel
  • Auf jedem Gerät verfügbar