使用 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 反馈 — 无需本地设置。
此课程中的所有课时
- DbContext 与 DbSet 基础
- 迁移与架构管理
- 使用 EF Core 执行 CRUD 操作
- 关系:一对多与多对多