我想要一种基于 entity framework 中的 where 子句更新一系列记录的方法,而不使用 ToList() 和 foreach
I want a way to update a range of records based on a where clause in entity framework without using ToList() and foreach
我的 asp.net 核心应用程序中有一个功能,它根据我在 where 子句中编写的特定条件更新一堆记录...我读到 ToList() 性能不佳,所以也是有比使用 tolist 和 foreach 更好更快的方法吗???
这是我目前的做法,如果有人提供更有效的方法,我将不胜感激
public async Task UpdateCatalogOnTenantApproval(int tenantID)
{
var catalogQuery = GetQueryable();
var catalog = await catalogQuery.Where(x => x.IdTenant == tenantID).ToListAsync();
catalog.ForEach(c => { c.IsApprovedByAdmin = true; c.IsActive = true; });
Context.UpdateRange(catalog);
await Context.SaveChangesAsync(); ;
}
Entity Framework 默认情况下不处理批量更新操作——因此您现有的代码。如果你真的想做这些批量操作,那么你有两个选择:
- 自己写SQL,使用ExecuteSqlCommand()方法
执行它;或
- 查看第 3 方扩展,例如 https://entityframework-extensions.net/
read that ToList() has bad performance ,
这是错误的。 ToList 的性能与您将获得的一样好 - 提交一个错误的查询,该查询过于复杂并导致错误 SQL,SQL 服务器将花费很长时间来执行并且速度很慢。
此外,许多人认为 "ToList" 很慢(如:在分析器中)。你看,你从数据库上下文开始,在那里获取一组实体,添加一些 where 子句——一切都很快。然后是 ToList,它需要 "long"(与其余部分相比)。好吧,这就是将查询发送到 sql 服务器的地方 ;) 这里 (x=>whatever) 采用 "no time" 因为它所做的只是向表达式树添加一些节点,而不是执行查询。这主要是人们混淆的 - 延迟执行,仅在要求结果时执行。
第三,有些人喜欢“ToList().Where() 并抱怨性能。尽可能过滤掉数据库。
这三个原因都是人们认为 ToList 很慢的原因 - 但它只表明缺乏对 LINQ 和 SQL 操作方式的理解。
我们可以通过在附加到 EF 进行跟踪之前选择一个数据子集,然后进行更新来降低查询成本。
但是,它可能只是无意义的微优化,除非您处理大量记录,否则性能不会明显提高。
// select pk for EF to track, and the 2 fields to be modified
var catalog = await catalogQuery.Where(x => x.IdTenant == tenantID)
.Select(x => new Catelog{x.CatelogId, x.IsApprovedByAdmin, x.IsActive }).ToListAsync();
//next we attach range here to let EF track the list
Context.AttachRange(catalog);
//perform your update as usual, this will be flagged as modified if changed
catalog.ForEach(c => { c.IsApprovedByAdmin = true; c.IsActive = true; });
//save and let EF update based on modified fields.
await Context.SaveChangesAsync();
让我向你解释一下你做了什么以及你想做什么。
您对与 ToList 和 ToListAsync 相关的性能问题部分正确,因为它们主要负责将实体上传到内存并跟踪它们。
基于此,如果您的请求预计会大量处理轻型数据,则您无需增强代码。但是,如果不是,则有许多开放的方法,每个方法都有其优点和缺点,并且您必须针对每种不想使用双重应用程序的情况在它们之间进行处理和平衡-SQL 请求。
让我们更现实地谈谈你的情况:
1- 我们假设您的方法消耗资源(加载大量数据,密集调用,或两者)
2- 我看到通过 c.IsApprovedByAdmin = true; c.IsActive = true;
更新所有行,修改过于静态
形成 (1) 和 (2) 我建议编写一个存储过程或 ExexcuteSqlCammand(正如 Bryan Lewis 所建议的那样)来为您执行此操作
因为 (3) 存储过程、触发器和所有基于 SQL 的操作都很难维护,并且极有可能出现隐藏的异常。但是,在你的情况下,你不太可能陷入这种情况,因为你的代码太基础了,你可以通过从动态元素构造查询来降低更多风险,例如 nameof(yourClassName 那是 table name).YouProperty之类的...
无论如何,这是一个例子,表明没有理想的方法,你已经单独研究了每个案例。
最后,我不同意 3d 方扩展,因为大多数由非专业人士开发的免费提供和由此引起的跟踪异常是噩梦,而且付费版本太贵而且不是 0 异常扩展。 3d 方扩展更面向复杂的批量 update/delete and/or 庞大的数据。
例如
await Context.UpdateAsync(e=> new Catalog
{ Archived = e.LastUpdate >
DateTime.UtcNow.AddYears(-99)? false : true
});
我的 asp.net 核心应用程序中有一个功能,它根据我在 where 子句中编写的特定条件更新一堆记录...我读到 ToList() 性能不佳,所以也是有比使用 tolist 和 foreach 更好更快的方法吗??? 这是我目前的做法,如果有人提供更有效的方法,我将不胜感激
public async Task UpdateCatalogOnTenantApproval(int tenantID)
{
var catalogQuery = GetQueryable();
var catalog = await catalogQuery.Where(x => x.IdTenant == tenantID).ToListAsync();
catalog.ForEach(c => { c.IsApprovedByAdmin = true; c.IsActive = true; });
Context.UpdateRange(catalog);
await Context.SaveChangesAsync(); ;
}
Entity Framework 默认情况下不处理批量更新操作——因此您现有的代码。如果你真的想做这些批量操作,那么你有两个选择:
- 自己写SQL,使用ExecuteSqlCommand()方法 执行它;或
- 查看第 3 方扩展,例如 https://entityframework-extensions.net/
read that ToList() has bad performance ,
这是错误的。 ToList 的性能与您将获得的一样好 - 提交一个错误的查询,该查询过于复杂并导致错误 SQL,SQL 服务器将花费很长时间来执行并且速度很慢。
此外,许多人认为 "ToList" 很慢(如:在分析器中)。你看,你从数据库上下文开始,在那里获取一组实体,添加一些 where 子句——一切都很快。然后是 ToList,它需要 "long"(与其余部分相比)。好吧,这就是将查询发送到 sql 服务器的地方 ;) 这里 (x=>whatever) 采用 "no time" 因为它所做的只是向表达式树添加一些节点,而不是执行查询。这主要是人们混淆的 - 延迟执行,仅在要求结果时执行。
第三,有些人喜欢“ToList().Where() 并抱怨性能。尽可能过滤掉数据库。
这三个原因都是人们认为 ToList 很慢的原因 - 但它只表明缺乏对 LINQ 和 SQL 操作方式的理解。
我们可以通过在附加到 EF 进行跟踪之前选择一个数据子集,然后进行更新来降低查询成本。 但是,它可能只是无意义的微优化,除非您处理大量记录,否则性能不会明显提高。
// select pk for EF to track, and the 2 fields to be modified
var catalog = await catalogQuery.Where(x => x.IdTenant == tenantID)
.Select(x => new Catelog{x.CatelogId, x.IsApprovedByAdmin, x.IsActive }).ToListAsync();
//next we attach range here to let EF track the list
Context.AttachRange(catalog);
//perform your update as usual, this will be flagged as modified if changed
catalog.ForEach(c => { c.IsApprovedByAdmin = true; c.IsActive = true; });
//save and let EF update based on modified fields.
await Context.SaveChangesAsync();
让我向你解释一下你做了什么以及你想做什么。 您对与 ToList 和 ToListAsync 相关的性能问题部分正确,因为它们主要负责将实体上传到内存并跟踪它们。
基于此,如果您的请求预计会大量处理轻型数据,则您无需增强代码。但是,如果不是,则有许多开放的方法,每个方法都有其优点和缺点,并且您必须针对每种不想使用双重应用程序的情况在它们之间进行处理和平衡-SQL 请求。
让我们更现实地谈谈你的情况:
1- 我们假设您的方法消耗资源(加载大量数据,密集调用,或两者)
2- 我看到通过 c.IsApprovedByAdmin = true; c.IsActive = true;
形成 (1) 和 (2) 我建议编写一个存储过程或 ExexcuteSqlCammand(正如 Bryan Lewis 所建议的那样)来为您执行此操作
因为 (3) 存储过程、触发器和所有基于 SQL 的操作都很难维护,并且极有可能出现隐藏的异常。但是,在你的情况下,你不太可能陷入这种情况,因为你的代码太基础了,你可以通过从动态元素构造查询来降低更多风险,例如 nameof(yourClassName 那是 table name).YouProperty之类的...
无论如何,这是一个例子,表明没有理想的方法,你已经单独研究了每个案例。
最后,我不同意 3d 方扩展,因为大多数由非专业人士开发的免费提供和由此引起的跟踪异常是噩梦,而且付费版本太贵而且不是 0 异常扩展。 3d 方扩展更面向复杂的批量 update/delete and/or 庞大的数据。 例如
await Context.UpdateAsync(e=> new Catalog
{ Archived = e.LastUpdate >
DateTime.UtcNow.AddYears(-99)? false : true
});