Entity framework EF STE和自引用表存在问题

Entity framework EF STE和自引用表存在问题,entity-framework,hierarchy,self-tracking-entities,self-reference,Entity Framework,Hierarchy,Self Tracking Entities,Self Reference,这是我在这里的第一篇帖子,所以我希望一切都很好 我的问题是: 我的数据库中有一个名为UserTypes的表。它有: 身份证 IsPrivate 家长ID 相关的是第一个和第三个。 我有另一个名为UserTypes\u T的表,其中包含不同类型的信息,即特定于语言的信息。这些字段是: 语言识别 用户类型标识 姓名 我试图实现的是从UserTypes表中加载整个层次结构,并将其显示在树视图中(这与现在无关)。然后,通过选择一些用户类型,我可以在单独的编辑框(名称)和组合框(父项)中编辑它们 在我尝试

这是我在这里的第一篇帖子,所以我希望一切都很好

我的问题是: 我的数据库中有一个名为UserTypes的表。它有:

  • 身份证
  • IsPrivate
  • 家长ID 相关的是第一个和第三个。 我有另一个名为UserTypes\u T的表,其中包含不同类型的信息,即特定于语言的信息。这些字段是:

  • 语言识别
  • 用户类型标识
  • 姓名 我试图实现的是从UserTypes表中加载整个层次结构,并将其显示在树视图中(这与现在无关)。然后,通过选择一些用户类型,我可以在单独的编辑框(名称)和组合框(父项)中编辑它们

    在我尝试将更改持久化到数据库中之前,一切正常。EF为这些表生成了两个实体类:

    用户类型的类具有:

  • 身份证
  • IsPrivate
  • 家长ID
  • 自引用的导航属性(0..1)
  • 子元素的导航属性
  • UserTypes_T表(1..*)的另一个导航属性 翻译信息的类具有:

  • 用户类型标识
  • 语言识别
  • 姓名
  • UserTypes表(*…1)的导航属性
  • 语言表(*…1)的导航属性 我通过以下方式获得所需数据:

    return context.UserTypes.Include("UserTypes_T").Where(ut => ut.IsPrivate==false).ToList();
    
    在我的WCF Web服务中。我可以毫无问题地添加新的用户类型,但是当我尝试更新旧的用户类型时,会发生一些奇怪的事情

    如果我更新一个根元素(Parent_ID==null),一切都正常! 如果我更新了一个元素,其中的Parent\u ID=null我得到以下错误:

    AcceptChanges无法继续,因为对象的键值与ObjectStateManager中的另一个对象冲突

    我在互联网上到处搜索,并阅读了来自(以及更多)的博客文章,但我的问题不同。当我更改父用户类型时,我实际上更改了parent_ID属性,而不是导航属性。为了避免出现问题,我总是尝试使用ID,而不是生成的导航属性

    我做了一些研究,试图看看我得到的对象图是什么,发现有很多重复的实体:

    根元素有其子元素的列表。每个子元素都有对根元素或其父元素的反向引用,依此类推。你可以想象。由于我没有使用这些导航属性,因为我使用ID来获取/设置所需的数据,所以我将它们从模型中删除。具体来说,我从用户类型实体类中删除了4和5点。然后我有一个对象图,每个元素只有一次。我尝试了新的更新,但遇到了相同的问题:

    根元素更新得很好,但是有一些父元素的元素抛出了相同的异常

    我看到我在UserTypes\u T实体类中有一个导航属性,指向一个用户类型,所以我也删除了它。然后这个错误消失了。对象图中的所有项目都是唯一的。但问题仍然存在-我可以毫无问题地更新我的根元素,但在尝试更新子元素(没有排除)时,我在生成的Model.Context.Extensions类中遇到了null引用异常:

    if (!context.ObjectStateManager.TryGetObjectStateEntry(entityInSet.Item2, out entry))
    {
        context.AddObject(entityInSet.Item1, entityInSet.Item2);//here!
    }
    
    我试图只更新名称(在用户类型中),但错误相同

    我没有主意了,我已经试着解决这个问题8个小时了,所以如果有人给我想法或分享他们的经验,我将不胜感激

    附言:

    我成功更新子对象的唯一方法是使用以下代码检索数据:

    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“修复”对象并将父ID更改为null。如果我重新设置,EF也会设置用户类型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...
    }
    

    就这样!我希望它能对某些人有用

    好了,各位,我刚刚找到了问题所在,如果其他人遇到同样的问题,我会发布答案

    问题是我在服务器上进行了一些验证,以查看用户类型之间是否存在循环引用。因此,我在服务器上的方法类似于:

    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...
    }
    
    就这样!我希望它能对某些人有用