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

时间:2016-11-04 09:53:33

标签: c# entity-framework

在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);时,错误消息为

  

收藏被修改;枚举操作可能无法执行。

如果我执行此行CurrentAddress.Contacts.ToList().ForEach(r => db.Contacts.Remove(CurrentContacts));而不是此行existingAddress.Contacts.Remove(CurrentContacts);,那么我将收到错误消息

  

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

我是EF的新手,所以我无法弄清楚如何从子表中删除数据。

我的实体关系是客户>地址>联系人

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

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

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

1 个答案:

答案 0 :(得分:2)

您的问题与EF没有直接关系,而是与Enumerables有关。 您无法调用RemoveAdd或其他任何修改您当前枚举的集合的集合的内容。 (这就是为什么错误消息显示“集合已被修改;枚举操作可能无法执行。”)

这部分例如:

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

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

e.g。

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

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