跳转到主要内容
杨月昌的软件博客
返回

深入浅出 EF Core 的 CRUD 操作(增删改查)

Entity Framework Core (EF Core) 作为 .NET 开发者最常用的 ORM 框架,其核心魅力在于将复杂的 SQL 操作抽象为对内存中“实体对象”的操作。本文将带大家深入了解如何执行高效的增删改查(CRUD),并剖析其底层的状态管理机制

一、 EF Core 核心:实体状态机

在深入操作前,必须理解 EF Core 是如何感知数据变化的。每一个被 DbContext 加载的实体都有一个 EntityState


二、 数据新增操作 (Create)

使用 EF Core 插入数据时,推荐始终使用异步方法以提高系统吞吐量。

public async Task InsertAsync()
{
    using var context = new MyDbContext();
    
    // 1. 业务逻辑判断
    if (await context.TestTables.AnyAsync(p => p.Id == 1)) return;

    // 2. 构造实体(此时状态为 Detached)
    var newEntity = new TestTable
    {
        Name = "新数据条目"
    };

    // 3. 将状态标记为 Added
    await context.TestTables.AddAsync(newEntity); 
    
    // 4. 持久化(将内存变更转换为 SQL 事务执行)
    await context.SaveChangesAsync();
}

⚡ 避坑指南: > * 不要在方法签名中使用 async void(除非是事件处理),应使用 async Task

  • AddAsync 仅在特殊场景(如使用某些 HiLo 自增序列)才真正需要异步。对于大多数情况,直接使用 context.Add() 也是可以的,因为它只操作内存。


三、 数据查询操作 (Read)

EF Core 提供了跟踪查询(默认)与非跟踪查询

1. 跟踪查询 (Tracking)

默认情况下,EF Core 会在“快照”中记录查询到的实体。

var entities = await context.TestTables.ToListAsync();

2. 非跟踪查询 (No-Tracking)

如果你只是展示数据,不打算修改,必须使用 AsNoTracking()。它能显著降低内存开销并提升查询速度,因为它跳过了状态跟踪逻辑。

var readOnlyList = await context.TestTables
    .AsNoTracking()
    .Where(p => p.Id > 10)
    .ToListAsync();

四、 数据更新操作 (Update)

EF Core 的更新是基于“变化检测”的。

public async Task UpdateAsync(int id)
{
    using var context = new MyDbContext();
    
    // 1. 先追踪:从数据库获取原始数据
    var entity = await context.TestTables.FindAsync(id);
    
    if (entity != null)
    {
        // 2. 修改属性:EF Core 会自动将状态改为 Modified
        entity.Name = "更新后的名称";
        
        // 3. 提交:仅会更新发生变化的列
        await context.SaveChangesAsync();
    }
}

💡 原理小贴士:当调用 SaveChangesAsync 时,EF Core 会对比当前实体与查询时的“初始快照”,只针对有差异的字段生成 UPDATE 语句。


五、 数据删除操作 (Delete)

1. 常规删除(查 -> 删)

var entity = await context.TestTables.FindAsync(id);
if (entity != null)
{
    context.TestTables.Remove(entity);
    await context.SaveChangesAsync();
}

2. 高级技巧:无查询删除(仅通过主键)

如果你已知 ID,且不想额外消耗一次数据库查询请求,可以伪造一个“已附加”的对象:

var entity = new TestTable { Id = 1 }; // 仅需主键
context.Entry(entity).State = EntityState.Deleted; // 直接标记状态
await context.SaveChangesAsync();

六、 总结与最佳实践

为了写出高性能、可维护的 EF Core 代码,请参考以下建议:

操作最佳实践
查询纯展示页面务必带上 .AsNoTracking()
性能批量操作(如一次增删上千条)应考虑 ExecuteUpdateAsyncExecuteDeleteAsync(EF Core 7.0+ 引入)。
事务SaveChangesAsync 默认带有事务。如需跨 Context 事务,请使用 IDbContextTransaction
异步始终优先使用 ToListAsyncFirstOrDefaultAsync 等异步扩展方法。


上一篇
WPF 实战指南:从零构建工业级登录系统
下一篇
基于 Selenium 和 PyQuery 爬取淘宝数据:全自动无头模式实战