Проблема, с которой вы сталкиваетесь, связана с тем, как вы загружаете объект.Когда вы делаете:
var employee = dbContext.Employees.AsNoTracking().FirstOrDefault();
Вы в основном говорите EF: загрузите это Employee
для меня, но забудьте об этом.Обращайтесь с ним так, как если бы вы его никогда не загружали.
Далее вы хотите удалить его.Вы знаете, что он не отслеживается DbContext
, поэтому вы делаете:
dbContext.Entry(employee).State = EntityState.Deleted;
Это «ключ» к проблеме.Эта строка сообщает DbContext
: Эй, пожалуйста, начните отслеживать эту сущность и отметьте ее как удаляемую.
Проблема: Субъект Employee
владеет адресом, но DbContext
не знает , что вы также хотите удалить его,
Сообщение об ошибке, которое вы получаете, дает глубокое понимание фактической ошибки, но на первый взгляд может быть не совсем понятно:
Объект типа «Сотрудник» делитсятаблица «Сотрудники» с сущностями типа «Employee.Address # Address», но нет сущности этого типа с таким же значением ключа «{Id: 1ad382d7-4064-49a3-87ee-633578175247}», который был помечен как'Удалено'.
Это говорит: сущность Employee
с идентификатором 4 помечена как Deleted
, но у нее также есть сущность типа Address
, которая не было добавлено для удаления .Хотя у вас Address
не объявлено как DbSet
в вашем контексте, это все еще фактическая сущность в отношении EF.
Чтобы исправить это, сохранив тот же код, что и у вас, вам также необходимо добавить Address
для удаления:
context.Entry(employee.Address).State = EntityState.Deleted;
Но:
Я не уверен, является ли это просто примером или это ваш настоящий код.Но я лично (и я вижу многих также против этого) стараюсь максимально избегать манипулирования состояниями сущностей вручную.Это может быстро привести к неприятным последствиям и привести к тому, что вы уже испытали не столь очевидные результаты.Вместо этого, если у вас есть DbContext
, в который вы загружаете сущность, которую хотите удалить, вы можете избежать путаницы с состояниями и проблемами, просто изменив свой код следующим образом:
var employee = dbContext.Employees.First();
// .Remove will also mark the related entities to be deleted
// If Employee is not tracked, it will also start tracking it
// So, it's not necessary to do .Attach()
dbContext.Remove(employee);
dbContext.SaveChanges();
Это будет работать, и сущностьбудут удалены, как и ожидалось.Конечно, если ваш код не такой, и вы, на самом деле, работаете с сущностями в отключенном сценарии, то вам нужно вручную настроить его на удаление, как я показал выше.
Редактировать:
Как указано в комментариях @IvanStoev, метод Remove
- это то, что действительно может исправить поведение, с которым вы сталкиваетесь.Метод Remove
помечает саму сущность плюс связанные с ней как Deleted
и, если она ранее не отслеживалась, также начнет их отслеживание.Из документов: (выделено мной)
Если объект уже отслеживается в состоянии «Добавлен», то контекст перестанет отслеживать объект (а не помечать его как «Удаленный»), поскольку объект был добавлен ранее.к контексту и не существует в базе данных.
Любые другие достижимые объекты, которые еще не отслеживаются, будут отслеживаться так же, как и в случае вызова Attach (Object) перед вызовом этого метода. Это позволяет применять любые каскадные действия при вызове SaveChanges ().
DbContext.Remove Method