异步编程
异步操作避免在数据库中执行查询时阻塞线程。 异步作对于在丰富的客户端应用程序中保持响应式 UI 非常重要,还可以在 Web 应用程序中增加吞吐量,在 Web 应用程序中释放线程来为 Web 应用程序中的其他请求提供服务。
在 .NET 标准之后,EF Core 为执行 I/O 的所有同步方法提供异步对应项。 这些效果与同步方法相同,可与 C# async
和 await
关键字一起使用。 例如,不使用在执行数据库 I/O 时将阻塞线程的 DbContext.SaveChanges,而是改为使用 DbContext.SaveChangesAsync:
var blog = new Blog { Url = "http://sample.com" };
context.Blogs.Add(blog);
await context.SaveChangesAsync();
有关详细信息,请参阅 常规 C# 异步编程文档。
警告
EF Core 不支持在同一上下文实例上运行多个并行作。 在开始下一个操作之前,您应始终等待当前操作完成。 这通常是通过在每个异步操作上使用 await
关键字来完成的。
警告
遗憾的是,Microsoft.Data.SqlClient 的异步实现存在一些已知问题(例如 #593、#601等)。 如果看到意外的性能问题,请尝试改用同步命令执行,尤其是在处理大型文本或二进制值时。
说明
EF Core 将取消令牌传递到正在使用的基础数据库提供程序(例如Microsoft.Data.SqlClient)。 这些令牌可能会被接受,也可能不会——请查阅数据库供应商的文档。
异步 LINQ 运算符
为了支持异步执行 LINQ 查询,EF Core 提供了一组异步扩展方法,用于执行查询和返回结果。 这些与标准、同步 LINQ 运算符的对应项包括 ToListAsync、SingleAsync、AsAsyncEnumerable等:
var blogs = await context.Blogs.Where(b => b.Rating > 3).ToListAsync();
请注意,某些 LINQ 运算符(如 Where 或 OrderBy)没有异步版本,因为这些运算符只生成 LINQ 表达式树,并且不会导致查询在数据库中执行。 只有导致查询执行的运算符具有异步对应项。
重要
EF Core 异步扩展方法在 Microsoft.EntityFrameworkCore
命名空间中定义。 必须导入此命名空间才能使方法可用。
客户端异步 LINQ 运算符
在某些情况下,可能需要将客户端 LINQ 运算符应用于从数据库返回的结果;这是必需的,尤其是在需要执行无法转换为 SQL 的作时。 对于此类情况,请使用 AsAsyncEnumerable 对数据库执行查询,并通过生成的 IAsyncEnumerable<T>继续编写客户端 LINQ 运算符。 例如,下面对 EF LINQ 查询的异步结果执行本地 .NET 函数:
var blogs = context.Blogs
.Where(b => b.Rating > 3) // server-evaluated (translated to SQL)
.AsAsyncEnumerable()
.Where(b => SomeLocalFunction(b)); // client-evaluated (in .NET)
await foreach (var blog in blogs)
{
// ...
}
说明
.NET 10 中引入了超过 IAsyncEnumerable<T> 的 LINQ 运算符。 使用旧版 .NET 时,引用 System.Linq.Async
包。