在使用EF删除一对多关系的实体时,碰到如下提示:

“其他信息: 操作失败: 无法更改关系,因为一个或多个外键属性不可以为 null。对关系作出更改后,会将相关的外键属性设置为 null 值。如果外键不支持 null 值,则必须定义新的关系,必须向外键属性分配另一个非 null 值,或必须删除无关的对象。”

原因很简单,假设一个A对应多个B,那么B中的外键就是A的主键,如果先删除A,接着又把B读取到datacontext中

var lstB = a.B.ToList();

container.A.DeleteObject(a);

就会导致B中的外键失去关联,所以便产生了错误,解决的办法有下面几种:

1.将子表外键解除与主表的关联

如果仅仅是需要删除A,而不删除B,那么需要解除B与A的关联(一般情况下不这样做,都是删除A并且删除B)。代码如下:

1
2
3
4
5
6
var lstB = a.B.ToList();
foreach(B b in lstB)
{
b.Aid = Guid.Empty;
}
t.A.DeleteObject(a);

如果B的外键可以为null,那么可以改成

b.Aid = null;

2.先删除子表再删除主表

这是正常的操作方式,首先删除与A对应的所有的B,再删除A即可。不过在操作中却遇到了另外一个问题。

1
2
3
4
5
6
foreach (B b in a.B)
{
container.B.DeleteObject(b);
}
container.A.DeleteObject(a);
container.SaveChanges();

foreach操作看似简单方便,但却忽略了一点:这是一个修改数据源的操作!当执行

container.B.DeleteObject(b)

命令的时候,a.B这个集合实际上已经被修改了,所以会收到报错。那么换一个思路,用回for循环:

1
2
3
4
5
6
7
for (int i = 0; i < a.B.Count; i++)
{
B b = a.B.Tolist()[i];
container.B.DeleteObject(b);
}
container.A.DeleteObject(a);
container.SaveChanges();

特别需要注意这里会犯一个错误,虽然使用了for循环,但是该操作仍然是一个修改数据源的操作,也就是说每当执行一个

container.B.DeleteObject(b);

a.B.Count是减少一个的,所以代码应该是

1
2
3
4
5
6
7
8
for (int i = 0; i < a.B.Count; i++)
{
B b = a.B.Tolist()[i];
container.B.DeleteObject(b);
i--;
}
container.A.DeleteObject(a);
container.SaveChanges();

所以说细节决定成败,这种很容易犯的小错误以后还是需要注意啊:(

3.级联删除

首先需要在EF模型中建立级联删除关系

然后将A与B都读取到DataContext中,再删除主表A,EF就会级联的删除与A相关联的所有的B。