2013-07-29 61 views
1

我有持有实体(同根实体)的列表,以表示一个文件夹结构的实体:递归实体更新

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树视图,让用户修改和“保存”后回服务器到行动为IEnumerable<TreeViewItemModel> 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"); 
     } 

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

是我的做法正确,或做我必须去一个不同的路径?我在这里错过了什么?我想还有另一个“隐藏”的ID,它让EF将实体映射到数据库条目,但我不确定这一点。感谢帮助!

UPDATE: 相反SopFolder我的creatinga新实例也试过db.SopFolders.Find(sopfolder.Id),这适用于无子女的条目。如果我有孩子的实体,它会创建一个副本。

问候, 马库斯

+0

我不明白这个问题。但我使用这样的:var startFolder = entityRepository.Find(sopfolder.Id);然后startfolder.Name = sopfolder.Name ......你必须呼吁同一实体 –

+0

我试过'SopFolder startFolder = db.SopFolders.Find(sopfolder.Id)'但是这给我的结构的完整副本,而不是仅仅修改现行一。 –

+0

我认为这是不可避免的,@ user2014432。因为这意味着你的数据已经被更新了。 –

回答

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

不知道我是否正在处理正确的事情,但在我的代码优先方法中,IEnumerable SopFolderChildren列表会自动在数据库中创建一个名为SopFolder_Id(具有父文件夹标识)的父ID。你的意思是? –

+0

我编辑答案 –

+0

为什么你会推荐这种方法,而不是使用子集合?那么如何在对象中暴露父级SopFolderID,这不是一个适当的方法吗?然后我有孩子收集和父母的ID。但我无法弄清楚如何。 –

0

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

您已经计算出第一个解决方案 - 即:分别更新实体。实际上,你应该做的是从数据库中提取原始数据,然后对比已经发生的变化。有这样做的,他们中的一些由J.Lerman“编程EF的DbContext”的书,我强烈做多使用EF编码之前,建议您描述的一些通用的方法。

P.S.恕我直言,这是EF的糟糕之处。

0

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

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

// then validate if startFolder != null