#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. Выберите производительность. Всегда. Вам не нужно много поездок туда и обратно. Таким образом, создайте хранимую процедуру и выполните ее.