实体框架:无法删除子数据

本文关键字:删除 数据 框架 实体 | 更新日期: 2023-09-27 18:16:21

在foreach循环中控制迭代时抛出错误。

foreach (var existingAddress in existingCustomer.Addresses.Where(a => a.AddressID == 5).ToList())
{
    foreach (var CustContacts in existingAddress.Contacts.Where(a => a.ContactID == 5))
    {
        CurrentContacts = CustContacts;
        existingAddress.Contacts.Remove(CurrentContacts);
        //CurrentAddress.Contacts.ToList().ForEach(r => db.Contacts.Remove(CurrentContacts));
    }
    CurrentAddress = existingAddress;
    existingCustomer.Addresses.Remove(CurrentAddress);
    //existingCustomer.Addresses.ToList().ForEach(r => db.Addresses.Remove(CurrentAddress));
}

existingAddress.Contacts.Remove(CurrentContacts);行执行时,错误信息为

Collection被修改;不能执行枚举操作。

如果我执行这行CurrentAddress.Contacts.ToList().ForEach(r => db.Contacts.Remove(CurrentContacts));而不是这行existingAddress.Contacts.Remove(CurrentContacts);,那么我得到的错误信息是

附加信息:对象引用未设置为对象的实例。

我是EF的新手,所以我不知道如何从子表中删除数据。

我的实体关系是Customer> Address> Contacts

客户可以有多个地址,每个地址可以有多个联系方式。

我的完整代码如下所示,我用来更新父客户对象,并试图从地址和联系人子表中删除特定数据,并在子表中插入两个新数据。

private void button3_Click(object sender, EventArgs e)
{
    Addresses CurrentAddress = null;
    Contacts CurrentContacts = null;
    using (var db = new TestDBContext())
    {
        var existingCustomer = db.Customer
        .Include(a => a.Addresses.Select(x => x.Contacts))
        .FirstOrDefault(p => p.CustomerID == 5);
        existingCustomer.FirstName = "Test Customer122";
        // selecting address
        foreach (var existingAddress in existingCustomer.Addresses.Where(a => a.AddressID == 5).ToList())
        {
            foreach (var CustContacts in existingAddress.Contacts.Where(a => a.ContactID == 5))
            {
                CurrentContacts = CustContacts;
                existingAddress.Contacts.Remove(CurrentContacts);
                //CurrentAddress.Contacts.ToList().ForEach(r => db.Contacts.Remove(CurrentContacts));
            }
            CurrentAddress = existingAddress;
            existingCustomer.Addresses.Remove(CurrentAddress);
            //existingCustomer.Addresses.ToList().ForEach(r => db.Addresses.Remove(CurrentAddress));
        }

        Addresses oAdrModel = new Addresses();
        oAdrModel.Address1 = "test add2";
        oAdrModel.Address2 = "test add2";
        oAdrModel.SerialNo = 3;
        oAdrModel.IsDefault = true;
        oAdrModel.CustomerID = existingCustomer.CustomerID;
        db.Addresses.Add(oAdrModel);
        Contacts ContactModel = new Contacts();
        ContactModel.Phone = "1111111-33";
        ContactModel.Fax = "1-1111111";
        ContactModel.SerialNo = 4;
        ContactModel.IsDefault = true;
        ContactModel.AddressID = CurrentAddress.AddressID;
        db.Contacts.Add(ContactModel);

        db.SaveChanges();
    }
}

实体相关类

public class CustomerBase
{
    public int CustomerID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    [NotMapped]
    public string Address1 { get; set; }
    [NotMapped]
    public string Address2 { get; set; }
    [NotMapped]
    public string Phone { get; set; }
    [NotMapped]
    public string Fax { get; set; }
}
public class Customer : CustomerBase
{
    public virtual List<Addresses> Addresses { get; set; }
}
public class Addresses
{
    [Key]
    public int AddressID { get; set; }
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public bool IsDefault { get; set; }
    public int SerialNo { get; set; }
    public virtual List<Contacts> Contacts { get; set; }
    public int CustomerID { get; set; }
    public virtual Customer Customer { get; set; }
}
public class Contacts
{
    [Key]
    public int ContactID { get; set; }
    public string Phone { get; set; }
    public string Fax { get; set; }
    public bool IsDefault { get; set; }
    public int SerialNo { get; set; }
    public int AddressID { get; set; }
    public virtual Addresses Customer { get; set; } 
}

完整工作代码

    using (var db = new TestDBContext())
    {
        //db.Database.Log = s => MyLogger.Log("EFApp", s);
        var existingCustomer = db.Customer
        .Include(a => a.Addresses.Select(x => x.Contacts))
        .FirstOrDefault(p => p.CustomerID == 5);
        existingCustomer.FirstName = "Test Customer123";
        existingCustomer.Addresses.Where(a => a.AddressID == 5).ToList().ForEach(r => db.Addresses.Remove(r));
        existingCustomer.Addresses.Where(a => a.AddressID == 5).SelectMany(ad => ad.Contacts).Where(c=> c.ContactID==5).ToList().ForEach(r => db.Contacts.Remove(r));
        Addresses oAdrModel = new Addresses();
        oAdrModel.Address1 = "test xxx";
        oAdrModel.Address2 = "test xxx";
        oAdrModel.SerialNo = 3;
        oAdrModel.IsDefault = true;
        oAdrModel.CustomerID = 5;
        db.Addresses.Add(oAdrModel);
        db.SaveChanges();
        int CurAddressID = oAdrModel.AddressID;
        Contacts ContactModel = new Contacts();
        ContactModel.Phone = "XX-1111111-33";
        ContactModel.Fax = "XX-1-1111111";
        ContactModel.SerialNo = 4;
        ContactModel.IsDefault = true;
        ContactModel.AddressID = CurAddressID;
        db.Contacts.Add(ContactModel);
        db.SaveChanges();
    }

实体框架:无法删除子数据

您的问题与EF没有直接关系,而是与Enumerables有关。您不能在当前枚举的集合上调用RemoveAdd或其他任何修改集合的方法。(这就是为什么错误消息显示"Collection was modified;不能执行枚举操作。")

这部分例如:

foreach (var CustContacts in existingAddress.Contacts.Where(a => a.ContactID == 5))
{
    CurrentContacts = CustContacts;
    existingAddress.Contacts.Remove(CurrentContacts);
}

您正在枚举联系人并在循环中删除联系人。一个简单的解决方法是调用ToList(正如您在外部循环中所做的那样)以确保您正在使用不同的枚举。

foreach (var CustContacts in existingAddress.Contacts.Where(a => a.ContactID == 5).ToList())
{
    CurrentContacts = CustContacts;
    existingAddress.Contacts.Remove(CurrentContacts);
}

我不完全确定你想要实现什么,但从外观上看,如果你在数据库中有一个干净的级联删除(自动删除相关/连接的条目),你可能会更好。