递归实体更新

时间:2013-07-29 10:27:52

标签: 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<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; }
}

此实体使用Code-First Approach存储在我的数据库中,该方法工作正常。然后我将实体打印到KendoUI Treeview,让用户修改它并“保存”,将其作为IEnumerable<TreeViewItemModel> items发送回服务器。

然后我查找ROOT实体及其所有子项(只有一个根)并将其转换回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");
        }

然而这不起作用。该模型根本没有更新。如果我在修改之前移动“entityState.Modified”,它只会在数据库中创建一个完整的新数据副本(当然已修改)。

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

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

此致 马库斯

3 个答案:

答案 0 :(得分:0)

我建议您使用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; }
}

创建子文件夹时,选择它的父文件夹,以便收集数据。在儿童案件中试试这个:

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");
        }

答案 1 :(得分:0)

这是典型的断开连接图方案。请查看此问题以获取可能的解决方案 Disconnected Behavior of Entity Framework when Updating Object Graph

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

P.S。恕我直言,这是EF的最坏情况。

答案 2 :(得分:0)

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

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

 // then validate if startFolder != null