当前位置: 首页 > news >正文

EF Core 异步方法

文章目录

  • 前言
  • 一、为什么使用异步方法
  • 二、核心异步方法
    • 1)查询数据
    • 2)保存数据
    • 3)事务处理
  • 三、异步查询最佳实践
    • 1)始终使用 await
    • 2)组合异步操作
    • 3)并行查询(谨慎使用)
  • 四、异常处理
  • 五、性能注意事项
    • 1)DbContext 生命周期
    • 2)取消操作支持
    • 3)禁用跟踪(只读场景)
  • 六、常见错误
    • 1)混合同步/异步调用
    • 2)未正确处理上下文
  • 七、高级模式
    • 1)批量操作
    • 2)原始 SQL 查询
  • 总结
    • EF Core 的异步方法通过以下方式提升性能:
    • 关键要点:


前言

在 Entity Framework Core 中,异步方法是优化数据库操作性能、避免阻塞线程的关键工具,特别适用于 Web 应用、API 或其他高并发场景。


一、为什么使用异步方法

  1. 避免线程阻塞:异步操作释放当前线程(如 ASP.NET 的请求线程),提高吞吐量。
  2. 提升响应性:在 UI 应用(如 WPF、MAUI)中防止界面卡死。
  3. 高效利用资源:适合长时间运行的数据库操作(如复杂查询、批量写入)。

二、核心异步方法

EF Core 为常见操作提供了异步版本,需结合 async/await 使用:

1)查询数据

  1. ToListAsync():异步返回列表
  2. FirstOrDefaultAsync():异步获取首个匹配项
  3. SingleOrDefaultAsync():异步获取唯一匹配项
  4. CountAsync():异步统计数量
  5. AnyAsync():异步检查是否存在
public async Task<List<Person>> GetActivePersonsAsync()
{
    using var context = new MyDbContext();
    return await context.Persons
        .Where(u => u.Name=="Tom")
        .ToListAsync(); // 异步执行查询
}

2)保存数据

  1. SaveChangesAsync():异步提交更改
  2. AddAsync():异步添加单个实体(通常用于值生成策略)
public async Task CreatePersonsAsync(Person person)
{
    using var context = new MyDbContext();
    await context.Persons.AddAsync(person); // 异步添加
    await context.SaveChangesAsync();    // 异步提交
}

3)事务处理

public async Task TransferMoneyAsync(int fromId, int toId, decimal amount)
{
    using var context = new MyDbContext();
    using var transaction = await context.Database.BeginTransactionAsync();

    try
    {
        var fromAccount = await context.Accounts.FindAsync(fromId);
        var toAccount = await context.Accounts.FindAsync(toId);

        fromAccount.Balance -= amount;
        toAccount.Balance += amount;

        await context.SaveChangesAsync();
        await transaction.CommitAsync();
    }
    catch
    {
        await transaction.RollbackAsync();
        throw;
    }
}

三、异步查询最佳实践

1)始终使用 await

// ✅ 正确
var persons = await context.Persons.ToListAsync();

// ❌ 错误(立即阻塞线程)
var persons = context.Persons.ToListAsync().Result;

2)组合异步操作

public async Task<Person> GetPersonWithOrdersAsync(int personId)
{
    return await context.Persons
        .Include(u => u.Orders)
        .FirstOrDefaultAsync(u => u.Id == personId);
}

3)并行查询(谨慎使用)

var task1 = context.Persons.CountAsync();
var task2 = context.Orders.CountAsync();

await Task.WhenAll(task1, task2);

var totalPersons = task1.Result;
var totalOrders = task2.Result;

四、异常处理

try
{
    await context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException ex)
{
    // 处理并发冲突
}
catch (DbUpdateException ex)
{
    // 处理更新错误
}

五、性能注意事项

1)DbContext 生命周期

  1. 确保在 using 块或依赖注入范围内使用,避免内存泄漏。

2)取消操作支持

  1. 多数异步方法接受 CancellationToken

    var cts = new CancellationTokenSource();
    var users = await context.Persons
        .ToListAsync(cts.Token);
    

3)禁用跟踪(只读场景)

var persons = await context.Persons
    .AsNoTracking()
    .ToListAsync();

六、常见错误

1)混合同步/异步调用

// ❌ 危险!可能导致死锁
public Person GetPerson(int id)
{
    return context.Persons.FirstOrDefaultAsync(u => u.Id == id).Result;
}

错误修正(修正为异步方法)

  1. 始终优先使用 async/await,避免 .Result 或 .Wait()
public async Task<Person> GetPersonAsync(int id)
{
    return await context.Persons.FirstOrDefaultAsync(u => u.Id == id);
}

2)未正确处理上下文

// ❌ 上下文可能被提前释放
public async Task<List<Person>> GetPersonsAsync()
{
    using var context = new MyDbContext();
    return await context.Persons.ToListAsync(); 
} // 上下文在此处释放,返回的实体可能无法延迟加载

错误修正(将原始代码改为安全模式)

  1. 优先使用 DTO 或投影
    避免直接返回实体,尤其是在 Web API 中。
  2. 明确加载关联数据
    使用 IncludeSelect 确保所有需要的数据已加载。
  3. 默认禁用跟踪
    在只读场景中,始终使用 AsNoTracking 提升性能。
  4. 严格管理 DbContext 生命周期
    Web 应用中,通过依赖注入(Scoped 生命周期)管理 DbContext
    桌面应用中,确保 DbContext 生命周期与 UI 操作同步。
// ✅ 安全:返回 DTO,无需延迟加载
public async Task<List<PersonDto>> GetPersonsAsync()
{
    using var context = new MyDbContext();
    return await context.Persons
        .Select(p => new PersonDto 
        {
            Id = p.Id,
            Name = p.Name
        })
        .AsNoTracking()
        .ToListAsync(); 
}

七、高级模式

1)批量操作

await context.BulkInsertAsync(entities); // 使用 EF Plus 等扩展库

2)原始 SQL 查询

var persons = await context.Persons
    .FromSqlInterpolated("SELECT * FROM T_Persons WHERE Age > {0}", 18)
    .ToListAsync();

总结

EF Core 的异步方法通过以下方式提升性能:

  1. 减少线程阻塞
  2. 提高服务器吞吐量
  3. 优化资源利用率

关键要点:

  1. 始终 await 异步方法
  2. 正确处理上下文生命周期
  3. 结合 CancellationToken 实现可控取消
  4. 避免混合同步/异步代码

相关文章:

  • 高性能 Android 自定义 View:数据渲染与事件分发的双重优化
  • @Resource 与 @Autowired:Spring 中的依赖注入注解大比拼
  • gz sim机器人SDF模型 [持续更新]
  • trino查询mysql报Unknown or incorrect time zone: ‘Asia/Shanghai‘
  • Maven插件学习(一)——生成可执行的 JAR 文件
  • Redis集群哨兵相关面试题
  • SSM驾校预约管理系统
  • 【开题报告+论文+源码】基于SpringBoot的智能安全与急救知识科普系统设计与实现
  • 字节跳动前端开发实习生面试总结
  • Pytorch学习笔记(一)Learn the Basics - Quickstart
  • 辉视智慧会所:一键“唤”醒高端服务,乐享智慧生活新“声”级!
  • 动态规划 力扣hot100热门面试算法题 面试基础 核心思路 背题
  • 2024Android高频精选面试题讲解,程序人生
  • 协作机械臂需要加安全墙吗? 安全墙 光栅 干涉区
  • docker安装hyperf环境,连接本机redis问题处理
  • 9.4分漏洞!Next.js Middleware鉴权绕过漏洞安全风险通告
  • 多Agent系统,其中用户可以 自由选择不同Agent
  • redis与数据库双写一致性解决方案
  • pyqt SQL Server 数据库查询-优化
  • Vite管理的Vue3项目中monaco editer的使用以及组件封装
  • 网站服务费网络建设会计分录/互动营销案例分析
  • 小程序源码在哪个平台购买/企业网站seo方案案例
  • 做外贸去哪些网站找老外/网店运营培训
  • 南阳商都网站做网站/电商怎么做?如何从零开始学做电商赚钱
  • 网站上的文章做参考文献/万能软文范例800字
  • 做b2b b2c型的混合网站/百度极速版下载安装最新版