注入燃料——Entity Framework Core 与 Code First 实战
前言从内存到持久化在之前的文章中我们的数据都保存在内存列表里。一旦程序重启数据就会丢失。在企业级开发中数据是核心资产必须安全地存储在数据库中。传统开发模式下你需要手写SQL语句CREATE TABLE...SELECT * FROM...这不仅繁琐而且容易出错还需要处理数据库连接池、事务等复杂逻辑。Entity Framework Core (EF Core)解决了这些问题。它是一个ORMObject-Relational Mapper对象关系映射器。它就像一个智能翻译官能把你写的C#对象自动翻译成数据库里的表把你调用的C#方法自动翻译成SQL语句。你只需操作C#对象EF Core帮你搞定数据库。二、实战准备定义数据模型我们将构建一个经典的“待办事项管理”系统。2.1 安装依赖包首先我们需要引入EF Core的核心包以及数据库驱动。本文以最常用的SQL Server为例即使你没安装SQL Server也可以使用LocalDB或SQLite后文会讲。在项目根目录下打开终端执行以下命令dotnet add package Microsoft.EntityFrameworkCore.SqlServer dotnet add package Microsoft.EntityFrameworkCore.Design2.2 定义实体类我们定义一个TodoItem类。注意这次我们使用传统的class而非record因为在EF Core中实体通常需要属性的可变性且class对导航属性关联关系的支持更为成熟。创建Models/TodoItem.csnamespace MyTodoApp.Models; // 这是一个实体类对应数据库中的一张表 public class TodoItem { // 主键。EF Core约定名为 Id 或 类名Id 的属性会被自动设为主键 public int Id { get; set; } // 任务标题 public string? Title { get; set; } // 是否完成 public bool IsDone { get; set; } // 创建时间 public DateTime CreatedAt { get; set; } DateTime.Now; }三、数据库上下文代码与数据库的桥梁这是EF Core中最核心的概念。DbContext负责管理实体对象与数据库的会话状态。创建Data/AppDbContext.csusing Microsoft.EntityFrameworkCore; using MyTodoApp.Models; namespace MyTodoApp.Data; // 继承自 DbContext public class AppDbContext : DbContext { // 构造函数接收 DbContextOptions用于配置数据库连接 public AppDbContext(DbContextOptionsAppDbContext options) : base(options) { } // DbSet 对应数据库中的表。 // 属性名 Todos 将成为数据库表名EF Core默认约定为复数形式 public DbSetTodoItem Todos { get; set; } // 高级配置可以通过 Fluent API 在这里配置映射关系 protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); // 示例如果不想用默认的表名可以在这里指定 // modelBuilder.EntityTodoItem().ToTable(TaskItems); } }刚子解读AppDbContext就像一个仓库管理员。DbSetTodoItem Todos就是仓库里的一个货架。你往Todos里添加对象管理员就会记下来等到SaveChanges时他会把货架上的东西搬运到真正的数据库里。四、依赖注入与数据库连接回到Program.cs我们需要告诉应用程序使用哪个数据库连接字符串是什么4.1 配置连接字符串打开appsettings.json添加连接字符串{ Logging: { LogLevel: { Default: Information, Microsoft.AspNetCore: Warning } }, AllowedHosts: *, ConnectionStrings: { // 这里使用 LocalDB它是VS自带的轻量级SQL Server无需安装额外软件 // 如果你有真正的SQL Server将 Data Source 改为你的服务器地址 DefaultConnection: Server(localdb)\\mssqllocaldb;DatabaseMyTodoDb;Trusted_ConnectionTrue;MultipleActiveResultSetstrue } }4.2 注册服务在Program.cs中注册 DbContextusing Microsoft.EntityFrameworkCore; using MyTodoApp.Data; var builder WebApplication.CreateBuilder(args); // ... 其他服务注册 ... // 注册 DbContext builder.Services.AddDbContextAppDbContext(options { // 从配置文件读取连接字符串 options.UseSqlServer(builder.Configuration.GetConnectionString(DefaultConnection)); }); var app builder.Build(); // ... 中间件配置 ...【刚子提示】这里我们使用了AddDbContext默认生命周期是Scoped。这意味着在一次HTTP请求中无论你注入多少次AppDbContext拿到的都是同一个实例。这保证了事务的一致性非常符合Web开发的需求。五、见证奇迹Code First 迁移现在是激动人心的时刻。我们还没建数据库甚至没装数据库管理工具。我们将通过代码“变”出一个数据库。5.1 理解迁移迁移是EF Core的版本控制系统。每当你修改了实体类比如加个字段你就创建一个迁移文件记录这次变更。EF Core会根据这个文件更新数据库结构。5.2 创建并执行迁移确保已安装工具dotnet tool install --global dotnet-ef在项目根目录执行# 1. 创建迁移给这次变更起个名字比如 InitialCreate dotnet ef migrations add InitialCreate # 2. 更新数据库执行迁移生成数据库表 dotnet ef database update