Skip to main content

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();
}
}

添加

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 优化只读查询
  • 使用迁移管理数据库架构
  • 实现仓储和工作单元模式

相关资源