C# 删除顺序在实体框架中是不可预测的

C# 删除顺序在实体框架中是不可预测的,c#,entity-framework,C#,Entity Framework,我在实体框架代码优先项目中有以下删除方法: var selectedID = selectedGroup.ID; var users = (from user in db.Users where user.Group_ID == selectedID select user); db.Users.RemoveRange(users); db.Groups.Attach(selectedGroup); db.Groups.Remove(

我在实体框架代码优先项目中有以下删除方法:

var selectedID = selectedGroup.ID;
var users = (from user in db.Users
               where user.Group_ID == selectedID
               select user);
db.Users.RemoveRange(users);

db.Groups.Attach(selectedGroup);
db.Groups.Remove(selectedGroup);
db.SaveChanges();
这些是模型:

 public class Group
  {
    [Key]
    public Guid ID { get; set; }

    [Required]
    public Guid Branch { get; set; }

  }

  public class User
  {
    [Key]
    public Guid ID { get; set; }

    [Required]
    public Guid Group_ID { get; set; }

  }
调用
db.SaveChanges()
时,我得到一个异常:

DELETE语句与引用约束冲突 “FK_用户组”。数据库“UserDB”表中发生冲突 “dbo.Users”,列“组ID”。声明已终止

似乎Remove方法是以相反(随机)顺序调用的。如果在
RemoveRange()
之后添加另一个
db.SaveChanges()
,它(显然)工作正常


如何强制执行删除顺序?

您需要教授EF表关系。然后它会自动为您订购DML操作。在模型中声明关系。例如,用户类应该有一个组属性


这些属性在查询中也非常有用。我不知道没有他们你是怎么应付的。手动编写连接很乏味。

@Kaf是的,这就是为什么我先删除用户,然后删除组。EF反向执行它。“如果我在RemoveAnge()之后再添加一个db.SaveChanges(),它(显然)工作正常。”这就是你的解决方案-这有什么问题吗?他可能想继续使用1
SaveChanges
。嗯,我认为最好坚持使用级联上的
delete
,这应该可以防止这个问题发生。@DStanley如果我使用2个SaveChanges,这意味着到SQL server的2个往返。您是否认为它比使用仅1的性能更有效?在删除级联< /代码>时,您有什么理由禁用<代码>吗?如果不想使用导航属性,并且正在与数据属性进行映射,那么您该怎么做?我们完全停止使用导航属性,因为存在太多隐藏的性能问题,您永远不知道何时调用此类属性会很昂贵,甚至可能导致异常。@OliverSchimmer如果不让EF知道这些关系,我认为您没有任何选择。是否可以将这些属性设置为私有?不确定EF是否能处理好。让我知道你发现了什么。@OliverSchimmer也许我自己的经验中的一些建议可以帮助你:我养成了用SQL Profiler检查每个EF查询和每种类型的HTTP请求的习惯,以确保查询符合预期。这方面也有JavaScript解决方案。如果您稍微改进一下开发过程,也许可以使用导航属性。这些属性可能非常有用。我主要在查询中使用它们,而不是加载数据。比手工加入要好得多。我不认为开发过程是这里的问题,是否使用导航属性是一个设计决策。如果您想将逻辑和模型层与DAL分离,那么它们是有问题的。例如,您无法在更高的层中知道导航属性是否已初始化。当您不能期望上下文始终处于打开状态时,这一点很重要-这可能适用于较小的web应用程序,但当您必须在多个上下文上进行并行DB查询时,您应该使用分离的实体。