我有一个实体,它包含一个实体列表(与根实体相同)来表示一个文件夹结构:
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)
,这适用于没有子项的条目。如果我有子节点的实体,则会创建副本。
此致 马库斯
答案 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