这是我在这里的第一篇文章,所以我希望一切都很好。
这是我的问题: 我的数据库中有一个名为 UserTypes 的表。它有:
相关的是第一个和第三个。 我有另一个名为 UserTypes_T 的表,其中包含不同类型的信息,即特定于语言的信息。字段是:
我想要实现的是从 UserTypes 表加载整个层次结构并在TreeView中显示它(这与现在不相关)。然后,通过选择一些用户类型,我可以在单独的编辑框(名称)和组合框(父级)中编辑它们。
在我尝试将更改保留在数据库中之前,一切正常。 EF为我生成了两个表的实体类:
用户类型的类具有:
翻译信息的类有:
我得到了我需要的数据:
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,而不是生成的导航属性,以避免出现问题。
我做了一些研究,试图看看我得到的对象图是什么,看到有很多重复的实体:
根元素有一个子元素列表。每个子元素都有一个对root或其父级的后引用,依此类推。你可以想象。因为我没有使用那些导航属性,因为我使用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 ...也许有办法阻止这种行为?
答案 0 :(得分:1)
好的每个人,我刚刚发现了问题所在,如果其他人遇到同样的问题我会发布答案。
问题是我在服务器上进行了一些验证,以查看用户类型之间是否没有循环引用。所以,我在服务器上的方法看起来像:
using (MyEntities context = new MyEntities())
{
string errMsg = MyValidator.ValidateSomething(context.UserTypes,...);
if (!string.IsNullOrEmpty(errMsg)) throw new FaultException(errMsg);
//some other code here...
context.UserTypes.ApplyChanges(_userType);//_userType is the one that is updated
context.UserTypes.SaveChanges();
}
问题在于,在进行验证时,上下文被填充,当尝试保存更改时,会有一些具有相同键值的对象。
解决方案很简单 - 使用不同的上下文来验证服务器上的内容:
using (MyEntities validationContext = new MyEntities())
{
//validation goes here...
}
using (MyEntities context = new MyEntities())
{
//saving changes and other processing...
}
另一个可以是:
using (MyEntities context = new MyEntities())
{
using (MyEntities validationContext = new MyEntities())
{
//validation
}
//saving changes and other processing...
}
就是这样!我希望它对某人有用!