Ядро EF : сложный случай удаления (удаление нескольких строк по порядку)

#c# #sql #entity-framework-core #sql-delete

Вопрос:

У меня есть эта таблица с 4 объектами, которые иерархически происходят от типа сообщества, чтобы упростить вопрос, давайте назовем их: A, B, C, D .

Типы имеют следующие связи с внешними ключами:

  • B с одним A со многими B с A_id в качестве внешнего ключа.
  • C с одним B со многими C с B_id в качестве внешнего ключа.
  • D с одним C со многими D с C_id в качестве внешнего ключа.

Как удалить A, содержащий несколько B, которые содержат несколько C, а также с несколькими D, используя ядро EF?

Поскольку это в одной и той же таблице и все связи создают несколько каскадных путей, каскадное удаление не работает.

Я знаю , что это сработает, если я сначала удалю все буквы C, а затем позвоню SaveChanges , затем все буквы D и позвоню SaveChanges снова, и так далее .. заставляя меня 4 раза обращаться к базе данных для удаления.

Я попытался добавить в Context.Remove() по порядку удаления, сначала C и т. Д., А затем позвонить SaveChanges один раз, и это не сработало.

Я знаю, что если я создам SQL-запрос с удалениями, отсортированными сначала C, затем D и т. Д., Это сработает, но я хотел посмотреть, есть ли другой способ сделать это..

Добавление кода:

 EntityTypeBuilderlt;BaseModelgt; base= modelBuilder.Entitylt;BaseModelgt;();   base.ToTable("Models", BLSchema);   base.HasKey(k =gt; k.Id);    base.HasDiscriminatorlt;stringgt;(ModelConst.Type)   .HasValuelt;AModelgt;(TasksConst.TypesConst.A)  .HasValuelt;BModelgt;(TasksConst.TypesConst.B)  .HasValuelt;CModelgt;(TasksConst.TypesConst.C)  .HasValuelt;DModelgt;(TasksConst.TypesConst.D);    base.Property(p =gt; p.CreatedAt)  .HasDefaultValueSql("getdate()");  base.Property(p =gt; p.UpdatedAt)  .HasDefaultValueSql("getdate()");  EntityTypeBuilderlt;AModelgt; a= modelBuilder.Entitylt;AModelgt;();   a.HasIndex(x =gt; new { x.Name, x.ProjectId, x.Type })  .IsUnique()  .HasFilter($"[{ModelConst.Type}] = '{ModelConst.TypesConst.A}'");   a.HasMany(x =gt; x.Bs)  .WithOne(x =gt; x.A)  .HasForeignKey(f =gt; f.AId)  .OnDelete(DeleteBehavior.NoAction);    EntityTypeBuilderlt;BModelgt; b= modelBuilder.Entitylt;BModelgt;();   b.HasIndex(x =gt; new { x.Name, x.ProjectId, x.Type, x.AId})  .IsUnique()  .HasFilter($"[{ModelConst.Type}] = '{ModelConst.TypesConst.B}'");   b.HasMany(x =gt; x.Cs)  .WithOne(x =gt; x.B)  .HasForeignKey(f =gt; f.BId)  .OnDelete(DeleteBehavior.NoAction);   EntityTypeBuilderlt;CModelgt; c= modelBuilder.Entitylt;CModelgt;();   c.HasIndex(x =gt; new { x.Name, x.ProjectId, x.Type, x.BId })  .IsUnique()  .HasFilter($"[{ModelConst.Type}] = '{ModelConst.TypesConst.C}'");   c.HasMany(x =gt; x.Ds)  .WithOne(x =gt; x.C)  .HasForeignKey(f =gt; f.CId)  .OnDelete(DeleteBehavior.NoAction);   EntityTypeBuilderlt;DModelgt; d= modelBuilder.Entitylt;DModelgt;();   d.HasIndex(x =gt; new { x.Name, x.ProjectId, x.Type, x.CId })  .IsUnique()  .HasFilter($"[{ModelConst.Type}] = '{ModelConst.TypesConst.D}'");  

Комплименты

Комментарии:

1. Ядро EF имеет дело с сущностями, а не с таблицами и строками. Каскадное удаление работает, но опять же, вы имеете дело не с таблицами и строками. Если вы пометите все загруженные объекты как удаленные и вызовете SaveChanges , EF Core создаст DELETE инструкции для всех из них.

2. Это либо 4 раунда, необработанный sql-запрос, либо хранимая процедура.

3. С другой стороны this table with 4 different row types discriminated: , и The types have the following relationships: это, вероятно, запах. Отношения в базе данных определяются таблицами и внешними ключами. Не предположения программиста. Внешние ключи могут ссылаться на одну и ту же таблицу, поэтому каскадное удаление может работать, даже если оно будет очень неэффективным. Однако при загрузке объектов даже самые причудливые отношения должны быть переведены в обычные старые свойства объектов и коллекций.

4. if I delete all C's first and then SaveChanges, then all D's and SaveChange тебе не обязательно это делать. Найдите все объекты и позвоните Delete по ним, затем сделайте один звонок SaveChanges . Если вам нужно лучшее решение, опубликуйте свою фактическую схему таблицы и классы. Например, если бы у вас была иерархия самоссылок, вы могли бы создать рекурсивный CTE и УДАЛИТЬ, чтобы удалить все связанные строки одним вызовом. Если вы используете hierarchyid , вы можете избежать CTE и удалить все с помощью ключа, который начинается с ключа root, простой поиск по диапазону

5. Выберите производительность. Всегда. Вам не нужно много поездок туда и обратно. Таким образом, создайте хранимую процедуру и выполните ее.