将导航属性设置为null不会保存到数据库

时间:2013-11-15 21:18:02

标签: c# entity-framework

我对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

2 个答案:

答案 0 :(得分:5)

我已经知道发生了什么。当我设置many.MyOneSideEntity = null;时,实体的更改跟踪器已捕获初始值“null”。因此,从实体的角度来看,属性的值没有变化,因此即使属性的值与数据库中的值不同,更改跟踪器也不认为属性需要更新。

要解决此问题,只需通过getter访问该属性即可。这会导致实体的状态被加载到内存中,并且更改跟踪器将与这些值同步。然后,更改跟踪器会通过将该属性设置为null来注意所做的更改,然后在调用SaveChanges时将更改推送到数据库。

我必须这样做有点奇怪,但它与实体的更改跟踪器如何工作有关。

希望这有助于其他人!

答案 1 :(得分:0)

您似乎没有定义两个类之间的关系。您缺少以下定义:

.HasRequired(...).WithMany(...)

有关详细信息,请参阅this link