2013-06-04 4 views
0

У меня возникла проблема с попыткой захватить исключение DbUpdateConcurrencyException с использованием Entity Framework 5. Проблема, с которой я столкнулась, заключается в том, что EF обновляет запись, даже если свойство RowVersion (Timestamp) изменилось с тех пор, как строка была извлечена из база данных. Действие HttpGet Edit получает профиль пользователя из базы данных, и я передаю значения в ViewModel, включая список флажков для пользователя, чтобы выбрать роли и передать это в представление.Почему инфраструктура Entity Framework выполняла обновление при изменении RowVersion?

public ActionResult Edit(int id = 0) 
    { 
     UserProfile userProfile = unitOfWork.UserProfileRepository.GetUserProfileById(id); 

     UserProfileEditViewModel viewModel = new UserProfileEditViewModel 
     { 
     UserId = userProfile.UserId, 
     UserName = userProfile.UserName, 
     FirstName = userProfile.FirstName, 
     LastName = userProfile.LastName, 
     Email = userProfile.Email, 
     RowVersion = userProfile.RowVersion, 
     }; 

     var allRoles = unitOfWork.RoleRepository.GetAllRoles(); 
     var userProfileRoles = userProfile.Roles; 
     foreach (var role in allRoles) 
     { 
      if (userProfileRoles.Contains(role)) 
      { 
      viewModel.Roles.Add(new RoleViewModel 
      { 
       RoleId = role.RoleId, 
       RoleName = role.RoleName, 
       Assigned = true, 
      }); 
      } 
      else 
      { 
      viewModel.Roles.Add(new RoleViewModel 
      { 
       RoleId = role.RoleId, 
       RoleName = role.RoleName, 
       Assigned = false, 
      }); 
      } 
     } 
     return View(viewModel); 
    } 

У меня есть базовый вид редактирования, который имеет свойство HiddenFor для свойства RowVersion.

@model MvcWebsite.ViewModels.UserProfileEditViewModel 

@{ 
ViewBag.Title = "Edit"; 
} 

<h2>Edit</h2> 

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

<fieldset> 
    <legend>UserProfile</legend> 

    @Html.HiddenFor(model => model.UserId) 
    @Html.HiddenFor(model => model.UserName) 
    @Html.HiddenFor(model => model.RowVersion) 
    <div class="editor-label"> 
     @Html.LabelFor(model => model.UserName) 
    </div> 
    <div class="editor-field"> 
     @Html.DisplayFor(model => model.UserName) 
    </div> 

    <div class="editor-label"> 
     @Html.LabelFor(model => model.FirstName) 
    </div> 
    <div class="editor-field"> 
     @Html.EditorFor(model => model.FirstName) 
     @Html.ValidationMessageFor(model => model.FirstName) 
    </div> 

    <div class="editor-label"> 
     @Html.LabelFor(model => model.LastName) 
    </div> 
    <div class="editor-field"> 
     @Html.EditorFor(model => model.LastName) 
     @Html.ValidationMessageFor(model => model.LastName) 
    </div> 

    <div class="editor-label"> 
     @Html.LabelFor(model => model.Email) 
    </div> 
    <div class="editor-field"> 
     @Html.EditorFor(model => model.Email) 
     @Html.ValidationMessageFor(model => model.Email) 
    </div> 
    <div class="editor-field"> 
     <table> 
      <tr> 
       @Html.EditorFor(model => model.Roles) 
       @Html.ValidationMessageFor(model => model.Roles) 
      </tr> 
     </table> 
    </div> 
    <p> 
     <input type="submit" value="Save" /> 
    </p> 
</fieldset> 
} 

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

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

Я тогда Редактировать действие HttpPost, который принимает данные из ViewModel и добавляет его в профиль пользователя, который я извлеченный из базы данных. Я тогда изменить свойства этого профиля с теми, которые были получены от клиента, в том числе RowVersion (изменение RowVersion обратно в исходное состояние)

[HttpPost] 
    [ValidateAntiForgeryToken] 
    public ActionResult Edit(UserProfileEditViewModel model) 
    { 
     try 
     { 
     if (ModelState.IsValid) 
     { 
      var userProfile = unitOfWork.UserProfileRepository.GetUserProfileById(model.UserId); 

      userProfile.UserName = model.UserName; 
      userProfile.FirstName = model.FirstName; 
      userProfile.LastName = model.LastName; 
      userProfile.Email = model.Email; 
      userProfile.RowVersion = model.RowVersion; 

      var roleAssignments = model.Roles; 

      foreach (var roleAssignment in roleAssignments) 
      { 
      if (roleAssignment.Assigned) 
      { 
       userProfile.Roles.Add(unitOfWork.RoleRepository.GetRoleById(roleAssignment.RoleId)); 
      } 
      else 
      { 
       userProfile.Roles.Remove(unitOfWork.RoleRepository.GetRoleById(roleAssignment.RoleId)); 
      } 
      } 

      unitOfWork.UserProfileRepository.UpdateUserProfile(userProfile); 
      unitOfWork.Save(); 

      return RedirectToAction("Details", new { id = userProfile.UserId }); 
     } 
     } 
     catch (DbUpdateConcurrencyException ex) 
     { 
     ... Code omitted for brevity 
     } 
     } 
     return View(model); 
    } 

Я проверить это, открыв страницу редактирования дважды. Затем я обновляю вторую страницу и нажимаю save, которая фиксирует изменения в базе данных. База данных показывает, что версия строки фактически была изменена, чтобы отразить обновление. Когда я меняю вторую страницу и нажимаю save, даже если версия строки этого профиля отличается от версии строки, которая была создана при сохранении первого профиля, изменения также сохраняются в базе данных. Я действительно проверял, что версия строки в базе данных фактически изменяется дважды.

У меня есть странное чувство, что я пропускаю здесь очевидное, но любая помощь будет принята с благодарностью.

ответ

0

Как правило, вы не меняете строку версии явно. это будет обрабатываться самой ORM. Что бы вы сделали, сравните версию модели представления с версией домена. если они не соответствуют вам, тогда вам нужно будет обработать этот сценарий.

if(viewmodel.RowVersion != domainModel.RowVersion) 
{ 
    //model has changed, notify user... 
} 
else 
{ 
    //update domain model 
    //save changes 
} 

Вы могли бы еще предотвратить это, сделав RowVersion непреложный

class domainmodel 
{ 
    ... 
    public int RowVersion {get; private set;} 
} 
+0

Причина, по которой я меняю версию строки так, что ошибка Параллелизм будет подобран в первую очередь. Версия Row, содержащаяся в модели представления, является оригиналом. если я не изменю версию строки, я никогда не получу ошибку параллелизма, так как профиль, состояние которого окрашивается, извлекается после первого обновления. – MickySmig

+0

просто любопытно, как вы настроили колонку управления версиями? можете ли вы опубликовать код? –

+0

http://stackoverflow.com/questions/16952031/updating-a-userprofile-and-its-roles-using-entity-framework – MickySmig

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