EF Core 3 更新单个列而不是整行

EF Core 3 to update a single column instead of full row

正在寻找一种使用 EF Core 3 更新 table 中单行中单列的方法。这是我正在寻找的场景。今天我有 class 定义如下:

public partial class Records
{
    public int Id { get; set; }
    public int CustomerId { get; set; }
    public int UserId { get; set; }
    public string UserText { get; set; }
    public DateTime? UserDate { get; set; }
    public bool? NotificationSent { get; set; }
}

并有一个像这样的 PUT 命令:

[HttpPut("{customerId}/{id}")]
    public async Task<IActionResult> PutRecords([FromHeader(Name = "Token")] string token, [FromHeader(Name = "Secret")] string secret, int id, Records record)
    {
        if (id != record.Id)
        {
            return BadRequest();
        }

        _context.Entry(record).State = EntityState.Modified;

        try
        {
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!RecordsExists(id))
            {
                return NotFound();
}
            else
            {
                throw;
            }
        }
        return Ok("Success"); ;
    }

当我发送给客户时,我希望我可以简单地发送 ID 和一个列,如下所示:

{
"Id": 140225,
"UserText": "Test"

}

然后它只会更新单个文本。但是正在发生的事情是传入的 "record" 值包含 Class 中每个对象的名称,设置为 null 或 0,然后用这些值更新该行中的所有列。

一直在做一些研究,我知道我可以使用类似的东西:

var Record = await _context.Records.FindAsync(id);
        Record.UserText = record.UserText;
        _context.Entry(Record).Property("UserText").IsModified = true;

然后它只更新那一列。我似乎无法弄清楚的是如何利用我提供的知识从 A 到 B。只是好奇是否有其他人对此有 运行 或者有一个很酷的解决方案。我目前的做法可能是循环遍历记录,寻找能够设置 IsModified 的值,但运气不好,无法让它正常工作。

这是在客户端和服务器之间传递实体时的预期行为。如果要更新值,更好的方法是在请求中加载实体,设置适用的值(验证后),然后保存更改。

更新跟踪的实体时,它将仅为更改的列生成适当的更新语句。

例如,要更新实体的描述:

[HttpPut("{customerId}/{id}")]
public async Task<IActionResult> UpdateDescription([FromHeader(Name = "Token")] string token, [FromHeader(Name = "Secret")] string secret, int id, string description, int rowVersion)
{
    var record = _context.Records.Single(x => x.Id == id);
    // TODO: Check the user associated to this session/request and assert they have permissions to this record.

    if (rowVersion != record.RowVersion)
    {
        // Consider Refusing the update, notify user that data has changed & refresh.
    }

    record.Description = description;
    _context.SaveChanges();
}

它不必像那个(1 个字段)那样具体,它可以通过可以更改的允许字段的视图模型进行更新,您可以单独验证和复制或使用 Automapper 进行映射到加载的实体。不过,作为一般规则,所采取的操作应尽可能具体,仅接受识别要更新的内容所需的数据以及要更新的值。绝对不是一个完整的实体,因为篡改可能会导致更新不应更改的值,或以非预期的方式更改它们。

此方法通过检查行版本或上次修改的时间戳等来帮助避免过时的数据更改。它还应该根据检索到的行验证当前用户的会话,以验证提供的 ID 是否可以验证。例如,传递一个 ID 和一个分离的实体然后检查 id == model.Id 是没有意义的。客户端或中间人可以对这两个值进行篡改。