2014-12-13 5 views
2

Я искал эту тему, и я понимаю, что есть немного связанный вопрос here, и хотя проблема звучит очень похоже, принятое решение не работает (что, если читать комментарии , то будет известно, что проблема на самом деле не решена).Обновление объекта, все изменения не сохраняются

Вот моя проблема, и я надеюсь, что кто-то может помочь:

У меня есть Entity:

public class Garden 
{ 
    public virtual int Id { get; set; } 
    public virtual string Name { get; set; } 
    public virtual PlantHardinessZone Zone { get; set; } 
} 

Она имеет отношения с PlantHardinessZone Entity:

public class PlantHardinessZone 
{ 
    public int Id { get; set; } 
    public string Zone { get; set; } 
} 

Для того, чтобы легко использовать зоны в DropDownListFor, я создал ViewModel:

public class GardenViewModel 
{ 
    public int ZoneId { get; set; } 
    public IEnumerable<PlantHardinessZone> Zones { get; set; } 

    public Garden Garden { get; set; } 
} 

Эта модель ViewModel используется в нескольких представлениях. В настоящее время он работает так, как ожидалось, для создания нового объекта Garden, однако редактирование работает неправильно. Если я изменю Зону, она не будет обновлена ​​в БД. Я прошел через код, и правильная информация о зоне возвращается из представления, она просто не обновляется. Если я изменю имя сада, это будет прекрасно.

Вот [HttpPost} Редактировать Действие:

[HttpPost] 
    [ValidateAntiForgeryToken] 
    public ActionResult Edit(GardenViewModel viewModel) 
    { 
     if (ModelState.IsValid) 
     { 
      Garden garden = viewModel.Garden; 
      garden.Zone = db.Zones.Where(z => z.Id == viewModel.ZoneId).Single(); 
      db.Gardens.Attach(garden); // per the solution accepted [here][2] 
      db.Entry(garden).State = EntityState.Modified; 
      db.SaveChanges(); 
      return RedirectToAction("Index"); 
     } 
     return View(viewModel); 
    } 

А вот соответствующий вид:

@model GardenManager.Web.ViewModels.GardenViewModel 

@{ 
    ViewBag.Title = "Edit"; 
} 

<h2>Edit</h2> 


@using (Html.BeginForm()) 
{ 
    @Html.AntiForgeryToken() 

    <div class="form-horizontal"> 
     <h4>Garden</h4> 
     <hr /> 
     @Html.ValidationSummary(true, "", new { @class = "text-danger" }) 
     @Html.HiddenFor(model => model.Garden.Id) 

     <div class="form-group"> 
      @Html.LabelFor(model => model.Garden.Name, htmlAttributes: new { @class = "control-label col-md-2" }) 
      <div class="col-md-10"> 
       @Html.EditorFor(model => model.Garden.Name, new { htmlAttributes = new { @class = "form-control" } }) 
       @Html.ValidationMessageFor(model => model.Garden.Name, "", new { @class = "text-danger" }) 
      </div> 
     </div> 
     <div class="form-group"> 
      <div class="col-md-10 col-md-offset-2"> 
       @Html.DropDownListFor(model => model.ZoneId, 
       new SelectList(Model.Zones, "Id", "Zone", Model.ZoneId), 
       "Select Zone", new { @class = "form-control" }) 
      </div> 
     </div> 

     <div class="form-group"> 
      <div class="col-md-offset-2 col-md-10"> 
       <input type="submit" value="Save" class="btn btn-default" /> 
      </div> 
     </div> 
    </div> 
} 

<div> 
    @Html.ActionLink("Back to List", "Index") 
</div> 

@section Scripts { 
    @Scripts.Render("~/bundles/jqueryval") 
} 

Может кто-нибудь помочь направить меня к решению этой очень раздражает вопрос? Весь вход приветствуется и оценивается. Спасибо огромное!

+0

'db.Вход (сад) .State = EntityState.Modified' отмечает только «сад», а не его навигационные свойства. Вот что вызывает ваше замешательство. Использование EF в отключенной среде не так просто, как должно быть. Вы должны пройти весь график объекта, чтобы получить все изменения в трекере изменений. Существует библиотека, [Graphdiff] (https://github.com/refactorthis/GraphDiff), которая может выполнить эту задачу для вас. –

+0

Мое замешательство приходит, потому что в моей голове Зона менялась, только FK в саду указывала на соответствующую Зону. В соответствии с ответом я добавил явный FK (ZoneId) и обновление, которое работало так, как я ожидал. :) – OCDDev

ответ

0

Вы устанавливаете состояние из сада в Modified, но это не оказывает никакого влияния на навигационные свойства (ссылка на зоны). Таким образом, EF будет обновлять только Сад, не влияя на связанные Зона.

Если, однако, вы назначаете зоны по его ID, чтобы garden.ZoneId, который будет работать. garden.ZoneId - прямое свойство Сад, и он получит все правильно связанное.

garden.ZoneId = db.Zones.Where(z => z.Id == viewModel.ZoneId).Single().Id; 

Повторим:
- garden.Zoneне является истинным свойство объекта, это просто ссылка обрабатывается за кулисами EF. Вот почему он не обновляется.
- garden.ZoneId- это истинное свойство объекта, поэтому оно обновляется надлежащим образом, если вы его измените.

db.Gardens.Attach(garden); прикрепляет только объект garden. Он не прикрепляет другие объекты, которые могут быть связаны с ним.

Кроме того, я бы рекомендовал сначала привязать объект к контексту, а затем изменить его свойства и состояние.

+0

Я вижу, что вы говорите, однако ** Зона ** на самом деле не меняется, только FK, который идентифицирует, что ** Zone **, но это все еще сохраняется в ** Garden **, если только я не отсутствует что-то. Я попробовал 'db.Entry (garden.Zone) .State = EntityState.Added;' Я также пробовал 'db.Entry (garden.Zone) .State = EntityState.Modified;', но это привело к ошибке на run: 'Сохранить обновление, вставить или удалить заявление повлияло на неожиданное количество строк (0). Объекты могут быть изменены или удалены, поскольку объекты загружены. Обновите записи ObjectStateManager. «Я попытался исправить это, однако, не повезло. – OCDDev

+0

Вы попробовали мое второе предложение? –

+0

У меня есть, да. Мне пришлось добавить явное свойство для ** ZoneId ** и выполнить миграцию, что я и сделал. Это сработало, так что большое спасибо. Я не уверен, почему это имело такое значение, но я все еще участвую. :) Еще раз спасибо. – OCDDev

Смежные вопросы