我遇到了一个问题,试图捕捉使用实体框架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);
}
我通过打开编辑页面两次进行测试。然后我更新第二页并单击保存,它将更改提交到数据库。数据库显示行版本实际上已被更改以反映更新。当我更改第二个页面并单击保存时,即使此配置文件的行版本与保存第一个配置文件时创建的行版本不同,这些更改也会保存到数据库中。我已经检查过,数据库中的行版本确实发生了两次更改。
我有一个有趣的感觉,我很想念这里明显的,但任何帮助将不胜感激。
说我改变了行版本的原因是,这样的并发错误将首先被拾起防止这一点。包含在视图模型中的行版本是原始版本。如果我不更改行版本,那么我将永远不会得到并发性错误,因为在第一次更新发生后检索其状态被绘制的配置文件。 – MickySmig
只是好奇,你如何配置版本控制列?你可以发布代码吗? –
http://stackoverflow.com/questions/16952031/updating-a-userprofile-and-its-roles-using-entity-framework – MickySmig