2013-06-04 95 views
0

我遇到了一個問題,試圖捕捉使用實體框架5 DbUpdateConcurrencyException 5.我遇到的問題是EF正在更新該記錄,即使RowVersion(Timestamp)屬性已更改,因爲該行是從數據庫。 HttpGet Edit操作從數據庫獲取用戶配置文件,並將值傳遞給ViewModel,其中包括用於選擇角色並將其傳遞給視圖的複選框列表。當RowVersion更改時,爲什麼Entity Framework會執行更新?

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); 
    } 

然後我有一個基本的編輯視圖,它具有RowVersion屬性的HiddenFor。

@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編輯操作,從視圖模型獲取數據,並把它添加到我已經從數據庫中檢索用戶配置文件。然後我更改此配置文件的屬性,這些從客戶端檢索到,包括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); 
    } 

我通過打開編輯頁面兩次進行測試。然後我更新第二頁並單擊保存,它將更改提交到數據庫。數據庫顯示行版本實際上已被更改以反映更新。當我更改第二個頁面並單擊保存時,即使此配置文件的行版本與保存第一個配置文件時創建的行版本不同,這些更改也會保存到數據庫中。我已經檢查過,數據庫中的行版本確實發生了兩次更改。

我有一個有趣的感覺,我很想念這裏明顯的,但任何幫助將不勝感激。

回答

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

說我改變了行版本的原因是,這樣的併發錯誤將首先被拾起防止這一點。包含在視圖模型中的行版本是原始版本。如果我不更改行版本,那麼我將永遠不會得到併發性錯誤,因爲在第一次更新發生後檢索其狀態被繪製的配置文件。 – MickySmig

+0

只是好奇,你如何配置版本控制列?你可以發佈代碼嗎? –

+0

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

相關問題