【EF Core】1. 基本概念、使用方法

本系列专栏基于杨中科老师的《ASP.NET Core技术内幕与项目实战》,本人记录梳理的学习笔记,有部分的增补和省略。更全面系统的讲解,请看杨老师的视频课:【.NET教程,.Net Core视频教程,杨中科主讲】

一、基本概念

1. 定义

Entity Framework Core(简称 EF Core)是 .NET 平台下轻量级、跨平台、开源的对象关系映射(ORM)框架,由 Microsoft 官方开发和维护。它的核心价值是实现「对象」与「关系型数据库」的解耦:开发者只需操作 .NET 实体对象,EF Core 会自动将对象操作转换为对应的 SQL 语句,无需手动编写大量原生 SQL。

EF Core 支持主流数据库(SQL Server、MySQL、PostgreSQL、SQLite、Oracle 等),是 .NET 生态中最主流的 ORM 工具,尤其与 ASP.NET Core 深度集成。

核心优势:
  • 提高开发效率:消除数据访问层的样板代码,专注业务逻辑开发
  • 强类型查询:基于 LINQ 的查询语法,编译期即可发现语法错误(对比字符串拼接 SQL 的运行时错误)
  • 数据库迁移:自动化管理数据库结构变更(新增字段、修改类型、删除表等),支持回滚
  • 跨平台兼容:可运行在 Windows、Linux、macOS 等系统,适配 .NET Core/.NET 5+ 全版本
  • 生态深度集成:原生支持依赖注入、异步编程、ASP.NET Core 等 .NET 核心特性
  • 变更追踪:自动跟踪实体对象的状态变化(新增 / 修改 / 删除),无需手动标记

2. 与主流 ORM 框架对比

ORM 框架定位核心优势核心劣势适用场景
EF Core全功能官方 ORMLINQ 支持、自动迁移、变更追踪、多数据库兼容复杂查询性能略逊于微 ORM、学习成本稍高企业级项目、CRUD 逻辑复杂、架构清晰的场景
Dapper轻量级微 ORM性能接近原生、ADO.NET、完全控制 SQL、体积小无自动迁移、无变更追踪、需手动映射关联高并发、性能敏感、需精准控制 SQL 的场景
SqlSugar/FreeSql国内开源轻量 ORM语法简洁、上手快、文档友好、功能全面生态不如官方完善、大型项目验证度稍低中小型项目、快速开发、多数据库兼容场景
补充说明:
  • EF Core 并非「性能差」,而是「封装度高」:简单 CRUD 性能与 Dapper 差距极小,仅在超复杂查询 / 海量数据操作时需手动优化(如原生 SQL 拼接、索引优化);
  • SqlSugar/FreeSql 是国内社区的优秀产物,兼顾 EF Core 的易用性和 Dapper 的轻量,适合中小团队快速落地。

二、EF Core 基础使用方法

Code First 是 EF Core 最常用的开发模式:先编写 .NET 实体类,再通过 EF Core 自动生成数据库表结构。

1. 环境准备(安装依赖包)

根据目标数据库选择对应的 NuGet 包,以 SQL Server 为例,在命令行:

# 核心包:EF Core 核心功能 + SQL Server 驱动
Install-Package Microsoft.EntityFrameworkCore.SqlServer
# 工具包:支持迁移、数据库更新等命令
Install-Package Microsoft.EntityFrameworkCore.Tools
# 可选:可视化设计器(按需安装)
Install-Package Microsoft.EntityFrameworkCore.Design

2. 编写实体类(Entity)

实体类对应数据库中的表,属性对应表的字段,EF Core 遵循「约定大于配置」原则(如 Id 会自动识别为主键)。

// 书籍实体
public class Book
{
    // 主键(约定:Id 或 BookId 会被自动识别为主键)
    public long Id { get; set; }
    // 书籍标题
    public string Title { get; set; }
    // 发布时间
    public DateTime PubTime { get; set; }
    // 价格
    public double Price { get; set; }
    // 可选字段(演示可空属性)
    public string? AuthorName { get; set; }
}

// 人员实体
public class Person
{
    public long Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    // 新增字段(演示迁移场景)
    public DateTime? BirthDate { get; set; }
}

3. 编写实体配置类(可选,精细化配置)

当需要打破「约定」时(如自定义表名、字段长度、非空约束),通过 IEntityTypeConfiguration<T> 配置实体映射规则,相比特性(Attribute)更易维护。

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

// 书籍实体配置
public class BookEntityConfig : IEntityTypeConfiguration<Book>
{
    public void Configure(EntityTypeBuilder<Book> builder)
    {
        // 自定义表名(默认表名是实体类名复数:Books)
        builder.ToTable("T_Books");
        // 配置字段约束:标题最大长度50,非空
        builder.Property(e => e.Title)
               .HasMaxLength(50)
               .IsRequired();
        // 配置价格精度(避免浮点数精度问题)
        builder.Property(e => e.Price)
               .HasColumnType("decimal(18,2)");
    }
}

// 人员实体配置
public class PersonEntityConfig : IEntityTypeConfiguration<Person>
{
    public void Configure(EntityTypeBuilder<Person> builder)
    {
        builder.ToTable("T_Persons");
        // 姓名非空,最大长度20
        builder.Property(e => e.Name)
               .HasMaxLength(20)
               .IsRequired();
        // 年龄范围限制
        builder.Property(e => e.Age)
               .HasCheckConstraint("CK_Person_Age", "Age >= 0 AND Age <= 150");
    }
}

4. 编写 DbContext 类(核心:数据库上下文)

DbContext 是 EF Core 的核心类,相当于「数据库会话」:管理实体与数据库的映射、数据库连接、变更追踪、查询执行等。

using Microsoft.EntityFrameworkCore;

public class TestDbContext : DbContext
{
    // 声明 DbSet<T>:表示数据库中的对应表(EF Core 据此识别实体)
    public DbSet<Book> Books { get; set; }
    public DbSet<Person> Persons { get; set; } 

    // 配置数据库连接
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        base.OnConfiguring(optionsBuilder);
        // SQL Server 连接字符串(根据自己的数据库地址修改)
        string connStr = "Server=.;Database=EFTestDemo;Trusted_Connection=True;MultipleActiveResultSets=true;TrustServerCertificate=True";
        // 指定使用 SQL Server 数据库
        optionsBuilder.UseSqlServer(connStr);
        // 可选:开发环境打印生成的 SQL(调试用)
        // optionsBuilder.LogTo(Console.WriteLine);
    }

    // 加载实体配置类
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        // 自动加载当前程序集中所有实现 IEntityTypeConfiguration<T> 的配置类
        modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);
    }
}

5. 生成 / 更新数据库(迁移命令)

EF Core 的「迁移(Migration)」是管理数据库结构变更的核心功能,所有表结构修改都通过迁移命令同步到数据库。

第一步:初始化迁移(首次生成数据库)

打开「Visual Studio → 工具 → NuGet 包管理器 → 程序包管理器控制台(PMC)」,执行:

# 创建迁移文件(InitialCreate 是迁移名称,建议语义化命名)
Add-Migration InitialCreate
# 将迁移应用到数据库(自动创建数据库 + 表)
Update-Database
第二步:修改表结构(新增字段 / 修改约束)
  1. 先修改实体类 / 配置类(如给 Person 新增 BirthDate 字段);
  2. 执行迁移命令,在命令行:
# 创建新的迁移文件(记录结构变更)
Add-Migration AddPersonBirthDate
# 同步到数据库
Update-Database
迁移常用补充命令:

在命令行:

# 查看迁移历史
Get-Migration
# 回滚上一次迁移
Update-Database -Migration InitialCreate
# 删除最近一次未应用的迁移文件
Remove-Migration

6. 核心 CRUD 操作(业务代码)

EF Core 支持同步 / 异步两种操作方式,推荐优先使用异步(避免阻塞线程),所有操作需通过 SaveChanges/SaveChangesAsync 提交到数据库。

using System.Linq;
using System.Threading.Tasks;

class EFCRUDExample
{
    // 新增数据
    public static async Task AddData()
    {
        // 使用 using 自动释放 DbContext 资源
        using (var ctx = new TestDbContext())
        {
            var book = new Book
            {
                Title = "数学之美",
                PubTime = new DateTime(2020, 1, 1),
                Price = 49.9,
                AuthorName = "吴军"
            };
            // 将实体加入上下文(标记为新增状态)
            ctx.Books.Add(book);
            // 提交变更(生成 INSERT 语句)
            await ctx.SaveChangesAsync();
            Console.WriteLine($"新增书籍 ID:{book.Id}");
        }
    }

    // 删除数据
    public static async Task DeleteData()
    {
        using (var ctx = new TestDbContext())
        {
            // 先查询要删除的实体
            var book = await ctx.Books.SingleOrDefaultAsync(b => b.Title == "数学之美");
            if (book != null)
            {
                // 标记为删除状态
                ctx.Books.Remove(book);
                // 提交变更(生成 DELETE 语句)
                await ctx.SaveChangesAsync();
                Console.WriteLine("删除成功");
            }
        }
    }

    // 修改数据
    public static async Task UpdateData()
    {
        using (var ctx = new TestDbContext())
        {
            // 先查询实体
            var book = await ctx.Books.SingleOrDefaultAsync(b => b.Title == "数学之美");
            if (book != null)
            {
                // 直接修改属性(EF Core 自动追踪变更)
                book.Price = 59.9;
                book.AuthorName = "Jun Wu";
                // 提交变更(生成 UPDATE 语句)
                await ctx.SaveChangesAsync();
                Console.WriteLine("修改成功");
            }
        }
    }

    // 查询数据(LINQ 语法)
    public static async Task QueryData()
    {
        using (var ctx = new TestDbContext())
        {
            // 1. 基础查询:价格大于80的书籍
            var expensiveBooks = ctx.Books.Where(b => b.Price > 80);
            // 2. 排序:按价格升序
            var sortedBooks = ctx.Books.OrderBy(b => b.Price);
            // 3. 分组:按作者分组,统计书籍数量和最高价格
            var authorGroup = ctx.Books
                                 .GroupBy(b => b.AuthorName)
                                 .Select(g => new 
                                 {
                                     AuthorName = g.Key,
                                     BookCount = g.Count(),
                                     MaxPrice = g.Max(b => b.Price)
                                 });
            // 4. 单条查询:Single(无结果/多结果会抛异常)
            var singleBook = await ctx.Books.SingleAsync(b => b.Title == "零基础趣学C语言");
            // 5. 安全查询:FirstOrDefault(无结果返回 null)
            var firstBook = await ctx.Books.FirstOrDefaultAsync(b => b.Id == 9);

            // 遍历结果(延迟执行:只有遍历/ToList 时才生成 SQL 执行)
            foreach (var book in expensiveBooks)
            {
                Console.WriteLine($"{book.Title} - {book.Price}元");
            }
        }
    }

    // 批量操作(补充:原生 EF Core 无批量操作,需第三方库)
    public static async Task BatchOperation()
    {
        // 推荐使用 Zack.EFCore.Batch 库(NuGet 安装:Zack.EFCore.Batch)
        using (var ctx = new TestDbContext())
        {
            // 批量删除:价格小于50的书籍
            await ctx.Books.Where(b => b.Price < 50).BatchDeleteAsync();
            // 批量更新:所有书籍价格涨10元
            await ctx.Books.BatchUpdateAsync(b => new Book { Price = b.Price + 10 });
        }
    }
}

7. 关键注意事项

  1. DbContext 是轻量级对象,每次操作应创建新实例(使用 using 自动释放),不要单例复用;
  2. LINQ 查询是「延迟执行」:只有调用 ToListAsync()/FirstAsync()/ 遍历等操作时,才会生成 SQL 并执行;
  3. 异步方法优先:所有 CRUD 操作都有 Async 后缀的异步版本(如 SaveChangesAsync),避免阻塞主线程;
  4. 连接字符串配置:生产环境建议将连接字符串写入 appsettings.json,而非硬编码(通过依赖注入读取)。

总结

  1. EF Core 是 .NET 官方全功能 ORM,核心价值是通过对象操作数据库,支持 LINQ、自动迁移、变更追踪等特性;
  2. Code First 模式的核心步骤:安装依赖 → 写实体类 → 配置 DbContext → 迁移生成数据库 → 编写 CRUD 代码;
  3. 迁移是 EF Core 管理数据库结构的核心方式,语义化命名迁移文件、优先使用异步操作是最佳实践。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值