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. 学习资源 ​

最近更新