Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 递归实体更新_C#_Entity Framework_Asp.net Mvc 4 - Fatal编程技术网

C# 递归实体更新

C# 递归实体更新,c#,entity-framework,asp.net-mvc-4,C#,Entity Framework,Asp.net Mvc 4,我有一个实体,其中包含一个实体列表(与根实体相同),以表示文件夹结构: public class SopFolder { public int Id { get; set; } public string Name { get; set; } public DateTime? LastUpdated { get; set; } public int Status { get; set; } public virtual ICollection<Sop

我有一个实体,其中包含一个实体列表(与根实体相同),以表示文件夹结构:

public class SopFolder
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime? LastUpdated { get; set; }
    public int Status { get; set; }
    public virtual ICollection<SopField> SopFields { get; set; }
    public virtual ICollection<SopFolder> SopFolderChildrens { get; set; }
    public virtual ICollection<SopBlock> Blocks { get; set; }
    public virtual ICollection<SopReview> Reviews { get; set; }
}
公共类文件夹
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共日期时间?上次更新的{get;set;}
公共int状态{get;set;}
公共虚拟ICollection字段{get;set;}
公共虚拟ICollection SopFolderChildrens{get;set;}
公共虚拟ICollection块{get;set;}
公共虚拟ICollection审阅{get;set;}
}
这个实体使用代码优先的方法存储在我的数据库中,这种方法工作得很好。然后,我将实体打印到KendoUI树视图中,让用户修改它,并在“保存”时将其作为
IEnumerable items
发布到服务器的操作中

然后我查找根实体及其所有子实体(只有一个根),并将其转换回一个SopFolder对象

要更新数据库中的完整对象,请执行以下操作:

 List<SopFolder> sopfolderlist = ConvertTree(items.First());

        SopFolder sopfolder = sopfolderlist[0];

        if (ModelState.IsValid)
        {
            SopFolder startFolder = new SopFolder { Id = sopfolder.Id };

            //db.SopFolders.Attach(startFolder);
           // db.SopFolders.Attach(sopfolder);

            startFolder.Name = sopfolder.Name;
            startFolder.LastUpdated = sopfolder.LastUpdated;
            startFolder.SopFields = sopfolder.SopFields;
            startFolder.SopFolderChildrens = sopfolder.SopFolderChildrens;
            startFolder.Status = sopfolder.Status;

            db.Entry(startFolder).State = EntityState.Modified;

            db.SaveChanges();
            return Content("true");
        }
List sopfolderlist=ConvertTree(items.First());
SopFolder-SopFolder=sopfolderlist[0];
if(ModelState.IsValid)
{
SopFolder startFolder=new SopFolder{Id=SopFolder.Id};
//db.SopFolders.Attach(startFolder);
//db.SopFolders.Attach(sopfolder);
startFolder.Name=sopfolder.Name;
startFolder.LastUpdated=sopfolder.LastUpdated;
startFolder.SopFields=sopfolder.SopFields;
startFolder.SopFolderChildrens=sopfolder.SopFolderChildrens;
startFolder.Status=sopfolder.Status;
db.Entry(startFolder.State=EntityState.Modified;
db.SaveChanges();
返回内容(“真实”);
}
然而,这是行不通的。模型根本没有更新。如果我在修改之前移动“entityState.Modified”,它只会在数据库中创建一个完整的新数据副本(当然是修改的)

我的方法是正确的还是必须走另一条路?我错过了什么?我猜还有另一个“隐藏”id,它允许EF将实体映射到db条目,但我不确定这一点。谢谢你的帮助

更新: 我没有创建新的SopFolder实例,而是尝试了
db.SopFolders.Find(SopFolder.Id)
,这适用于没有子项的条目。如果我有子实体,它会创建一个副本

问候,,
Marcus

我建议您使用
ParentId
而不是子对象列表创建实体模型。当您需要treeview模型时,使用递归函数从数据库中收集它

public class SopFolder
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime? LastUpdated { get; set; }
    public int Status { get; set; }
    public virtual ICollection<SopField> SopFields { get; set; }

    //public virtual ICollection<SopFolder> SopFolderChildrens { get; set; }
    public int? ParentFolderId { get; set; }

    public virtual ICollection<SopBlock> Blocks { get; set; }
    public virtual ICollection<SopReview> Reviews { get; set; }
}
公共类文件夹
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共日期时间?上次更新的{get;set;}
公共int状态{get;set;}
公共虚拟ICollection字段{get;set;}
//公共虚拟ICollection SopFolderChildrens{get;set;}
public int?ParentFolderId{get;set;}
公共虚拟ICollection块{get;set;}
公共虚拟ICollection审阅{get;set;}
}
创建子文件夹时,请选择它的父文件夹,以便收集数据。在儿童案例中,请尝试以下方法:

List<SopFolder> sopfolderlist = ConvertTree(items.First());

        SopFolder sopfolder = sopfolderlist[0];

        if (ModelState.IsValid)
        {
            SopFolder startFolder = new SopFolder { Id = sopfolder.Id };

            //db.SopFolders.Attach(startFolder);
           // db.SopFolders.Attach(sopfolder);

            startFolder.Name = sopfolder.Name;
            startFolder.LastUpdated = sopfolder.LastUpdated;
            startFolder.SopFields = sopfolder.SopFields;
            startFolder.SopFolderChildrens = sopfolder.SopFolderChildrens;

            foreach (var child in sopfolder.SopFolderChildrens)
            {
               db.SopFolders.CurrentValues.SetValues(child);
               db.SaveChanges();
            }

            startFolder.Status = sopfolder.Status;
            db.Entry(startFolder).State = EntityState.Modified;
            db.SaveChanges();
            return Content("true");
        }
List sopfolderlist=ConvertTree(items.First());
SopFolder-SopFolder=sopfolderlist[0];
if(ModelState.IsValid)
{
SopFolder startFolder=new SopFolder{Id=SopFolder.Id};
//db.SopFolders.Attach(startFolder);
//db.SopFolders.Attach(sopfolder);
startFolder.Name=sopfolder.Name;
startFolder.LastUpdated=sopfolder.LastUpdated;
startFolder.SopFields=sopfolder.SopFields;
startFolder.SopFolderChildrens=sopfolder.SopFolderChildrens;
foreach(sopfolder.SopFolderChildrens中的var child)
{
db.SopFolders.CurrentValues.SetValues(子级);
db.SaveChanges();
}
startFolder.Status=sopfolder.Status;
db.Entry(startFolder.State=EntityState.Modified;
db.SaveChanges();
返回内容(“真实”);
}

这是典型的断开连接图场景。有关可能的解决方案,请参见此问题:

您已经找到了第一个解决方案——即:分别更新实体。实际上,您应该做的是从数据库中获取原始数据,然后比较更改的内容。有一些通用的方法可以做到这一点,其中一些在J.Lerman的“Programming EF DbContext”一书中有描述,在使用EF进行更多编码之前,我强烈建议您使用该书


请注意,这是EF最糟糕的缺点。

替换SopFolder startFolder=new SopFolder{Id=SopFolder.Id};与

 SopFolder startFolder = db.SopFolders.FirstOrDefault(s=>s.Id.Equals(sopfolder.Id));

 // then validate if startFolder != null

我不能理解这个说法。但我使用这样的方法:var startFolder=entityRepository.Find(sopfolder.Id);然后startfolder.Name=sopfolder.Name。。。您必须上诉相同的实体我尝试了
SopFolder startFolder=db.SopFolders.Find(SopFolder.Id)
,但这给了我一个完整的结构副本,而不是仅仅编辑现有的结构。我认为这是不可能的,@user2014432。因为这意味着您的数据已经更新。请检查上面的“我的更新”。它适用于查找单个条目,但不适用于包含子项的文件夹。因此,我将改变我的方法,迭代每个实体,并分别修改并保存到数据库中。也许可以。不确定我的地址是否正确,但在我的代码优先方法中,IEnumerable SopFolderChildren列表会自动在数据库中创建一个名为SopFolder_ID(带有父文件夹ID)的父ID。你是说这个吗?为什么你会推荐这种方法而不是使用子集合?在对象中公开父SopFolderID怎么样,这不是一种合适的方法吗?然后我有了子集合和父id。但是我不知道如何进行。因为在你的情况下,你也应该