2013-07-29 3 views
1

У меня есть объект, который содержит список лиц (так же, как корневого объекта) представлять структуру папок:Рекурсивный Entity Update

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.

Затем я ищу объект 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» перед изменениями, он просто создает полный свежий дубликат моих данных в базе данных (измененный, конечно).

Является ли мой подход правильным или мне нужно идти другим путем? Что мне здесь не хватает? Я думаю, есть еще один «скрытый» идентификатор, который позволяет EF отображать объекты в записи db, но я не уверен в этом. Спасибо за помощь!

UPDATE: Вместо создания нового экземпляра SopFolder я также попытался использовать 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 (с родительским идентификатором папки) в базе данных. Вы имеете в виду это? –

+0

Я отредактировал ответ –

+0

Зачем вам рекомендовать этот подход вместо использования детской коллекции? Как насчет разоблачения родительского SopFolderID внутри объекта, не будет ли это правильным? Тогда у меня есть дочерняя коллекция и родительский идентификатор. Однако я не мог понять, как это сделать. –

0

Это типичный сценарий несвязанного графика. Пожалуйста, ознакомьтесь с этим вопросом для возможных решений: Disconnected Behavior of Entity Framework when Updating Object Graph

Вы уже определили первое решение - то есть: обновите объекты отдельно. Фактически, вам нужно извлечь исходные данные из базы данных, а затем выполнить сравнение того, что изменилось. Есть несколько общих способов сделать это, некоторые из них описаны в книге «Программирование 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 
Смежные вопросы