Майкрософт.EntityFrameworkCore.Исключение DbUpdateConcurrencyException: "Ожидается, что операция с базой данных повлияет на 1 строку(строки), но на самом деле повлияла на 2 строки(строки)

0

Вопрос

Я получил эту ошибку, как только я пытаюсь обновить таблицу с тем же значением (порядковый номер), мое условие-обновить, если поле фактической даты возврата равно нулю.

По какой-то причине это выглядит так, как будто запрос возвращает 2 строки, но на самом деле есть только одна. Я использую EF. Это и есть функция:

экран с ошибкой - печать

   public void updateStatus(int carNumber1, string acctualDate1)
    {
        DateTime accReturn = DateTime.Parse(acctualDate1);

        var orderCar1 =  db.CarRentalFields.FirstOrDefault(carNum =>
        (carNum.CarNumber == carNumber1 && carNum.ActualReturnDate == null));

            orderCar1.ActualReturnDate = accReturn  ;
             
                db.SaveChanges();

Ошибка возникает при попытке db.SaveChanges()

таблица из базы данных, номер автомобиля 1000 - печать экрана

Конструктор моделей.Изображение объекта

пожалуйста, дайте мне знать, как я могу решить эту проблему.

c# entity-framework linq sql-server
2021-11-23 20:34:34
2
0

проблема решена путем добавления нового столбца в таблицу car_rental_fields, столбца идентификатора, включающего идентификатор. как я понимаю отсюда и из Интернета, существует проблема со сложным пк. в моем решении идентификатор не является первичным ключом, но это делает логику linq для обновления правильного столбца. спасибо всем людям, которые участвовали в этом вопросе.

2021-11-26 20:37:27
0

Эта ошибка возникает, когда EF не может разрешить PK для вашей сущности. В большинстве случаев для простых сущностей соглашения EF могут определять PK, но в вашем случае вы используете составной ключ, поэтому его необходимо настроить. В зависимости от того, как вы сопоставляете свои сущности, вы можете сделать это либо в:

  • EDMX
  • в DbContext.Создание модели
  • используя EntityTypeConfiguration декларация
  • использование атрибутов внутри самой сущности

Поскольку мы не знаем, как настроены ваши сущности, вы можете проверить это как причину, используя подход атрибутов в вашей сущности в качестве теста. Если вы используете EDMX, классы сущностей будут сгенерированы, поэтому вы захотите заменить это конфигурацией в EDMX. (Не могу вам в этом помочь, потому что я не использую эти чертовы штуки :D )

У вас, вероятно, будет что-то вроде:

public class CarRentalFields
{
    [Column("start_day")]
    public DateTime StartDay { get; set; }
    [Column("return_date")]
    public DateTime ReturnDate { get; set; }
    [Column("user_id")]
    public int UserId { get; set; }
    [Column("car_number")]
    public DateTime CarNumber { get; set; }
    
    // ... more columns...
}

Возможно, у вас даже есть [Key] атрибут в одном из этих полей, например, порядковый номер. Если в сущности отображен PK, проблема заключается в том, что он недостаточно специфичен, чтобы однозначно идентифицировать строку. Когда EF переходит к обновлению одной сущности, он проверяет наличие и ожидает обновления только одной строки в таблице. Это приведет к тому, что будет затронуто более одной строки, поэтому это не удастся.

Добавьте атрибуты для [Key] с порядком столбцов, чтобы он распознавался как составной ключ.

public class CarRentalFields
{
    [Key, Column(Name="start_day", Order=1)]
    public DateTime StartDay { get; set; }
    [Key, Column(Name="return_date", Order=2)]
    public DateTime ReturnDate { get; set; }
    [Key, Column(Name="user_id", Order=3)]
    public int UserId { get; set; }
    [Key, Column(Name="car_number", Order=4)]
    public DateTime CarNumber { get; set; }
    
    // ... more columns...
}

При условии, что эти 4 столбца гарантированно являются уникальным ограничением для таблицы, EF будет удовлетворен, если при построении инструкции UPDATE SQL будет обновлена только одна строка.

Еще раз обратите внимание, что если это работает и вы используете EDMX, вам нужно будет просмотреть и изменить отображение EDMX, чтобы внести соответствующие изменения, поскольку этот класс сущностей может быть восстановлен, потеряв ваши дополнительные атрибуты. (Я полагаю, что сгенерированные классы сущностей из EDMX имеют заголовок комментария, предупреждающий вас о том, что это сгенерированный класс, так что это индикатор, за которым следует следить.)

Обновить: Мое основное подозрение в этом будет заключаться в том, что в таблице на самом деле не определен соответствующий PK, либо используется другая комбинация PK, либо, что более вероятно, нет PK, учитывая природу этих полей. EF может работать с таблицами, для которых не определен PK, но для этого требуется определение ключа, обеспечивающее уникальную идентификацию записей. Ошибка, которую вы видите, возникает, когда это определение ключа недостаточно уникально. (т. Е. Если вы обновляете car 1 и выбираете строку, которая имеет: car_number = 1, start_day = 2021-11-21, return_day = 2021-11-22, идентификатор пользователя = 0 Проблема в том, что в базе данных более одной строки содержит такую комбинацию. Если в базе данных, которую вы проверяете, не более одной совпадающей строки, то ваше приложение почти наверняка указывает на другую базу данных, чем вы проверяете.

Что вы можете сделать, чтобы убедиться в этом:

  1. получите строку подключения во время выполнения и посмотрите, соответствует ли она базе данных, которую вы проверяете:

Перед выполнением запроса добавьте следующее:

// EF6
var connectionString = db.Database.Connection.ConnectionString;
// EF Core 5
var connectionString = db.Database.GetConnectionString();
  1. Взгляните на данные, которые вы на самом деле запрашиваете:

.

var cars =  db.CarRentalFields.Where(carNum =>
    (carNum.CarNumber == carNumber1 && carNum.ActualReturnDate == null)).ToList();

Хотя этот запрос может возвращать только 1 запись, это не является причиной проблемы. Что вам нужно, так это номер, дата начала, дата возврата и идентификатор пользователя для этой записи:

var car =  db.CarRentalFields
    .Where(carNum => carNum.CarNumber == carNumber1 
        && carNum.ActualReturnDate == null)
    .Select(x => new 
    {
        x.CarNumber,
        x.StartDay,
        x.ReturnDate,
        x.UserId
    }).Single(); // Expect our 1 record here...
var cars = db.CarRentalFields
    .Where(x => x.CarNumber == car.CarNumber
        && x.StartDay == car.StartDay
        && x.ReturnDate == car.ReturnDate
        && x.UserId == car.UserId)
    .ToList(); // Get rows that match our returned Key fields.

Эти запросы выбирают предполагаемые значения PK для записи автомобиля, которую вы хотите обновить, затем выполняют поиск автомобилей для сопоставления записей с ожидаемыми ключевыми полями. Я бы поставил на то, что, хотя верхний запрос возвращает 1 запись, нижний запрос возвращает две строки, то есть, хотя только 1 запись имеет значение #null ActualReturnDate, ваш ключ недостаточно уникален для содержимого этой таблицы.

2021-11-26 22:57:48

я использую contex, вы видели мой экран печати конструктора моделей?
elirans

Да, хорошо, что используется модуль построения моделей OnModelCreating DbContext, поэтому ключ определяется. Следующее, что нужно проверить, - соответствуют ли эти столбцы ограничению уникальности PK /w в вашей соответствующей базе данных. Если нет, то этот ключ, возможно, потребуется расширить. Составных ключей следует избегать, насколько это возможно, так как они значительно усложняют настройку отношений. Вы также можете использовать профилировщик для захвата предлагаемого оператора обновления, а затем преобразовать его в простой ВЫБОР, чтобы увидеть, какие строки возвращаются. По какой-то причине возвращается несколько строк.
Steve Py

Еще одна вещь, которую необходимо проверить, - это то, попадает ли приложение во время выполнения в ту же базу данных, что и вы проверяете. Данные, которые вы проверяете, могут показаться достаточно уникальными, если база данных не применяет ограничение уникальности к этим столбцам, но база данных, на которую указывают во время выполнения, содержит повторяющиеся строки.
Steve Py

та же ошибка возникает при использовании вашего решения, нужно ли было также изменять мою функцию? @Стив Пай
elirans

Захватите сгенерированный SQL и запустите его в базе данных. Обычно я использую для этого профилировщик, поэтому для SQL Server и SSMS в разделе Инструменты\Профилировщик SQL. Запустите это в своей базе данных, а затем выполните свой запрос. Вы можете использовать точку останова в своем приложении непосредственно перед сохранением изменений, затем очистить выходные данные профилировщика перед возобновлением, чтобы устранить предыдущий шум и найти инструкцию UPDATE.
Steve Py

Кроме того, можете ли вы опубликовать выходные данные конструктора таблиц для своей таблицы? Есть ли в таблице фактический набор PK с этими 4 столбцами?
Steve Py

Я добавил к ответу выше, чтобы включить шаги для двойной проверки строки подключения, а также проверки наличия в данных повторяющихся значений ключей.
Steve Py

Я попробовал твое решение. первое, что выглядит так, как будто вы пропустили какое-то " = " в автомобилях. второе - когда я пытаюсь сделать обновление: автомобили.ActualReturnDate = acctualDate1; я получил ошибку cs1061.
elirans

На других языках

Эта страница на других языках

Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................