entity framework不会检测导航属性的更改

我在检测导航属性的更改时遇到问题:

我的测试模型如下所示:

public class Person { public int Id { get; set; } public string Name { get; set; } public virtual Address Address { get; set; } } public class Address { public int Id { get; set; } public string Name { get; set; } } 

我创建并保存了一个Person类型的对象,并指定了Name和Address属性。 我的问题是,如果我从数据库中取回Person对象并更改Address属性(例如Null),那么ef不会检测到更改! 我的代码是这样的:

 using (var ctx = new EFContext()) { Person p = ctx.People.First(); //p.Address IS NOT NULL! p.Address = null; var entry = ctx.Entry(p); } 

为什么entry.State 不变

编辑:如果我调用SaveChanges,记录将正确保存(地址变为空)!

编辑2:我已经创建了billy建议的外键属性,如果我在visual studio中检查Person对象,则State被修改..如果我不停止调试器检查对象的值,状态是不变的!

编辑3:使用ctx.People.Include(x => x.Address)加载Person对象.First(); 解决了这个问题。 有没有办法避免调用Include并继续修改Address属性而不是AddressId属性?

首先:您必须遵循@ billy的建议才能使用Include 。 您的注释“ p.Address IS NOT NULL! ”仅为真,因为您正在调试器中观察p.Address ,从而在调试器中触发延迟加载,因此检测到将地址设置为null的更改。 在发布模式下或当您不检查调试器中的属性时,您的代码将无法工作,并且不会保存任何更改。

那么,你的编辑3的答案是:不。

第二: var entry = ctx.Entry(p)只返回实体状态而你没有改变实体状态,而是改变了关系状态 ,或者更确切地说是你删除了一个关系。 您不能使用DbContext API检查关系状态,而只能使用ObjectContext API检查关系状态:

 Person p = ctx.People.Include(x => x.Address).First(); p.Address = null; var objCtx = ((IObjectContextAdapter)ctx).ObjectContext; var objentr = objCtx.ObjectStateManager.GetObjectStateEntries(EntityState.Deleted); 

objentr将具有RelationshipEntry类型的条目:

在此处输入图像描述

当您调用SaveChanges()并删除关系时,EF会将此关系条目与实体状态条目一起考虑,即将数据库中PersonAddress外键列设置为NULL

关于编辑2:更改外键属性(模型中的标量属性)是实体本身的更改,因此在这种情况下实体状态将被Modified

您需要包含地址导航。 支柱。 在您的查询中,否则EF会在您保存时不考虑对其进行更改:

 using (var ctx = new EFContext()) { Person p = ctx.People.Include(x => x.Address).First(); //p.Address IS NOT NULL! p.Address = null; var entry = ctx.Entry(p); } 

您也可以在模型中使用外键,我非常喜欢:

 public class Person { public int Id { get; set; } public string Name { get; set; } public virtual Address Address { get; set; } public int? AddressId {get; set;} } 

 using (var ctx = new EFContext()) { Person p = ctx.People.First(); p.AddressId = null; var entry = ctx.Entry(p); } 

在我的应用程序中,在请求重新加载或用户离开项目/视图之前,我执行一些检查以确保没有未保存的更改。

这基本上是运行当前接受的答案,但我想提供一个实现,并提醒您必须在ObjectContext.ObjectStateManager可以获取关系更改之前调用Context.ChangeTracker.DetectChanges() ! 我花了不少时间调试这个,傻!

 _EagleContext.ChangeTracker.DetectChanges(); var objectContext = ((IObjectContextAdapter)_EagleContext).ObjectContext; var changedEntities = objectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified); if (_EagleContext.ChangeTracker.Entries().Any(e => e.State == EntityState.Modified) || changedEntities.Count() != 0) { var dialogResult = MessageBox.Show("There are changes to save, are you sure you want to reload?", "Warning", MessageBoxButton.YesNo); if (dialogResult == MessageBoxResult.No) { return; } } // Continue with reloading...