Невозможно удалить объект, которому принадлежит объект, в EntityFramework Core - PullRequest
1 голос
/ 08 мая 2019

У меня есть следующая сущность:

public class Employee
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public Address Address { get; set; }
}
public class Address
{
    public string City { get; set; }
    public string State { get; set; }
}

И используя свободный API, я настроил собственную сущность следующим образом:

 private void ConfigureEmployee(EntityTypeBuilder<Employee> builder)
{
    builder.OwnsOne(x => x.Address, w =>
    {
        w.Property(x => x.City).HasMaxLength(100);
        w.Property(x => x.State).HasMaxLength(100);
    });
}

А когда я пытаюсь удалить сущность Employee:

var employee = dbContext.Employees.AsNoTracking().FirstOrDefault();
dbContext.Entry(employee).State = EntityState.Deleted;
dbContext.SaveChanges();

Я получил следующее исключение:

Сущность типа «Сотрудник» делит таблицу «Сотрудники» с сущностями типа «Employee.Address # Address», но нет сущности этого типа с таким же значением ключа «{Id: 1ad382d7-4064- 49a3-87ee-633578175247} ', который был помечен как' Удаленный '.

Я пробовал указанный обходной путь Здесь , но он не работал.

Я использую EntityFrameworkCore v2.2.4

Ответы [ 2 ]

3 голосов
/ 08 мая 2019

Проблема, с которой вы сталкиваетесь, связана с тем, как вы загружаете объект.Когда вы делаете:

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

0 голосов
/ 08 мая 2019

Вы должны использовать каскадное удаление, как показано ниже:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Employee>()
        .HasOptional<Standard>(s => s.Address)
        .WithMany()
        .WillCascadeOnDelete(false);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...