Entity Framework Core 基础
什么是 EF Core?
核心概念
EF Core 是 .NET 的现代对象关系映射器(ORM),支持 LINQ 查询、更改跟踪、更新和架构迁移。
快速开始
安装NuGet包
# SQL Server
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
# MySQL
dotnet add package Pomelo.EntityFrameworkCore.MySql
# PostgreSQL
dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL
# SQLite
dotnet add package Microsoft.EntityFrameworkCore.Sqlite
# 工具包
dotnet add package Microsoft.EntityFrameworkCore.Tools
dotnet add package Microsoft.EntityFrameworkCore.Design
定义实体
Models/User.cs
public class User
{
public int Id { get; set; }
public string Username { get; set; }
public string Email { get; set; }
public DateTime CreatedAt { get; set; }
// 导航属性
public List<Order> Orders { get; set; }
}
public class Order
{
public int Id { get; set; }
public decimal Amount { get; set; }
public DateTime OrderDate { get; set; }
// 外键
public int UserId { get; set; }
public User User { get; set; }
}
创建 DbContext
Data/ApplicationDbContext.cs
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<User> Users { get; set; }
public DbSet<Order> Orders { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// 配置实体
modelBuilder.Entity<User>(entity =>
{
entity.ToTable("Users");
entity.HasKey(e => e.Id);
entity.Property(e => e.Username).IsRequired().HasMaxLength(50);
entity.Property(e => e.Email).IsRequired().HasMaxLength(100);
entity.HasIndex(e => e.Email).IsUnique();
});
modelBuilder.Entity<Order>(entity =>
{
entity.ToTable("Orders");
entity.HasKey(e => e.Id);
entity.Property(e => e.Amount).HasColumnType("decimal(18,2)");
// 配置关系
entity.HasOne(e => e.User)
.WithMany(u => u.Orders)
.HasForeignKey(e => e.UserId)
.OnDelete(DeleteBehavior.Cascade);
});
}
}
注册 DbContext
Program.cs
builder.Services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseSqlServer(
builder.Configuration.GetConnectionString("DefaultConnection"),
sqlOptions =>
{
sqlOptions.EnableRetryOnFailure(
maxRetryCount: 3,
maxRetryDelay: TimeSpan.FromSeconds(30),
errorNumbersToAdd: null);
});
// 开发环境启用敏感数据记录
if (builder.Environment.IsDevelopment())
{
options.EnableSensitiveDataLogging();
options.EnableDetailedErrors();
}
});
CRUD 操作
查询
- 基础查询
- 关联查询
- 投影查询
public class UserRepository
{
private readonly ApplicationDbContext _context;
public UserRepository(ApplicationDbContext context)
{
_context = context;
}
// 获取所有用户
public async Task<List<User>> GetAllAsync()
{
return await _context.Users.ToListAsync();
}
// 根据ID获取
public async Task<User> GetByIdAsync(int id)
{
return await _context.Users.FindAsync(id);
}
// 条件查询
public async Task<List<User>> GetActiveUsersAsync()
{
return await _context.Users
.Where(u => u.IsActive)
.ToListAsync();
}
// 分页查询
public async Task<List<User>> GetPagedAsync(int page, int pageSize)
{
return await _context.Users
.OrderBy(u => u.CreatedAt)
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToListAsync();
}
}
// Include: 加载关联数据
public async Task<User> GetUserWithOrdersAsync(int userId)
{
return await _context.Users
.Include(u => u.Orders)
.FirstOrDefaultAsync(u => u.Id == userId);
}
// ThenInclude: 多级关联
public async Task<User> GetUserWithOrderDetailsAsync(int userId)
{
return await _context.Users
.Include(u => u.Orders)
.ThenInclude(o => o.OrderItems)
.FirstOrDefaultAsync(u => u.Id == userId);
}
// 筛选关联数据 (EF Core 5.0+)
public async Task<User> GetUserWithRecentOrdersAsync(int userId)
{
return await _context.Users
.Include(u => u.Orders.Where(o => o.OrderDate >= DateTime.Now.AddDays(-30)))
.FirstOrDefaultAsync(u => u.Id == userId);
}
// 投影到匿名类型
var users = await _context.Users
.Select(u => new
{
u.Id,
u.Username,
OrderCount = u.Orders.Count()
})
.ToListAsync();
// 投影到 DTO
public class UserDto
{
public int Id { get; set; }
public string Username { get; set; }
public int OrderCount { get; set; }
}
var users = await _context.Users
.Select(u => new UserDto
{
Id = u.Id,
Username = u.Username,
OrderCount = u.Orders.Count()
})
.ToListAsync();
添加
public async Task<User> AddAsync(User user)
{
_context.Users.Add(user);
await _context.SaveChangesAsync();
return user;
}
// 批量添加
public async Task AddRangeAsync(List<User> users)
{
_context.Users.AddRange(users);
await _context.SaveChangesAsync();
}
更新
// 方式1: 查询后更新
public async Task UpdateAsync(int userId, string newEmail)
{
var user = await _context.Users.FindAsync(userId);
if (user != null)
{
user.Email = newEmail;
await _context.SaveChangesAsync();
}
}
// 方式2: 直接附加并标记为已修改
public async Task UpdateDirectlyAsync(User user)
{
_context.Users.Update(user);
await _context.SaveChangesAsync();
}
// 方式3: 部分更新
public async Task UpdateEmailAsync(int userId, string newEmail)
{
var user = new User { Id = userId };
_context.Users.Attach(user);
user.Email = newEmail;
_context.Entry(user).Property(u => u.Email).IsModified = true;
await _context.SaveChangesAsync();
}
删除
// 方式1: 查询后删除
public async Task DeleteAsync(int userId)
{
var user = await _context.Users.FindAsync(userId);
if (user != null)
{
_context.Users.Remove(user);
await _context.SaveChangesAsync();
}
}
// 方式2: 直接删除(不查询)
public async Task DeleteDirectlyAsync(int userId)
{
var user = new User { Id = userId };
_context.Users.Remove(user);
await _context.SaveChangesAsync();
}
// 批量删除 (EF Core 7.0+)
public async Task DeleteInactiveUsersAsync()
{
await _context.Users
.Where(u => !u.IsActive)
.ExecuteDeleteAsync();
}
迁移 (Migrations)
# 添加迁移
dotnet ef migrations add InitialCreate
# 应用迁移
dotnet ef database update
# 回滚迁移
dotnet ef database update PreviousMigrationName
# 移除最后一个迁移
dotnet ef migrations remove
# 生成 SQL 脚本
dotnet ef migrations script
# 查看迁移列表
dotnet ef migrations list
性能优化
1. AsNoTracking
// ✅ 只读查询使用 AsNoTracking
public async Task<List<User>> GetUsersAsync()
{
return await _context.Users
.AsNoTracking()
.ToListAsync();
}
2. 避免 N+1 查询
// ❌ 差: N+1 查询问题
var users = await _context.Users.ToListAsync();
foreach (var user in users)
{
var orders = await _context.Orders
.Where(o => o.UserId == user.Id)
.ToListAsync(); // 每个用户都查询一次
}
// ✅ 好: 使用 Include
var users = await _context.Users
.Include(u => u.Orders)
.ToListAsync();
3. 批量操作
// 使用 EFCore.BulkExtensions
// dotnet add package EFCore.BulkExtensions
await _context.BulkInsertAsync(users);
await _context.BulkUpdateAsync(users);
await _context.BulkDeleteAsync(users);
4. 分页查询
public async Task<PagedResult<User>> GetPagedUsersAsync(int page, int pageSize)
{
var query = _context.Users.AsQueryable();
var totalCount = await query.CountAsync();
var users = await query
.OrderBy(u => u.Id)
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToListAsync();
return new PagedResult<User>
{
Items = users,
TotalCount = totalCount,
Page = page,
PageSize = pageSize
};
}
5. 编译查询
// 定义编译查询
private static readonly Func<ApplicationDbContext, int, Task<User>> _getUserById =
EF.CompileAsyncQuery((ApplicationDbContext context, int id) =>
context.Users.FirstOrDefault(u => u.Id == id));
// 使用编译查询
public async Task<User> GetUserByIdAsync(int id)
{
return await _getUserById(_context, id);
}
最佳实践
EF Core 最佳实践
1. 使用仓储模式
public interface IRepository<T> where T : class
{
Task<T> GetByIdAsync(int id);
Task<List<T>> GetAllAsync();
Task<T> AddAsync(T entity);
Task UpdateAsync(T entity);
Task DeleteAsync(int id);
}
public class Repository<T> : IRepository<T> where T : class
{
protected readonly ApplicationDbContext _context;
protected readonly DbSet<T> _dbSet;
public Repository(ApplicationDbContext context)
{
_context = context;
_dbSet = context.Set<T>();
}
public virtual async Task<T> GetByIdAsync(int id)
{
return await _dbSet.FindAsync(id);
}
public virtual async Task<List<T>> GetAllAsync()
{
return await _dbSet.ToListAsync();
}
// ... 其他方法实现
}
2. 使用工作单元模式
public interface IUnitOfWork : IDisposable
{
IUserRepository Users { get; }
IOrderRepository Orders { get; }
Task<int> SaveChangesAsync();
}
public class UnitOfWork : IUnitOfWork
{
private readonly ApplicationDbContext _context;
public UnitOfWork(ApplicationDbContext context)
{
_context = context;
Users = new UserRepository(context);
Orders = new OrderRepository(context);
}
public IUserRepository Users { get; }
public IOrderRepository Orders { get; }
public async Task<int> SaveChangesAsync()
{
return await _context.SaveChangesAsync();
}
public void Dispose()
{
_context.Dispose();
}
}
3. 配置分离
// 使用 IEntityTypeConfiguration
public class UserConfiguration : IEntityTypeConfiguration<User>
{
public void Configure(EntityTypeBuilder<User> builder)
{
builder.ToTable("Users");
builder.HasKey(e => e.Id);
builder.Property(e => e.Username).IsRequired().HasMaxLength(50);
builder.Property(e => e.Email).IsRequired().HasMaxLength(100);
builder.HasIndex(e => e.Email).IsUnique();
}
}
// 在 DbContext 中应用
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfiguration(new UserConfiguration());
// 或自动应用所有配置
modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
}
总结
关键要点
- EF Core 是强大的 ORM 工具
- 使用 LINQ 进行类型安全的查询
- Include 加载关联数据,避免 N+1
- AsNoTracking 优化只读查询
- 使用迁移管理数据库架构
- 实现仓储和工作单元模式