Skip to content

EF Core 入门指南

Entity Framework Core (EF Core) 是微软官方提供的对象关系映射 (ORM) 框架,用于简化 .NET 应用程序与数据库的交互。它支持多种数据库,包括 SQL Server、MySQL、PostgreSQL、SQLite 等。

1. 安装 EF Core

1.1 安装核心包

在项目中安装 EF Core 核心包和相应的数据库提供程序:

bash
# 安装 EF Core 核心包
dotnet add package Microsoft.EntityFrameworkCore

# 安装 SQL Server 提供程序
dotnet add package Microsoft.EntityFrameworkCore.SqlServer

# 安装 MySQL 提供程序(如果使用 MySQL)
dotnet add package Pomelo.EntityFrameworkCore.MySql

# 安装工具包(用于迁移)
dotnet add package Microsoft.EntityFrameworkCore.Design

2. 创建数据模型

2.1 定义实体类

csharp
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

public class Product
{
    [Key]
    public int ProductId { get; set; }
    
    [Required]
    [StringLength(100)]
    public string Name { get; set; }
    
    [Column(TypeName = "decimal(18,2)")]
    public decimal Price { get; set; }
    
    public string Description { get; set; }
    
    public bool IsActive { get; set; }
    
    public DateTime CreatedAt { get; set; } = DateTime.Now;
}

public class Category
{
    [Key]
    public int CategoryId { get; set; }
    
    [Required]
    [StringLength(50)]
    public string Name { get; set; }
    
    // 导航属性 - 一对多关系
    public ICollection<Product> Products { get; set; }
}

3. 创建数据上下文

3.1 定义 DbContext

csharp
using Microsoft.EntityFrameworkCore;

public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
    {}
    
    // DbSet 属性 - 对应数据库表
    public DbSet<Product> Products { get; set; }
    public DbSet<Category> Categories { get; set; }
    
    // 配置模型关系(可选)
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // 配置 Category 和 Product 的一对多关系
        modelBuilder.Entity<Category>()
            .HasMany(c => c.Products)
            .WithOne()
            .HasForeignKey("CategoryId");
        
        // 其他配置...
    }
}

4. 配置 EF Core

4.1 在 Program.cs 中配置

csharp
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

// 配置数据库连接字符串
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");

// 注册 DbContext
builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(connectionString));

var app = builder.Build();
// ...

4.2 在 appsettings.json 中配置连接字符串

json
{
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=MyDatabase;Trusted_Connection=True;"
  }
}

5. 数据库迁移

5.1 创建迁移

bash
dotnet ef migrations add InitialCreate

5.2 应用迁移

bash
dotnet ef database update

5.3 移除迁移

bash
dotnet ef migrations remove

6. 基本 CRUD 操作

6.1 插入数据

csharp
using var context = new AppDbContext();

// 创建新分类
var category = new Category { Name = "电子产品" };
context.Categories.Add(category);

// 创建新产品
var product = new Product
{
    Name = "智能手机",
    Price = 2999.99M,
    Description = "高性能智能手机",
    IsActive = true
};
context.Products.Add(product);

// 保存更改
await context.SaveChangesAsync();

6.2 查询数据

csharp
using var context = new AppDbContext();

// 查询所有产品
var allProducts = await context.Products.ToListAsync();

// 条件查询
var activeProducts = await context.Products
    .Where(p => p.IsActive && p.Price > 1000)
    .ToListAsync();

// 包含关联数据(Eager Loading)
var productsWithCategories = await context.Products
    .Include(p => p.Category)
    .ToListAsync();

// 分页查询
var page = 1;
var pageSize = 10;
var pagedProducts = await context.Products
    .Skip((page - 1) * pageSize)
    .Take(pageSize)
    .ToListAsync();

6.3 更新数据

csharp
using var context = new AppDbContext();

// 查找产品
var product = await context.Products.FindAsync(1);
if (product != null)
{
    // 更新属性
    product.Price = 2799.99M;
    product.IsActive = false;
    
    // 保存更改
    await context.SaveChangesAsync();
}

6.4 删除数据

csharp
using var context = new AppDbContext();

// 查找产品
var product = await context.Products.FindAsync(1);
if (product != null)
{
    // 删除产品
    context.Products.Remove(product);
    
    // 保存更改
    await context.SaveChangesAsync();
}

7. 查询优化

7.1 延迟加载(Lazy Loading)

bash
# 安装延迟加载包
dotnet add package Microsoft.EntityFrameworkCore.Proxies
csharp
// 在配置中启用延迟加载
builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(connectionString)
           .UseLazyLoadingProxies());

7.2 显式加载(Explicit Loading)

csharp
using var context = new AppDbContext();

var product = await context.Products.FindAsync(1);

// 显式加载分类
await context.Entry(product).Reference(p => p.Category).LoadAsync();

// 显式加载集合
await context.Entry(category).Collection(c => c.Products).LoadAsync();

7.3 投影查询

csharp
// 只查询需要的字段
var productSummaries = await context.Products
    .Select(p => new
    {
        p.ProductId,
        p.Name,
        p.Price
    })
    .ToListAsync();

8. 高级特性

8.1 事务管理

csharp
using var context = new AppDbContext();
using var transaction = await context.Database.BeginTransactionAsync();

try
{
    // 执行多个操作
    context.Products.Add(newProduct);
    context.Categories.Add(newCategory);
    
    await context.SaveChangesAsync();
    await transaction.CommitAsync();
}
catch (Exception)
{
    await transaction.RollbackAsync();
    throw;
}

8.2 原生 SQL 查询

csharp
// 执行原生 SQL 查询
var products = await context.Products
    .FromSqlRaw("SELECT * FROM Products WHERE Price > {0}", 1000)
    .ToListAsync();

// 执行非查询 SQL
await context.Database.ExecuteSqlRawAsync("UPDATE Products SET IsActive = 0 WHERE CreatedAt < {0}", DateTime.Now.AddYears(-1));

9. 最佳实践

  1. 使用依赖注入:在 ASP.NET Core 应用中,始终通过依赖注入使用 DbContext
  2. ** DbContext 是轻量级的**:每个请求创建一个新的 DbContext 实例
  3. 使用异步方法:优先使用 Async 版本的方法(如 SaveChangesAsync)
  4. 合理使用加载策略
    • Eager Loading:使用 Include 预加载所需的关联数据
    • Lazy Loading:谨慎使用,避免 N+1 查询问题
    • Explicit Loading:仅在必要时加载关联数据
  5. 使用投影:只查询需要的字段,减少数据传输
  6. 批量操作:对于大量数据操作,考虑使用 AddRange/RemoveRange
  7. 迁移管理:使用迁移管理数据库架构变更
  8. 性能监控:使用 EF Core Profiler 等工具监控查询性能

10. 学习资源

最近更新