Obsługa konfliktów współbieżnościHandling Concurrency Conflicts

Uwaga

Ta strona dokumentów, jak współbieżność działa w programie EF Core i sposób obsługi konfliktów współbieżności w aplikacji.This page documents how concurrency works in EF Core and how to handle concurrency conflicts in your application. Zobacz tokeny współbieżności Aby uzyskać szczegółowe informacje na temat konfigurowania tokeny współbieżności w modelu.See Concurrency Tokens for details on how to configure concurrency tokens in your model.

Porada

Przykład użyty w tym artykule można zobaczyć w witrynie GitHub.You can view this article's sample on GitHub.

Baza danych współbieżności odnosi się do sytuacji, w których wiele procesów lub użytkownikom dostęp lub zmienić te same dane w bazie danych, w tym samym czasie.Database concurrency refers to situations in which multiple processes or users access or change the same data in a database at the same time. Kontrola współbieżności odwołuje się do określonych mechanizmów używane w celu zapewnienia spójności danych w obecności równoczesnych zmian.Concurrency control refers to specific mechanisms used to ensure data consistency in presence of concurrent changes.

Implementuje programu EF Core mechanizmu kontroli optymistycznej współbieżności, co oznacza, że umożliwi ona wiele procesów lub użytkownicy wprowadzać zmiany, niezależnie od siebie bez konieczności synchronizacji lub blokowania.EF Core implements optimistic concurrency control, meaning that it will let multiple processes or users make changes independently without the overhead of synchronization or locking. W sytuacji idealnej te zmiany nie kolidują ze sobą i w związku z tym będzie można pomyślnie.In the ideal situation, these changes will not interfere with each other and therefore will be able to succeed. W najgorszym przypadku wielkości liter dwa lub więcej procesów podejmie próbę zmiany powodujące konflikt, i tylko jeden z nich ma być pomyślnie wykonane.In the worst case scenario, two or more processes will attempt to make conflicting changes, and only one of them should succeed.

Jak działa Kontrola współbieżności w programie EF CoreHow concurrency control works in EF Core

Właściwości skonfigurowane tokeny współbieżności są używane do wdrożenia mechanizmu kontroli optymistycznej współbieżności: zawsze, gdy operacji update lub delete jest wykonywane podczas SaveChanges, wartość tokenu współbieżności w bazie danych jest porównywana oryginał wartość odczytu przez platformę EF Core.Properties configured as concurrency tokens are used to implement optimistic concurrency control: whenever an update or delete operation is performed during SaveChanges, the value of the concurrency token on the database is compared against the original value read by EF Core.

  • Jeśli wartości są zgodne, można wykonać operacji.If the values match, the operation can complete.
  • Jeśli wartości nie są zgodne, EF Core założono, że inny użytkownik wykonał operacji powodującej konflikt i przerywa bieżącej transakcji.If the values do not match, EF Core assumes that another user has performed a conflicting operation and aborts the current transaction.

Sytuacja, gdy inny użytkownik wykonał operację, która powoduje konflikt z bieżącej operacji jest znany jako konfliktów współbieżności.The situation when another user has performed an operation that conflicts with the current operation is known as concurrency conflict.

Dostawcy baz danych są odpowiedzialni za wdrażanie porównanie wartości tokenu współbieżności.Database providers are responsible for implementing the comparison of concurrency token values.

W relacyjnych baz danych programu EF Core obejmuje sprawdzenia wartości tokenu współbieżności w WHERE klauzuli dowolnego UPDATE lub DELETE instrukcji.On relational databases EF Core includes a check for the value of the concurrency token in the WHERE clause of any UPDATE or DELETE statements. Po wykonaniu instrukcji, programem EF Core odczytuje liczbę wierszy, które miały wpływ.After executing the statements, EF Core reads the number of rows that were affected.

Jeśli wpływają żadne wiersze nie został wykryty konflikt współbieżności i zgłasza wyjątek programu EF Core DbUpdateConcurrencyException.If no rows are affected, a concurrency conflict is detected, and EF Core throws DbUpdateConcurrencyException.

Na przykład firma Microsoft może być konieczne skonfigurowanie LastName na Person za tokenem współbieżności.For example, we may want to configure LastName on Person to be a concurrency token. Następnie żadnych operacji aktualizacji w osoba będzie zawierać wyboru współbieżność w WHERE klauzuli:Then any update operation on Person will include the concurrency check in the WHERE clause:

UPDATE [Person] SET [FirstName] = @p1
WHERE [PersonId] = @p0 AND [LastName] = @p2;

Rozwiązywanie konfliktów współbieżnościResolving concurrency conflicts

Kontynuując poprzedni przykład gdy jeden użytkownik próbuje zapisać pewne zmiany Person, ale już inny użytkownik zmienił LastName, a następnie zostanie zgłoszony wyjątek.Continuing with the previous example, if one user tries to save some changes to a Person, but another user has already changed the LastName, then an exception will be thrown.

W tym momencie aplikacja może po prostu informować użytkownika, że aktualizacja zakończyła się niepowodzeniem z powodu zmian powodujących konflikt i przejść.At this point, the application could simply inform the user that the update was not successful due to conflicting changes and move on. Jednak może być pożądane, aby monitować użytkownika, upewnij się, że ten rekord reprezentuje nadal tę samą osobę rzeczywiste i spróbuj ponownie wykonać operację.But it may be desirable to prompt the user to ensure this record still represents the same actual person and to retry the operation.

Ten proces jest przykładem Rozwiązywanie konfliktów współbieżności.This process is an example of resolving a concurrency conflict.

Rozwiązywanie konfliktów współbieżności obejmuje scalanie oczekujące zmiany z bieżącej DbContext z wartościami w bazie danych.Resolving a concurrency conflict involves merging the pending changes from the current DbContext with the values in the database. Scalony jakie wartości będą się różnić w zależności od aplikacji i zaleceniami dane wejściowe użytkownika.What values get merged will vary based on the application and may be directed by user input.

Istnieją trzy rodzaje wartości może pomóc rozwiązać konflikt współbieżności:There are three sets of values available to help resolve a concurrency conflict:

  • Bieżące wartości są wartościami, które aplikacja próby zapisu w bazie danych.Current values are the values that the application was attempting to write to the database.

  • Oryginalne wartości są wartościami, które zostały pierwotnie pobrany z bazy danych, zanim zmiany zostały wprowadzone.Original values are the values that were originally retrieved from the database, before any edits were made.

  • Bazy danych wartości wartości przechowywane w bazie danych.Database values are the values currently stored in the database.

Obsługa konfliktów współbieżności ogólne podejście jest:The general approach to handle a concurrency conflicts is:

  1. CATCH DbUpdateConcurrencyException podczas SaveChanges.Catch DbUpdateConcurrencyException during SaveChanges.
  2. Użyj DbUpdateConcurrencyException.Entries Aby przygotować nowy zestaw zmian dla obiektów, których to dotyczy.Use DbUpdateConcurrencyException.Entries to prepare a new set of changes for the affected entities.
  3. Odśwież oryginalne wartości parametru tokenu współbieżności do bieżącej wartości w bazie danych.Refresh the original values of the concurrency token to reflect the current values in the database.
  4. Ponów próbę wykonania procesu, dopóki nie występują żadne konflikty.Retry the process until no conflicts occur.

W poniższym przykładzie Person.FirstName i Person.LastName są skonfigurowane jako tokeny współbieżności.In the following example, Person.FirstName and Person.LastName are setup as concurrency tokens. Brak // TODO: komentarz w lokalizacji, gdzie obejmują określonej logiki aplikacji, aby wybrać wartość do zapisania.There is a // TODO: comment in the location where you include application specific logic to choose the value to be saved.

using (var context = new PersonContext())
{
    // Fetch a person from database and change phone number
    var person = context.People.Single(p => p.PersonId == 1);
    person.PhoneNumber = "555-555-5555";

    // Change the person's name in the database to simulate a concurrency conflict
    context.Database.ExecuteSqlCommand(
        "UPDATE dbo.People SET FirstName = 'Jane' WHERE PersonId = 1");

    var saved = false;
    while (!saved)
    {
        try
        {
            // Attempt to save changes to the database
            context.SaveChanges();
            saved = true;
        }
        catch (DbUpdateConcurrencyException ex)
        {
            foreach (var entry in ex.Entries)
            {
                if (entry.Entity is Person)
                {
                    var proposedValues = entry.CurrentValues;
                    var databaseValues = entry.GetDatabaseValues();

                    foreach (var property in proposedValues.Properties)
                    {
                        var proposedValue = proposedValues[property];
                        var databaseValue = databaseValues[property];

                        // TODO: decide which value should be written to database
                        // proposedValues[property] = <value to be saved>;
                    }

                    // Refresh original values to bypass next concurrency check
                    entry.OriginalValues.SetValues(databaseValues);
                }
                else
                {
                    throw new NotSupportedException(
                        "Don't know how to handle concurrency conflicts for "
                        + entry.Metadata.Name);
                }
            }
        }
    }
}