У меня возникла проблема с попыткой захватить исключение 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, даже если версия строки этого профиля отличается от версии строки, которая была создана при сохранении первого профиля, изменения также сохраняются в базе данных. Я действительно проверял, что версия строки в базе данных фактически изменяется дважды.
У меня есть странное чувство, что я пропускаю здесь очевидное, но любая помощь будет принята с благодарностью.
Причина, по которой я меняю версию строки так, что ошибка Параллелизм будет подобран в первую очередь. Версия Row, содержащаяся в модели представления, является оригиналом. если я не изменю версию строки, я никогда не получу ошибку параллелизма, так как профиль, состояние которого окрашивается, извлекается после первого обновления. – MickySmig
просто любопытно, как вы настроили колонку управления версиями? можете ли вы опубликовать код? –
http://stackoverflow.com/questions/16952031/updating-a-userprofile-and-its-roles-using-entity-framework – MickySmig