При работе с EF и ссылками (DriverQualification -> Qualification) используйте ссылки, а не FK.Фактически, я вообще советую не добавлять FK к сущностям, а использовать теневые свойства (EF Core) или .Map()
в конфигурации сущностей, чтобы избежать их доступности.Проблема, с которой вы сталкиваетесь, заключается в том, что EF по-прежнему отслеживает сущности DriverQualification, которые ссылаются на определенную квалификацию, поэтому установка нулевой квалификации и обновление FK на самом деле не работает.
Итак, вы возвращаете драйвер,хочу загрузить эту сущность драйвера заново и обновить их квалификацию на основе переданного драйвера.
Предполагая, что переданный драйвер поступил от клиента (веб-приложения и т. д.) и был изменен, мы не можем "доверять ему или ссылочным данным, поэтому хорошо, что вы загружаете его свежим, а не повторно присоединяете его к контексту.
edit: Я рекомендую использовать ViewModel, а не передаватьсущность, даже если вы не собираетесь доверять ей.Основной риск передачи сущности заключается в том, что может возникнуть соблазн повторно присоединить / использовать ее или ссылочные сущности при обновлении.Мне пришлось перепроверить этот ответ, потому что я думал, что нарушил это правило при получении обновленных квалификаций!:) Передача графов сущностей в клиентский браузер, например, также предоставляет больше информации о вашем домене, чем вы должны.Даже если вы не отображаете различные столбцы / fks / справочные данные, клиенты могут просматривать эти данные с помощью инструментов отладки.Это также больше данных по проводам, чем может потребоваться.Automapper может сделать транспонирование объектов для просмотра моделей одним щелчком и также работает с IQueryable
.(ProjectTo
). / edit
Я переименовал некоторые переменные для ясности .. (т.е. val => updatedDriver)
using (var context = new COMP1690Entities())
{
var updatedQualificationIds = updatedDriver.DriverQualifications.Select(dq => dq.Qualification.Id).ToList();
// Get the updated qualification entities from the DB.
var updatedQualifications = context.Qualifications.Where(q => updatedQualificationIds.Contains(q.Id)).ToList();
var driver = context.Drivers.Where(d => d.Id == updatedDriver.Id)
.Include(d => d.DriverQualifications)
.Include("DriverQualifications.Qualification").Single();
var driverQualificationsToRemove = driver.DriverQualifications
.Where(dq => !updatedQualificationIds.Contains(udq.Qualification.Id));
foreach(var driverQualification in driverQualificationsToRemove)
driver.DriverQualifications.Remove(driverQualification);
var driverQualificationsToAdd = updatedDriverQualifications
.Except(driver.DriverQualifications.Select(dq => dq.Qualification),
new LamdaComparer((q1,q2) => q1.Id == q2.Id))
.Select(q => new DriverQualification { Qualification = q })
.ToList();
driver.DriverQualifications.AddRange(driverQualificationsToAdd);
driver.PhoneNumber = updatedDriver.PhoneNumber;
context.SaveChanges();
}
Это предполагает, что мы хотим удалить квалификациюассоциации, которые больше не связаны с водителем, и добавить новые квалификации, которые еще не связаны.(оставляя без изменений квалификацию.)
LamdaComparer, который вы можете найти здесь
В основном, чтобы избежать проблем со ссылками / ключами, придерживайтесь обновлений ссылок и полностью игнорируйте FK.Для сущностей / контекстов, где мне нужно сделать много «сырых» обновлений, я объявлю только FK и воздержусь от добавления ссылок на производительность.