如何在EF码第一数据库中删除一个子到多个相关记录

本文关键字:一个 记录 删除 EF 数据库 | 更新日期: 2023-09-27 18:14:44

嗯,我有一对多相关的模型:

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);

Child类中具有附加的Parent性质

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);

Child类中添加Parent_Id属性

public class Child
{
     ...
     public int Parent_Id { get; set; }
     ...
}

那么,如何正确配置级联删除呢?或者我应该如何删除这些子实体?

如何在EF码第一数据库中删除一个子到多个相关记录

在EF6中,更快的操作方法是…

 context.Children.RemoveRange(parent.Children)

级联删除在这里没有效果,因为您不删除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();
}

这叫做"删除孤儿"。

如果父数据没有被删除,EF是否可以自动删除孤儿数据?

我不知道它在EF6中是如何工作的,但在EF Core中它工作得很好https://learn.microsoft.com/en-us/ef/core/saving/cascade-delete所以你不一定需要删除级联的父级。

删除孤儿示例

尝试更改为

 public virtual ICollection<Child> Children { get; set; }

,因为需要virtual来实现延迟加载。作为解释

我认为你的parent.Children.clear不起作用是因为Children还没有加载

如果您的对象是自引用的,您可以使用下面的方法删除多对多和一对多的子对象。只要记住之后调用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);
    }
}