0Pricing
C# Academy · 课时

使用 EF Core 执行 CRUD 操作

使用 EF Core 的变更跟踪和 SaveChanges 执行创建、读取、更新和删除操作。

使用 EF Core 执行 CRUD 操作 是 CoddyKit 上的免费 C# Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C# Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C# Academy 课程共包含 4 节课。

EF Core 中的增删改查概览

EF Core 通过更改跟踪和 SaveChangesAsync() 的组合,处理增删改查这四类操作——创建、读取、更新、删除。理解更改跟踪器是掌握增删改查的关键。

创建:添加新实体

使用 DbSet.Add() 或 AddAsync() 将实体标记为已添加。调用 SaveChangesAsync() 时,EF Core 会生成 INSERT,并填充自增键。

var order = new Order
{
    CustomerId = 5,
    PlacedAt   = DateTime.UtcNow,
    Status     = OrderStatus.Pending
};

await _db.Orders.AddAsync(order);
await _db.SaveChangesAsync();

Console.WriteLine(order.Id); // populated by DB

添加实体图

通过一次调用添加带有子实体的父实体,会插入整个对象图。EF Core 会自动解析 FK 关系。

var order = new Order
{
    CustomerId = 5,
    PlacedAt   = DateTime.UtcNow,
    Lines      = new List<OrderLine>
    {
        new() { ProductId = 10, Quantity = 2, Price = 49.99m },
        new() { ProductId = 11, Quantity = 1, Price = 19.99m }
    }
};

_db.Orders.Add(order);
await _db.SaveChangesAsync();
// Inserts Order + 2 OrderLines in one transaction

读取:使用 LINQ 查询

EF Core 会将 LINQ 表达式转换为 SQL。使用 Where、Select、OrderBy 等组合查询,然后通过 ToListAsync 或 FirstOrDefaultAsync 将结果具体化。

// Read all pending orders for a customer
var orders = await _db.Orders
    .Where(o => o.CustomerId == 5 && o.Status == OrderStatus.Pending)
    .OrderByDescending(o => o.PlacedAt)
    .Select(o => new OrderSummaryDto
    {
        Id     = o.Id,
        Total  = o.Lines.Sum(l => l.Quantity * l.Price),
        Status = o.Status.ToString()
    })
    .ToListAsync();

读取:查找单个实体

读取单个实体时,可以使用 FindAsync(先检查跟踪器),也可以使用带谓词的 FirstOrDefaultAsync / SingleOrDefaultAsync。

// By PK (checks cache first)
var order = await _db.Orders.FindAsync(orderId);

// By predicate (always hits DB)
var latest = await _db.Orders
    .Where(o => o.CustomerId == 5)
    .OrderByDescending(o => o.PlacedAt)
    .FirstOrDefaultAsync();

更新:更改跟踪

通过 EF Core 加载的实体会被跟踪。直接修改属性,然后调用 SaveChangesAsync()。EF Core 会检测差异并生成最小化的 UPDATE 语句。

var order = await _db.Orders.FindAsync(orderId);
if (order is null) return;

order.Status   = OrderStatus.Shipped;
order.ShippedAt = DateTime.UtcNow;

await _db.SaveChangesAsync();
// UPDATE Orders SET Status=..., ShippedAt=... WHERE Id=orderId

更新:批量更新(EF Core 7+)

ExecuteUpdateAsync 会直接在数据库中更新行,而无需加载实体。对于批量操作,它的效率高得多。

// Mark all overdue orders as Cancelled — no loading needed
await _db.Orders
    .Where(o => o.Status == OrderStatus.Pending
             && o.PlacedAt < DateTime.UtcNow.AddDays(-30))
    .ExecuteUpdateAsync(set => set
        .SetProperty(o => o.Status, OrderStatus.Cancelled)
        .SetProperty(o => o.UpdatedAt, DateTime.UtcNow));

删除:移除单个实体

对已跟踪的实体调用 Remove(),然后调用 SaveChangesAsync()。如果您只有 ID,请先查找实体,或使用 ExecuteDeleteAsync。

var order = await _db.Orders.FindAsync(orderId);
if (order is null) return;

_db.Orders.Remove(order);
await _db.SaveChangesAsync();
// DELETE FROM Orders WHERE Id=orderId

删除:批量删除(EF Core 7+)

ExecuteDeleteAsync 会发出一条 DELETE SQL 语句,而无需加载实体,非常适合批量清理操作。

// Delete all cancelled orders older than 1 year
int deleted = await _db.Orders
    .Where(o => o.Status == OrderStatus.Cancelled
             && o.PlacedAt < DateTime.UtcNow.AddYears(-1))
    .ExecuteDeleteAsync();

Console.WriteLine($"Deleted {deleted} old orders");

事务

单次 SaveChangesAsync 调用中的所有操作都会封装在一个事务中。对于跨越多次保存的多步骤操作,请使用显式事务。

using var transaction = await _db.Database.BeginTransactionAsync();
try
{
    _db.Orders.Add(newOrder);
    await _db.SaveChangesAsync();

    inventory.Stock -= newOrder.Quantity;
    await _db.SaveChangesAsync();

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

实战:完整的增删改查服务

完整的服务会封装所有增删改查操作,进行适当的错误处理,并返回数据传输对象,以避免暴露实体的内部细节。

public async Task<OrderDto> CreateOrderAsync(CreateOrderRequest req)
{
    var order = new Order { CustomerId = req.CustomerId, PlacedAt = DateTime.UtcNow };
    _db.Orders.Add(order);
    await _db.SaveChangesAsync();
    return new OrderDto { Id = order.Id, Status = order.Status.ToString() };
}

public async Task<bool> CancelOrderAsync(int id)
{
    int rows = await _db.Orders
        .Where(o => o.Id == id && o.Status == OrderStatus.Pending)
        .ExecuteUpdateAsync(s =>
            s.SetProperty(o => o.Status, OrderStatus.Cancelled));
    return rows > 0;
}

快速检查

与加载实体并调用 SaveChangesAsync 相比,ExecuteUpdateAsync / ExecuteDeleteAsync 有什么优势?

回顾:使用 EF Core 执行增删改查

核心要点:

  • Add + SaveChangesAsync → INSERT;EF Core 会填充自动生成的键
  • 修改已跟踪实体 + SaveChangesAsync → 最小化 UPDATE
  • Remove + SaveChangesAsync → 删除单个实体时执行 DELETE
  • ExecuteUpdateAsync / ExecuteDeleteAsync → 无需加载实体即可执行批量操作(EF Core 7+)
  • 将多步骤操作封装在显式事务中,以确保原子性

常见问题解答

「使用 EF Core 执行 CRUD 操作」课时是免费的吗?

是的 — 「使用 EF Core 执行 CRUD 操作」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C# Academy 课程的其余内容,请升级到 CoddyKit PRO。 C# Academy 课程共包含 4 节课。

「使用 EF Core 执行 CRUD 操作」这节课中我会学到什么?

使用 EF Core 的变更跟踪和 SaveChanges 执行创建、读取、更新和删除操作。 你通过在浏览器中直接运行的动手代码来练习 C# Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C# Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C# Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「使用 EF Core 执行 CRUD 操作」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C# Academy 课中编写并运行代码吗?

能。每节 C# Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. DbContext 与 DbSet 基础
  2. 迁移与架构管理
  3. 使用 EF Core 执行 CRUD 操作
  4. 关系:一对多与多对多
← 返回 C# Academy