Как удалить дочерние одно во многие связанные записи в первой базе данных EF-кода?
Ну, у меня есть одна-ко-многим связанная модель:
public class Parent
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Child> Children { get; set; }
}
public class Child
{
public int Id { get; set; }
public string ChildName { get; set; }
}
Что я хочу сделать, это очистить Parent.Children
и удалить связанные дочерние сущности из базы данных. Я уже пробовал:
Класс контекста базы данных:
modelBuilder.Entity<Parent>()
.HasMany(p => p.Children)
.WithOptional()
.WillCascadeOnDelete(true);
это отлично работает, но у меня все еще есть избыточные записи в базе данных с полями Parent_Id = null
, когда я делаю
parent.Children.Clear();
repository.InsertOrUpdate(parent);
в моем классе репозитория. То же самое происходит и в том, что я делаю:
modelBuilder.Entity<Parent>()
.HasMany(pr => pr.Children)
.WithOptional(ri => ri.Parent)
.WillCascadeOnDelete(true);
с дополнительным свойством Parent
в Child
классе
public class Child
{
...
public Parent Parent { get; set; }
...
}
или когда я делаю
modelBuilder.Entity<Child>()
.HasOptional(p => p.Parent)
.WithMany(p => p.Children)
.HasForeignKey(p => p.Parent_Id)
.WillCascadeOnDelete(true);
с дополнительным свойством Parent_Id в классе Child
public class Child
{
...
public int Parent_Id { get; set; }
...
}
Итак, как я могу правильно настроить каскадное удаление? Или как я должен удалить эти дочерние объекты? Я предполагаю, что это случайная задача, но я просто что-то пропустил.
Ответы
Ответ 1
Каскадное удаление здесь не действует, потому что вы не удаляете parent
, а просто вызываете InsertOrUpdate
. Правильная процедура состоит в том, чтобы удалить дочерние элементы один за другим, например, например:
using (var context = new MyContext())
{
var parent = context.Parents.Include(p => p.Children)
.SingleOrDefault(p => p.Id == parentId);
foreach (var child in parent.Children.ToList())
context.Children.Remove(child);
context.SaveChanges();
}
Ответ 2
В EF6 более быстрый способ выполнить операцию...
context.Children.RemoveRange(parent.Children)
Ответ 3
Попробуйте перейти на
public virtual ICollection<Child> Children { get; set; }
потому что виртуальный нужен для ленивой загрузки.
как объяснено
здесь
Я думаю, что ваш parent.Children.clear не работает, потому что дети не загружены
Ответ 4
Если ваш объект является саморегуляцией, вы можете удалить как "много-ко-многим", так и "один ко многим", используя приведенный ниже метод. Просто не забудьте затем вызвать db.SaveChanges():)
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
Object obj = this.db.Objects.Find(id);
this.DeleteObjectAndChildren(obj);
this.db.Objects.Remove(obj);
this.db.SaveChanges();
return this.Json(new { success = true });
}
/// <summary>
/// This deletes an object and all children, but does not commit changes to the db.
/// - MH @ 2016/08/15 14:42
/// </summary>
/// <param name="parent">
/// The object.
/// </param>
private void DeleteObjectAndChildren(Object parent)
{
// Deletes One-to-Many Children
if (parent.Things != null && parent.Things.Count > 0)
{
this.db.Things.RemoveRange(parent.Things);
}
// Deletes Self Referenced Children
if (parent.Children != null && parent.Children.Count > 0)
{
foreach (var child in parent.Children)
{
this.DeleteObjectAndChildren(child);
}
this.db.Objects.RemoveRange(parent.Children);
}
}