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

Uwaga

Ta strona dokumentów działania współbieżności EF Core i sposób obsługi konfliktom 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 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

Można wyświetlić w tym artykule próbki w witrynie GitHub.You can view this article's sample on GitHub.

Baza danych współbieżności odwołuje się do sytuacji, w których wiele procesów lub użytkowników dostęp lub zmienić tych samych danych 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. Formant współbieżności odwołuje się do określonych mechanizmy służące do 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 EF Core optymistyczne sterowanie współbieżnością, co oznacza, że umożliwi programowi wiele procesów lub użytkownicy wprowadzać zmiany niezależnie bez ponoszenia dodatkowych nakładów 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 tych zmian 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 scenariusz dwie 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 formant współbieżności w EF CoreHow concurrency control works in EF Core

Właściwości skonfigurowany jako tokeny współbieżności są używane do implementowania optymistyczne sterowanie współbieżnością: zawsze, gdy jest wykonywana operacja aktualizacji lub usuwania podczas SaveChanges, wartość tokenu współbieżności bazy danych zostaną porównane z oryginalną wartość odczytywane przez 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 przerwanie 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.

Sytuacji, gdy inny użytkownik wykonał operację, która powoduje konflikt z bieżącą operacją nosi nazwę konflikt 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 bazy danych są zobowiązani do wykonania porównania wartości tokenu współbieżności.Database providers are responsible for implementing the comparison of concurrency token values.

W relacyjnych baz danych EF Core obejmuje sprawdzenia wartości tokenu współbieżności w WHERE klauzuli dowolnego UPDATE lub DELETE instrukcje.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, EF Core odczytuje liczbę wierszy, które zostały zainfekowane.After executing the statements, EF Core reads the number of rows that were affected.

Jeśli dotyczy żadnych wierszy, został wykryty konflikt współbieżności i zgłasza 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 być tokenem współbieżności.For example, we may want to configure LastName on Person to be a concurrency token. Następnie żadnej operacji update na 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

Kontynuowanie poprzedni przykład, jeśli jeden użytkownik próbuje zapisać pewnych zmian Person, ale już inny użytkownik zmienił LastName zostanie wygenerowany 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 the an exception will be thrown.

W tym momencie aplikacja może po prostu poinformować użytkownika, że aktualizacja nie zakończyła się niepowodzeniem z powodu zmian powodujących konflikt i przenieść na.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 nadal reprezentuje sama osoba 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 konfliktu 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ących zmian z bieżącego 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. Jakie wartości scalony różni się zależnie od aplikacji i mogą być kierowane przez dane wejściowe użytkownika.What values get merged will vary based on the application and may be directed by user input.

Istnieją trzy zestawy 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 wartości próby zapisu w bazie danych aplikacji.Current values are the values that the application was attempting to write to the database.

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

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

Ogólne podejście do obsługi konfliktom współbieżności 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 do odpowiednich jednostek.Use DbUpdateConcurrencyException.Entries to prepare a new set of changes for the affected entities.
  3. Odśwież oryginalnych wartości 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ślonego logikę 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);
                }
            }
        }
    }
}