Эта ошибка возникает, когда 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 Проблема в том, что в базе данных более одной строки содержит такую комбинацию. Если в базе данных, которую вы проверяете, не более одной совпадающей строки, то ваше приложение почти наверняка указывает на другую базу данных, чем вы проверяете.
Что вы можете сделать, чтобы убедиться в этом:
- получите строку подключения во время выполнения и посмотрите, соответствует ли она базе данных, которую вы проверяете:
Перед выполнением запроса добавьте следующее:
// EF6
var connectionString = db.Database.Connection.ConnectionString;
// EF Core 5
var connectionString = db.Database.GetConnectionString();
- Взгляните на данные, которые вы на самом деле запрашиваете:
.
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, ваш ключ недостаточно уникален для содержимого этой таблицы.