首页 > 解决方案 > 更新实体而不读取 EF 核心中的整个实体

问题描述

当我们只有主键时是否可以只更新特定属性,我不想读取现有的完整实体。我认为可以通过以下方式完成

using(var context = new SampleContext())
{
    var commandText = "Update Book SET Name='WhatEver' WHERE id=@id";
    var name = new SqlParameter("@id", "10001");
    context.Database.ExecuteSqlCommand(commandText, name);
}

但是有什么方法可以在不使用 EF 核心中的 SQL 查询的情况下进行更新?

注:典型方式

  1. 阅读现有的 Book 实体
  2. 更新名称 3 然后保存更改

但是,当我们需要更新 20k 条记录时,这种典型的方式成本更高

标签: entity-frameworkasp.net-coreupdates

解决方案


EF 并不真正适合批量操作,尽管它是工具带中的工具,因此当遇到不适合电钻的要求时,拔出螺丝刀以进行更精细的控制是完全可以的。

如果您需要执行批量更新,例如更新状态或日期,或跨大量行的其他一些静态更改,将其编写为语句并使用 ExecuteSqlCommand 在数据库中执行它没有任何问题。这里的问题是,如果这些记录中的任何一个恰好是您可能正在使用的 DbContext 中的跟踪实体,则需要在执行命令后刷新这些记录并从数据库重新加载它们以查看更改。

如果您需要对大量行执行逻辑检查,并且希望在代码中而不是 SQL 或 Sproc 之类的东西中执行此操作,那么另一种选择是使用具有极简实体定义的作用域 DbContext,将实体加载到批次并保存。例如,如果您有一个由 100 列(不包括关系)组成的实体,并且您只需要 4 列来涵盖您需要检查和更新的内容,那么您可以定义一个 DbContext 来处理仅包含这四列的实体定义的更新。这些可以分批读取,即从更新 DbContext 中一次读取 1000-10000 行,然后在调用之前将其输入到方法中进行验证和更新SaveChanges(),然后为下一批转储并重新创建 DbContext 实例。这种方法的警告是事务性的,如果更新失败,只有该批次会回滚。由于较小的实体足迹,系统可能会管理一次更新大量实体,可能是所有实体,但这需要监控性能成本。批量操作可能最好安排在下班后,以避免在繁忙时段临时触发数据库上的读锁/死锁或繁重的事务操作。


推荐阅读