【问题标题】:EF Core 3 to update a single column instead of full rowEF Core 3 更新单列而不是整行
【发布时间】:2020-03-25 21:26:59
【问题描述】:

寻找一种使用 EF Core 3 更新表中单行中的单个列的方法。这是我正在寻找的方案。今天我的类定义如下:

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"

}

然后它只会更新那个单一的文本。但是正在发生的是传入的“记录”值包含类中每个对象的名称,设置为 null 或 0,然后使用这些值更新该行中的所有列。

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

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

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

【问题讨论】:

    标签: entity-framework ef-core-3.0


    【解决方案1】:

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

    当一个被跟踪的实体被更新时,它会为改变的列生成适当的更新语句。

    例如,更新实体的描述:

    [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 是没有意义的。客户或中间人可以对这两个值进行篡改。

    【讨论】:

      猜你喜欢
      • 2019-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-23
      • 2021-10-20
      • 2019-08-04
      • 2021-09-08
      相关资源
      最近更新 更多