如何批量更新实体框架中的记录?

时间:2017-05-26 06:18:19

标签: c# entity-framework linq bulkupdate entity-framework-extended

我正在尝试使用Entity Framework批量更新记录。我尝试过Entity Framework.Extensions Update方法。

Update方法可以为具有相同更新值集的一组记录进行批量更新。

示例:

           Id -  Quantity
Record 1 - A  -  10
Record 2 - B  -  20
Record 3 - C  -  30

我们可以通过简单的调用

批量更新所有上述记录
Records.Update(new => Record { Quantity = 100 });

如何使用Entityframework.Extensions或其他任何方法批量更新具有不同数量的每条记录,从而更快地完成批量更新?

7 个答案:

答案 0 :(得分:15)

如果您不想使用SQL语句,可以使用Attach方法更新实体而不必先加载它:

using (myDbEntities db = new myDbEntities())
{
    try
    {
      //disable detection of changes to improve performance
      db.Configuration.AutoDetectChangesEnabled = false;

      //for all the entities to update...
      MyObjectEntity entityToUpdate = new MyObjectEntity() {Id=123, Quantity=100};
      db.MyObjectEntity.Attach(entityToUpdate);

      //then perform the update
      db.SaveChanges();
    }
    finally
    {
      //re-enable detection of changes
      db.Configuration.AutoDetectChangesEnabled = true;
    }
}

答案 1 :(得分:12)

使用ExecuteSqlCommand

using (yourDbEntities db = new yourDbEntities())
{
    db.Database.ExecuteSqlCommand("UPDATE YourTABLE SET Quantity = {0} WHERE Id = {1}", quantity, id);
}

ExecuteStoreCommand

yourDbContext.ExecuteStoreCommand("UPDATE YourTABLE SET Quantity = {0} WHERE Id = {1}", quantity, id);

答案 2 :(得分:1)

我发现一个easy way to do that没有任何第三方包装:
通过添加一种通用扩展方法SetValue,您可以简单地编写:

示例:

void Main()
{
    
    var dc = this; // context
    var p = dc.Purchases.Where(x=>x.Description.ToLower()=="bike")
                        .SetValue(w => w.Description = "Bicycle");
    p.Dump();
    dc.SubmitChanges();
}

如您所见,可以将符合Where条件的任何值显式设置为新值,因此此处Bike将被Bicycle替换。您可以随后查询该表以查看更改是否确实存在。

当然,如果要更改所有记录,例如:

,也可以省略Where语句。
dc.Records.SetValue(x => x.Quantity = 100);
dc.SubmitChanges();

实体框架(EF)/ LINQ会跟踪这些更改,并在调用.SubmitChanges()时-如使用LinqPad在SQL选项卡中所见-它将创建如下的SQL代码:

-- Region Parameters
DECLARE @p0 Int = 3
DECLARE @p1 VarChar(1000) = 'Bicycle'
-- EndRegion
UPDATE [Purchase]
SET [Description] = @p1
WHERE [ID] = @p0

对于较小的更改,这是可以的,但是对于大型表,它变得效率低下,因为它使用ID列标识和更改记录,而不是.SetValue定义的Description列。

从理论上讲,EF可以优化此操作,但是如您所见,它并不能做到这一点。 因此,如果您要进行真正的批量操作,则需要运行SQL命令,或者创建要通过EF调用的存储过程(用于复杂查询)。


扩展方法SetValue

此扩展方法可以解决问题(不需要其他第三方软件包):

// see: https://visualstudiomagazine.com/articles/2019/07/01/updating-linq.aspx
public static class Extensions
{
    public static IEnumerable<T> SetValue<T>(this IEnumerable<T> items, 
                                                  Action<T> updateMethod)
    {
        foreach (T item in items)
        {
            updateMethod(item);
        }
        return items;
    }
}

注意: 上面的示例使用 Nutshell 示例数据库,您可以通过遵循this link来轻松创建该数据库,并且代码是为LinqPad 6编写的,但是可以轻松地进行修改(LinqPad 6使用.NET Core,但是您也可以在.NET Framework的LinqPad 5上尝试使用它。

答案 3 :(得分:0)

批量更新可以通过简单的EF而不是单独的扩展方法分三个步骤完成: -

  • 首先加载所有实体。
  • 对每个实体进行Foreach并更改其字段值。
  • 在Foreach之后保存上下文一次。

这将以单批次发送多个更新查询。

答案 4 :(得分:0)

如果只想修改一些属性,请使用这种方式:

   foreach (var vSelectedDok in doks)
                    {
                        //disable detection of changes to improve performance
                        vDal.Configuration.AutoDetectChangesEnabled = false;

                        vDal.Dokumente.Attach(vSelectedDok);

                        vDal.Entry(vSelectedDok).Property(x=>x.Status).IsModified=true;
                        vDal.Entry(vSelectedDok).Property(x => x.LastDateChanged).IsModified = true;
    }
    vDal.SaveChanges();

答案 5 :(得分:0)

在EF 6中,每个表中都有AddRange方法。文档显示此方法比使用许多添加方法要快得多。因此,可以将所有可更新记录插入到临时表中,并使用一条sql语句批量更新主表。

编辑:此Document建议AddRange仅优化更改检测。它不会更改更改应用于数据库的方式。

答案 6 :(得分:0)

a)EFCore.BulkExtensions-BatchUpdateAsync

_dbContext.Set<MyObjectEntity>().BatchUpdateAsync( x => new MyObjectEntity{ Id=123, Quantity=100 });

https://github.com/borisdj/EFCore.BulkExtensions

“ EntityFrameworkCore扩展:批量操作(插入,更新,删除,读取,Upsert,同步)和批处理(删除,更新)。 库轻巧且非常高效,具有所有最常用的CRUD操作。 被微软推荐的前20名EF核心扩展中选中。”

b)或EF扩展-UpdateFromQuery

_dbContext.Set<MyObjectEntity>().UpdateFromQuery( x => new MyObjectEntity{ Id=123, Quantity=100 });

资源:

https://entityframework-extensions.net/update-from-query

https://stackoverflow.com/a/63460251/12425844

为什么UpdateFromQuery比SaveChanges,BulkSaveChanges和BulkUpdate快?

UpdateFromQuery直接在SQL中执行一条语句,例如 作为更新[TableName] SET [SetColumnsAndValues]在[键]中。

其他操作通常需要一次或多次数据库往返 这会降低性能。