如何使用 ForNpgsqlUseXminAsConcurrencyToken 创建的 EF Core 并发令牌

Fan*_*nda 7 c# concurrency npgsql entity-framework-core asp.net-core

我找到了 npgsql 提供程序扩展来为实体框架核心实体设置并发令牌,它应该执行如下操作:

modelBuilder.Entity<MyEntity>(b =>
{
    b.Property<uint>("xmin")
        .HasColumnType("xid")
        .ValueGeneratedOnAddOrUpdate()
        .IsConcurrencyToken();
});
Run Code Online (Sandbox Code Playgroud)

如果我理解得很好,它会在实体上创建影子属性。

例如,如何使用此属性来跟踪 ASP.NET Core 中的并发更新(更多用户尝试更新同一实体)?我是否应该尝试将 xmin 列映射到普通属性并将其放入隐藏的输入标记,如asp.net core 文档中所示?或者还有别的办法吗?

Fan*_*nda 7

通过与 Olivier MATROT 讨论,我意识到如何做我需要的事情。

该解决方案并不理想,因为它与提供程序相关(SQL Server 提供程序需要 byte[] 作为并发令牌属性),但可以按预期工作:

public class MyEntity
{
    public int Id { get; set; }
    public string Name { get; set; }
    public uint ConcurrencyStamp { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

在上下文中(如果使用迁移,则需要从迁移代码中删除属性以消除列创建尝试)

protected override void OnModelCreating(ModelBuilder builder)
{
    base.OnModelCreating(builder);

    // ...

    builder.Entity<MyEntity>()
        .Property(e => e.ConcurrencyStamp)
            .ForNpgsqlHasColumnName("xmin")
            .ForNpgsqlHasColumnType("xid")
            .ValueGeneratedOnAddOrUpdate()
            .IsConcurrencyToken();
}
Run Code Online (Sandbox Code Playgroud)

编辑视图

@model Namespace.MyEntity

<form asp-action="Edit">
    <div class="form-horizontal">
        <h4>Person</h4>
        <hr />
        <div asp-validation-summary="ModelOnly" class="text-danger"></div>

        <input type="hidden" asp-for="Id" />
        <input type="hidden" asp-for="ConcurrencyStamp" />

        <div class="form-group">
            <label asp-for="Name" class="col-md-2 control-label"></label>
            <div class="col-md-10">
                <input asp-for="Name" class="form-control" />
                <span asp-validation-for="Name" class="text-danger"></span>
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Save" class="btn btn-default" />
            </div>
        </div>

    </div>
</form>
Run Code Online (Sandbox Code Playgroud)

和默认的脚手架操作(只是为了完成示例)

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,Name,ConcurrencyStamp")] MyEntity model)
{
    if (id != model.Id)
    {
        return NotFound();
    }

    if (ModelState.IsValid)
    {
        try
        {
            _context.Update(model);
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!MyEntityExists(model.Id))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }
        return RedirectToAction("Index");
    }
    return View(model);
}
Run Code Online (Sandbox Code Playgroud)

因此,解决方案是使 xmin 值可作为实体属性访问。