2

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

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

该实体使用运行良好的代码优先方法存储在我的数据库中。然后我将实体打印到 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)这适用于没有子项的条目。如果我有有孩子的实体,它会创建一个副本。

问候, 马库斯

4

3 回答 3

1

这是典型的断开连接图场景。请参阅此问题以获取可能的解决方案: 更新对象图时实体框架的断开行为

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

PS 恕我直言,这是 EF 更糟糕的缺点。

于 2013-07-29T11:17:53.060 回答
0

Replace SopFolder startFolder = new SopFolder { Id = sopfolder.Id }; with

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

 // then validate if startFolder != null
于 2013-07-29T11:35:29.523 回答
0

我建议您使用ParentId而非子对象列表创建实体模型。当您需要树视图模型时,使用数据库中的递归函数收集它。

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");
        }
于 2013-07-29T11:08:33.640 回答