这是我在这里的第一篇文章,所以我希望一切都好。
这是我的问题:我的数据库中有一个名为UserTypes的表。它有:
- ID;
- 是私人的;
- 父ID;
相关的是第一个和第三个。我有另一个名为UserTypes_T的表,其中包含不同类型的信息,即特定于语言的信息。这些字段是:
- 语言_ID;
- 用户类型_ID;
- 姓名;
我想要实现的是从UserTypes表中加载整个层次结构并将其显示在 TreeView 中(这目前不相关)。然后,通过选择一些用户类型,我可以在单独的编辑框(名称)和组合框(父级)中编辑它们。
一切正常,直到我尝试将更改保留在数据库中。EF 为我生成了这些表的两个实体类:
用户类型的类有:
- ID;
- 是私人的;
- 父ID;
- 自引用的导航属性(0..1);
- 子元素的导航属性;
- UserTypes_T 表的另一个导航属性 (1..*);
翻译信息的类有:
- 用户类型_ID;
- 语言_ID;
- 姓名;
- UserTypes 表的导航属性 (*..1);
- 语言表的导航属性 (*..1);
我得到我需要使用的数据:
return context.UserTypes.Include("UserTypes_T").Where(ut => ut.IsPrivate==false).ToList();
在我的 WCF Web 服务中。我可以毫无问题地添加新的用户类型,但是当我尝试更新旧的用户类型时,会发生一些奇怪的事情。
如果我更新根元素(Parent_ID==null)一切正常!如果我更新 Parent_ID!=null 的元素,我会收到以下错误:
AcceptChanges 无法继续,因为对象的键值与 ObjectStateManager 中的另一个对象冲突。
我在整个互联网上搜索并阅读了Diego B Vega(以及更多)的博客文章,但我的问题有所不同。当我更改父用户类型时,我实际上更改了 Parent_ID 属性,而不是导航属性。我总是尝试使用 ID,而不是生成的导航属性以避免出现问题。
我做了一些研究,试图看看我得到的对象图是什么,发现有很多重复的实体:
根元素有一个其子元素的列表。每个子元素都有一个对根或其父元素的反向引用,依此类推。你可以想象。由于我没有使用那些导航属性,因为我使用 ID 来获取/设置我需要的数据,所以我从模型中删除了它们。具体来说,我从UserTypes实体类中删除了第 4点和第 5点。然后我有一个每个元素只有一次的对象图。我尝试了一个新的更新,但我遇到了同样的问题:
根元素更新得很好,但是有一些父元素的元素抛出了同样的异常。
我看到我在UserTypes_T实体类中有一个导航属性,指向一个用户类型,所以我也删除了它。然后这个错误消失了。对象图中的所有项目都是唯一的。但是问题仍然存在 - 我可以毫无问题地更新我的根元素,但是当尝试更新子元素(没有排除)时,我在生成的 Model.Context.Extensions 类中得到了一个空引用异常:
if (!context.ObjectStateManager.TryGetObjectStateEntry(entityInSet.Item2, out entry))
{
context.AddObject(entityInSet.Item1, entityInSet.Item2);//here!
}
我尝试仅更新名称(在UserTypes_T中),但错误是相同的。
我没有想法,我已经尝试解决这个问题 8 个小时了,所以如果有人给我想法或分享他们的经验,我将不胜感激。
PS:
我成功更新子对象的唯一方法是使用以下代码检索数据:
var userTypes = argoContext.UserTypes.Include("UserTypes_T").Where(ut => ut.IsPrivate==false).ToList();
foreach (UserType ut in userTypes)
{
ut.UserType1 = null;
ut.UserTypes1 = null;
}
return userTypes;
其中UserType1是导航属性,指向父用户类型,而UserTypes1是导航属性,包含子元素的列表。这里的问题是 EF “修复”对象并将Parent_ID更改为null。如果我再次设置它,EF 也会设置UserTypes1 ......也许有办法阻止这种行为?