关于 entity-framework-core
面向 .NET 开发者的 Entity Framework Core 速查技能,介绍 DbContext、实体配置、迁移和 LINQ 查询。内容也包括查询性能建议与常见问题排查。
主要功能
- 01DbContext 配置
- 02Fluent API 实体配置
- 03数据库迁移命令
- 04LINQ 查询与投影
- 05只读和批量操作优化
- 06常见问题排查
适用场景
- 01配置数据库上下文和实体
- 02执行迁移以更新数据库
- 03优化只读查询和批量操作
MCP 相关
提及可通过 `mcp__documentation__fetch_docs` 获取 Entity Framework Core 的深入文档。
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ claude-dev-suite/ claude-dev-suite --skill entity-framework-core安装后在 Claude Code 中输入/entity-framework-core确认已加载。
详细介绍
Entity Framework Core - 快速参考
深入了解:使用
mcp__documentation__fetch_docs,并指定技术:entity-framework-core,获取完整文档。
DbContext 设置
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
public DbSet<User> Users => Set<User>();
public DbSet<Order> Orders => Set<Order>();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfigurationsFromAssembly(typeof(AppDbContext).Assembly);
}
}
// Registration
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("Default")));
实体配置(Fluent API)
public class UserConfiguration : IEntityTypeConfiguration<User>
{
public void Configure(EntityTypeBuilder<User> builder)
{
builder.HasKey(u => u.Id);
builder.Property(u => u.Name).IsRequired().HasMaxLength(100);
builder.Property(u => u.Email).IsRequired().HasMaxLength(255);
builder.HasIndex(u => u.Email).IsUnique();
// Relationships
builder.HasMany(u => u.Orders)
.WithOne(o => o.User)
.HasForeignKey(o => o.UserId)
.OnDelete(DeleteBehavior.Cascade);
// Value conversion
builder.Property(u => u.Status)
.HasConversion<string>();
// Default values
builder.Property(u => u.CreatedAt)
.HasDefaultValueSql("GETUTCDATE()");
}
}
迁移
# Add migration
dotnet ef migrations add InitialCreate
# Update database
dotnet ef database update
# Remove last migration (not applied)
dotnet ef migrations remove
# Generate SQL script
dotnet ef migrations script
# Revert to specific migration
dotnet ef database update MigrationName
LINQ 查询
// Basic queries
var user = await context.Users.FindAsync(id);
var users = await context.Users.Where(u => u.IsActive).ToListAsync();
var user = await context.Users.FirstOrDefaultAsync(u => u.Email == email);
// Projection
var dtos = await context.Users
.Where(u => u.IsActive)
.Select(u => new UserResponse(u.Id, u.Name, u.Email))
.ToListAsync();
// Include related data
var usersWithOrders = await context.Users
.Include(u => u.Orders)
.ThenInclude(o => o.OrderItems)
.ToListAsync();
// Pagination
var page = await context.Users
.OrderBy(u => u.Name)
.Skip((pageNumber - 1) * pageSize)
.Take(pageSize)
.ToListAsync();
// Aggregation
var count = await context.Users.CountAsync(u => u.IsActive);
var avgAge = await context.Users.AverageAsync(u => u.Age);
仓储模式
public interface IRepository<T> where T : class
{
Task<T?> GetByIdAsync(int id);
Task<IEnumerable<T>> GetAllAsync();
Task AddAsync(T entity);
void Update(T entity);
void Remove(T entity);
Task<bool> ExistsAsync(Expression<Func<T, bool>> predicate);
Task SaveChangesAsync();
}
public class Repository<T> : IRepository<T> where T : class
{
protected readonly AppDbContext _context;
protected readonly DbSet<T> _dbSet;
public Repository(AppDbContext context)
{
_context = context;
_dbSet = context.Set<T>();
}
public async Task<T?> GetByIdAsync(int id) => await _dbSet.FindAsync(id);
public async Task<IEnumerable<T>> GetAllAsync() => await _dbSet.ToListAsync();
public async Task AddAsync(T entity) => await _dbSet.AddAsync(entity);
public void Update(T entity) => _dbSet.Update(entity);
public void Remove(T entity) => _dbSet.Remove(entity);
public async Task<bool> ExistsAsync(Expression<Func<T, bool>> predicate)
=> await _dbSet.AnyAsync(predicate);
public async Task SaveChangesAsync() => await _context.SaveChangesAsync();
}
性能提示
| 提示 | 实现方式 |
|---|---|
只读时使用 AsNoTracking() | context.Users.AsNoTracking().ToListAsync() |
使用 Select 投影 | 避免加载完整实体 |
使用 AsSplitQuery() | 防止使用 include 时发生笛卡尔积爆炸 |
| 使用已编译查询 | 在热点路径使用 EF.CompileAsyncQuery(...) |
| 批量操作 | ExecuteUpdateAsync / ExecuteDeleteAsync(EF Core 7+) |
// Bulk update (EF Core 7+)
await context.Users
.Where(u => u.LastLoginAt < cutoff)
.ExecuteUpdateAsync(u => u.SetProperty(x => x.IsActive, false));
// Bulk delete
await context.Users
.Where(u => u.IsDeleted)
.ExecuteDeleteAsync();
反模式
| 反模式 | 问题 | 正确做法 |
|---|---|---|
| 为显示而加载完整实体 | 浪费内存、速度慢 | 使用 Select 投影 |
| N+1 查询 | 严重影响性能 | 使用 Include 或投影 |
未使用 AsNoTracking | 产生不必要的开销 | 用于只读查询 |
每个实体都调用 SaveChanges | 批量操作速度慢 | 完成所有更改后调用一次 |
将 DbContext 用作单例 | 存在线程安全问题 | 使用 AddDbContext(Scoped) |
快速故障排除
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 跟踪冲突 | 实体已被跟踪 | 使用 AsNoTracking 或分离实体 |
| 迁移失败 | 模型不匹配 | 检查待处理的更改,然后重新构建 |
| 查询缓慢 | 缺少索引 | 在配置中添加 HasIndex |
| 延迟加载失败 | 未配置 | 使用 Include(显式加载) |
| 并发冲突 | 数据过时 | 添加 [ConcurrencyCheck] 或 RowVersion |
评论
支持 Markdown