繁体   English   中英

当模型属性具有 [ConcurrencyCheck] 属性时,ASP.NET Core MVC ConcurrencyCheck 失败

[英]ASP.NET Core MVC ConcurrencyCheck is failing when the model property has the [ConcurrencyCheck] attribute

我是 ASP.NET Core MVC 中的并发检查的新手,必须在这里实现错误,但是 Microsoft 文档似乎很薄弱。 有人能指出我正确的方向吗?

这是一个简单的用户类,可由管理员编辑。 如果没有任何并发​​检查,表单更改将毫无问题地保存到数据库中,但是,当我将 [ConcurrencyCheck] 属性添加到模型属性之一时,即使字段值发生更改,保存到数据库也会失败(我是期望这只会在用户 A 在用户 B 之前更新字段时失败,等等)

任何帮助将不胜感激。

这里有一些片段。

模型

public class MyUser : IdentityUser
    {
        [ConcurrencyCheck]
        [PersonalData]
        [DisplayName("First Name")]
        [Column(TypeName = "nvarchar(100)")]
        public string FirstName { get; set; }

        [PersonalData]
        [DisplayName("Last Name")]
        [Column(TypeName = "nvarchar(100)")]
        public string LastName { get; set; }


        [DisplayName("Created Date")]
        [Column(TypeName = "DateTime")]
        public DateTime CreatedDateTime { get; set; }

        [DisplayName("Customer ID")]
        [Column(TypeName = "int")]
        public int CustomerId { get; set; }


        public string GetFullName()
        {
            return $"{FirstName} {LastName}";
        }

    }

控制器


 // GET: UserController/Edit/5
        public ActionResult Edit(string id)
        {
            // New user view model.
            UserViewModel userViewModel = new UserViewModel();

            // Get user details.
            MyUser user = _context.Users.Where(u => u.Id == id).Single();


           var roles = _context.UserRoles.Where(r => r.UserId == id).ToList();

            if (user != null)
            {
                // Set viewmodel user with user details.
                userViewModel.thisUser = user;

               // userViewModel.thisUserRoles = _context.UserRoles.Where()

                // Get roles assigned to the user.
                //userViewModel.thisUserRoles = _context.userRoles.Where(r => r.UserId == id).ToList();

                // Set viewmodel variables based on which roles the user has.
                if (roles.Count > 0)
                {
                    foreach(var role in roles)
                    {
                        switch (_context.Roles.Where(r => r.Id == role.RoleId).Select(r => r.Name).Single().ToString())
                        {
                            case "User":
                                userViewModel.UserRole = true;
                                break;
                            case "Sales User":
                                userViewModel.SalesUserRole = true;
                                break;
                            case "Sales Branch User":
                                userViewModel.SalesBranchUserRole = true;
                                break;
                            case "Sales Administrator":
                                userViewModel.SalesAdministrator = true;
                                break;
                            case "Administrator":
                                userViewModel.Administrator = true;
                                break;
                                    
                        }
                    }
                }

                return View(userViewModel);
            }
            else
            {
                ViewBag.ErrorMessage = "The user could not be found.";
                return RedirectToAction("Index");
            }
            
        }






 // POST: UserController/Edit/5
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit(UserViewModel userViewModel)
        {

            if (ModelState.IsValid)
            {
                userViewModel.thisUser.UserName = userViewModel.thisUser.Email;
                userViewModel.thisUser.NormalizedUserName = userViewModel.thisUser.Email.ToUpper();
                userViewModel.thisUser.NormalizedEmail = userViewModel.thisUser.Email.ToUpper();


                try
                {

                    _context.Entry(userViewModel.thisUser).State = EntityState.Modified;
                    _context.SaveChanges();

                }
                catch (Exception ex)
                {
                    // Prompt the user to try again.
                    ModelState.AddModelError("", "The information has been updated by someone else before you saved. Please try again.");
                    return View(userViewModel);

                }





            }

            return RedirectToAction("Index");

        }

看法

@model MyApp.ViewModels.UserViewModel

@{
    ViewData["Title"] = "Edit";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

@*<h1>Edit</h1>*@



@*<h5>
    Details
</h5>
<hr />*@

<div class="row">
    <div class="col-md-4">
        <form asp-action="Edit">
            <div asp-validation-summary="All" class="text-danger"></div>


            @Html.HiddenFor(m => m.thisUser.Id)
            @Html.HiddenFor(m => m.thisUser.PasswordHash)
            @Html.HiddenFor(m => m.thisUser.LockoutEnd)
            @Html.HiddenFor(m => m.thisUser.LockoutEnabled)
            @Html.HiddenFor(m => m.thisUser.AccessFailedCount)
            @Html.HiddenFor(m => m.thisUser.CreatedDateTime)
            @Html.HiddenFor(m => m.thisUser.SecurityStamp)
            @Html.HiddenFor(m => m.thisUser.ConcurrencyStamp)
            @Html.HiddenFor(m => m.thisUser.EmailConfirmed)
            <div class="form-group">
                <label asp-for="thisUser.FirstName" class="control-label"></label>
                <input asp-for="thisUser.FirstName" class="form-control" />
                <span asp-validation-for="thisUser.FirstName" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="thisUser.LastName" class="control-label"></label>
                <input asp-for="thisUser.LastName" class="form-control" />
                <span asp-validation-for="thisUser.LastName" class="text-danger"></span>
            </div>




            <div class="form-group">
                <label asp-for="thisUser.Email" class="control-label"></label>
                <input asp-for="thisUser.Email" class="form-control" />
                <span asp-validation-for="thisUser.Email" class="text-danger"></span>
            </div>
           
            <div class="form-group">
                <label asp-for="thisUser.PhoneNumber" class="control-label"></label>
                <input asp-for="thisUser.PhoneNumber" class="form-control" />
                <span asp-validation-for="thisUser.PhoneNumber" class="text-danger"></span>
            </div>
            <div class="form-group form-check">
                <label class="form-check-label">
                    <input class="form-check-input" asp-for="thisUser.PhoneNumberConfirmed" /> @Html.DisplayNameFor(model => model.thisUser.PhoneNumberConfirmed)
                </label>
            </div>
            <div class="form-group form-check">
                <label class="form-check-label">
                    <input class="form-check-input" asp-for="thisUser.TwoFactorEnabled" /> @Html.DisplayNameFor(model => model.thisUser.TwoFactorEnabled)
                </label>
            </div>

            <div class="form-group">
                <label asp-for="thisUser.CustomerId" class="control-label"></label>
                <input asp-for="thisUser.CustomerId" class="form-control" />
                <span asp-validation-for="thisUser.CustomerId" class="text-danger"></span>
            </div>



            <h5>
                Roles
            </h5>
            <hr />

            <div class="form-group form-check">
                <label class="form-check-label">
                    <input class="form-check-input" asp-for="UserRole" /> @Html.DisplayNameFor(model => model.UserRole)
                </label>
            </div>

            <div class="form-group form-check">
                <label class="form-check-label">
                    <input class="form-check-input" asp-for="SalesUserRole" /> @Html.DisplayNameFor(model => model.SalesUserRole)
                </label>
            </div>

            <div class="form-group form-check">
                <label class="form-check-label">
                    <input class="form-check-input" asp-for="SalesBranchUserRole" /> @Html.DisplayNameFor(model => model.SalesBranchUserRole)
                </label>
            </div>

            <div class="form-group form-check">
                <label class="form-check-label">
                    <input class="form-check-input" asp-for="SalesAdministrator" /> @Html.DisplayNameFor(model => model.SalesAdministrator)
                </label>
            </div>

            <div class="form-group form-check">
                <label class="form-check-label">
                    <input class="form-check-input" asp-for="Administrator" /> @Html.DisplayNameFor(model => model.Administrator)
                </label>
            </div>



            <div class="form-group">
                <input type="submit" value="Save" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-action="Index">Back to List</a>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

根据ms官方文档,推荐使用row version处理并发冲突

从文档中总结,我们需要添加一个名为“RowVersion”的列,其数据类型为“rowversion”,并将其添加到您的实体中。

    [Timestamp]
    public byte[] RowVersion { get; set; }

在此处输入图片说明

接下来,在调用await _context.SaveChangesAsync();之前await _context.SaveChangesAsync(); 我们需要将原始 RowVersion 属性值放在实体的 OriginalValues 集合中

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> EditAsync(UserViewModel userViewModel)
{
     if (ModelState.IsValid)
     {
         try
         {
               _context.Entry(userViewModel.thisUser).Property("RowVersion").OriginalValue = userViewModel.thisUser.RowVersion;
               _context.Update(userViewModel.thisUser);
               await _context.SaveChangesAsync();
          }
          catch (Exception ex)
          {
                    // Prompt the user to try again.
              ModelState.AddModelError("", "The information has been updated by someone else before you saved. Please try again.");
              return View(userViewModel);

          }
     }

     return RedirectToAction("Index");
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM