EF Code-First,无法删除外键关系。

5

我有两个模型,如下所示:

public class Application
{
  public string Name { get; set; }
  public virtual ICollection<ApplicationTransaction> ApplicationTransactions { get; set; }
}

并且

public class ApplicationTransaction
{
  public long ApplicationId { get; set; }
  public virtual Application Application { get; set; }
}

我尝试使用以下代码删除所有ApplicationApplicationTransaction

var app = _repository.Get<Application>(i => i.Id == 1);
app.ApplicationTransactions.Clear();
Context.SaveChanges();

但是当上下文尝试保存更改时,会出现错误:
操作失败:无法更改关系,因为一个或多个外键属性是非空的。当对关系进行更改时,相关的外键属性将设置为空值。如果外键不支持空值,则必须定义新关系、分配另一个非空值的外键属性,或删除不相关的对象。

代码中显示的模型与数据库中不同,我知道。我会简要展示模型。 - Behrooz
4个回答

1
我也遇到了同样的问题,以下是解决方案:
技巧:在设置父子关系时,你必须在子表上创建一个“复合”键。这样,当你告诉父表删除一个或所有子表时,相关记录会从数据库中实际删除。
使用Fluent API配置复合键:
modelBuilder.Entity<Child>.HasKey(t => new { t.ParentId, t.ChildId });

然后,要删除相关的子元素:
var parent = _context.Parents.SingleOrDefault(p => p.ParentId == parentId);

var childToRemove = parent.Children.First(); // Change the logic 
parent.Children.Remove(childToRemove);

// or, you can delete all children 
// parent.Children.Clear();

_context.SaveChanges();

完成!


0
在你的“保存应用程序”方法中,你可以添加如下逻辑:
var modifiedAppplicationTransactions = context.ChangeTracker.Entries<ApplicationTransactions>().Where(x => x.State == EntityState.Modified);
foreach (var item in modifiedAppplicationTransactions )
{
    if (item.Entity.ApplicationId == null)
    {
        context.Entry(item.Entity).State = EntityState.Deleted;
    }
}
context.SaveChanges():

0

仅清除相关实体的集合是不够的,因为每个相关实体都存储指向Application实体的外键;因此,您需要删除相关实体而不是清除相关实体的集合。

foreach (ApplicationTransaction applicationTransaction in app.ApplicationTransactions.ToList())
    context.DeleteObject(applicationTransaction);

1
如果一个应用程序有成千上万个应用事务,那么EF必须为每条记录生成成千上万个查询。 - Behrooz
@Behrooz 是的,但这就是它的工作方式。EF在清除集合时不会执行一次性删除(就像NHibernate可以做的那样)。顺便说一下,DbContext语法应该是context.ApplicationTransactions.Remove(applicationTransaction); - Gert Arnold
不,你必须在子表上设置一个复合主键。这样,当你从父表中删除一个子项时,EF将删除关系并从数据库中删除子记录。如果你没有设置复合主键,它只会尝试删除关系。 - Mosh

0

也许你可以使用流畅的API手动创建关系,就像这样:

 modelBuilder.Entity<Application>()
            .HasOptional(a => a.ApplicationTransactions)
            .WithOptionalPrincipal(a => a.Application);

然后外键列将可为空


我认为WithOptionalPrincipal用于一对一关系,但这是一对多关系。 - Behrooz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接