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

时间:2020-03-25 21:26:59

标签: entity-framework ef-core-3.0

寻找一种使用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"

}

然后它将仅更新单个文本。但是发生的是传递的“记录”值包含Class中每个对象的名称,将其设置为null或0,然后使用这些值更新该行中的所有列。

做过一些研究之后,我知道我可以使用类似的东西:

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

,然后仅更新该单列。我似乎无法弄清楚的是,如何利用我已经掌握的知识从A到B。只是好奇是否有人遇到了这个问题或有一个不错的解决方案。我目前的工作可能是遍历记录,以寻找可以设置IsModified的值,但没有运气使其正常工作。

1 个答案:

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