我对EF很新,我遇到过Entity没有按照我的预期行事的情况。我很感激帮助理解它是EF中的错误还是我理解中的“错误”。
我在帖子的末尾包含了所有代码;它应该在安装了Entity 6的测试项目中编译和运行。
这是情况。
我正在使用Code-First。
我有两个多对一关系的实体。他们在这里:
public class OneSideEntity
{
public int OneSideEntityId { get; set; }
public string Name { get; set; }
public virtual List<ManySideEntity> MyManySideEntities { get; set; }
}
public class ManySideEntity
{
public int ManySideEntityId { get; set; }
public string Name { get; set; }
public virtual OneSideEntity MyOneSideEntity { get; set; }
}
现在假设我创建ManySideEntity
并将其保存到变量many
,我在context.SaveChanges()
之后处理了上下文。然后我通过对OneSideEntity
的{{1}}属性执行“set”来创建并保存MyOneSideEntity
并保存,处理上下文后跟。这很好用;将新的many
实例添加到数据库中,并将许多外键正确更新为OneSideEntity
实例的主键值。
这是它开始变得有趣的地方。如果我现在尝试使用新上下文设置OneSideEntity
并保存,则不会将更改推送到数据库,并且单元测试many.MyOneSideEntity = null;
中的断言会失败。
但是,如果我使用关系的另一端执行删除,它就可以工作。也就是说,如果我得到RelationshipRemovalFails
实例,简称为OneSideEntity
,并将其从单侧导航属性中删除,如此one
并保存,它会被推送到数据库。因此,对应于此场景的单元测试中的断言(在下面的代码中称为one.MyManySideEntities.Remove( many );
)在保存更改时传递。实体甚至正确(根据我的理解)将RelationshipRemovalSucceeds1
更新为null作为保存的副作用。
最后,如果失败的相同单元测试稍微更改为使用相同的DbContext添加many.MyOneSideEntity
及其后来通过one
删除,它也会成功。此单元测试在下面的代码中称为many.MyOneSideEntity = null;
。
我认为失败的情况应该起作用,并且应该更新单侧实体的导航属性。有没有办法将导航属性设置为null并让实体推送更改而不必保持相同的DbContext?
完整代码:
RelationshipRemovalSucceeds2
答案 0 :(得分:5)
我已经知道发生了什么。当我设置many.MyOneSideEntity = null;
时,实体的更改跟踪器已捕获初始值“null”。因此,从实体的角度来看,属性的值没有变化,因此即使属性的值与数据库中的值不同,更改跟踪器也不认为属性需要更新。
要解决此问题,只需通过getter访问该属性即可。这会导致实体的状态被加载到内存中,并且更改跟踪器将与这些值同步。然后,更改跟踪器会通过将该属性设置为null来注意所做的更改,然后在调用SaveChanges时将更改推送到数据库。
我必须这样做有点奇怪,但它与实体的更改跟踪器如何工作有关。
希望这有助于其他人!
答案 1 :(得分:0)