一、今日任务(直接执行)
- 在
Admin.NET.API项目中集成 EF Core - 理解:
DbContext/DbSet/ 迁移机制 - 掌握两种配置方式:数据注解 DataAnnotations 、FluentAPI
- 练习:CodeFirst 创建
- 用户表
SysUser - 角色表
SysRole - 用户角色关联表
SysUserRole
- 用户表
- 执行 Migration 生成真实数据库
- 高频面试题背诵
相关两篇博客(EF Core的详细教程)
.Net Core 学习:Razor Pages -- EF Core工作原理
.Net Core 学习: Razor Pages -- EF Core简介
二、第一步:安装 EF Core 包
在 NuGet 包管理器 或 程序包管理器控制台 执行:
必需包 安装到对应DDD(领域驱动设计)四层架构
Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.Tools
如果你用 MySQL / PostgreSQL 就换对应驱动:
- MySQL:
Pomelo.EntityFrameworkCore.MySql - PostgreSQL:
Npgsql.EntityFrameworkCore.PostgreSQL
咱就以 SQL Server 为例(企业最常用)。
三、核心概念(10 分钟)
-
**DbContext:**数据库上下文,相当于 MyBatis 的 SqlSessionFactory + Hibernate 的 SessionFactory。
-
**DbSet<T>:**对应数据库中的一张表。
-
**CodeFirst:**先写实体类 → 执行迁移命令 → 自动生成库和表。
-
**Migration:**迁移记录:每次表结构变更都会生成一个版本文件,可回滚。
四、在项目中编写实体(Domain 层)
位置:Admin.NET.Domain新建文件夹:Entities
1. SysUser 用户表
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Admin.NET.Domain.Entities;
public class SysUser
{
/// <summary>
/// 用户ID
/// </summary>
[Key]
public long Id { get; set; }
/// <summary>
/// 账号
/// </summary>
[Required]
[Column(TypeName = "varchar(50)")]
public string Account { get; set; }
/// <summary>
/// 密码
/// </summary>
[Required]
[Column(TypeName = "varchar(100)")]
public string Password { get; set; }
/// <summary>
/// 姓名
/// </summary>
[Column(TypeName = "nvarchar(20)")]
public string Name { get; set; }
/// <summary>
/// 状态 0=禁用 1=正常
/// </summary>
public int Status { get; set; } = 1;
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreateTime { get; set; } = DateTime.Now;
// 导航属性:一个用户多个角色
public ICollection<SysUserRole> UserRoles { get; set; } = new List<SysUserRole>();
}
2. SysRole 角色表
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Admin.NET.Domain.Entities;
public class SysRole
{
[Key]
public long Id { get; set; }
/// <summary>
/// 角色名称
/// </summary>
[Required]
[Column(TypeName = "nvarchar(50)")]
public string RoleName { get; set; }
/// <summary>
/// 角色编码
/// </summary>
[Required]
[Column(TypeName = "varchar(50)")]
public string RoleCode { get; set; }
public int Status { get; set; } = 1;
public DateTime CreateTime { get; set; } = DateTime.Now;
// 导航属性
public ICollection<SysUserRole> UserRoles { get; set; } = new List<SysUserRole>();
}
3. SysUserRole 用户角色关联表(多对多)
using System.ComponentModel.DataAnnotations;
namespace Admin.NET.Domain.Entities;
public class SysUserRole
{
[Key]
public long Id { get; set; }
public long UserId { get; set; }
public long RoleId { get; set; }
// 导航
public SysUser User { get; set; }
public SysRole Role { get; set; }
}
五、创建 DbContext(Infrastructure 层)
位置:Admin.NET.Infrastructure 新建文件夹:DbContexts
AppDbContext.cs
using Admin.NET.Domain.Entities;
using Microsoft.EntityFrameworkCore;
namespace Admin.NET.Infrastructure.DbContexts;
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{
}
// 表
public DbSet<SysUser> SysUsers { get; set; }
public DbSet<SysRole> SysRoles { get; set; }
public DbSet<SysUserRole> SysUserRoles { get; set; }
// FluentAPI 配置(可选,比注解更强大)
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// 联合索引/唯一键示例
modelBuilder.Entity<SysUser>()
.HasIndex(u => u.Account)
.IsUnique();
modelBuilder.Entity<SysUserRole>()
.HasIndex(ur => new { ur.UserId, ur.RoleId })
.IsUnique();
}
}
六、在 API 层注入 DbContext(Program.cs)
using Microsoft.EntityFrameworkCore;
using Serilog;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
//注入 Swagger
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// 注入 EF Core
builder.Services.AddDbContext<AppDbContext>(options =>
{
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"));//从 appsettings.json 获取数据库连接
});
//Serilog 注册(用 Serilog 替换默认日志)
builder.Host.UseSerilog((ctx, cfg) =>
{
cfg.ReadFrom.Configuration(ctx.Configuration);// 从 appsettings.json 读取日志配置
});
var app = builder.Build();
// 中间件顺序:日志 → 异常 → 其他
//启用日志中间件
app.UseLogMiddleware();
//启用全局异常中间件
app.UseGlobalException();
//app.UseRouting(); //路由
//app.UseAuthentication(); //认证
//app.UseAuthorization(); //授权
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.MapControllers();
app.Run();
在 appsettings.json 加连接字符串:
"ConnectionStrings": {
"DefaultConnection": "Server=.;Database=AdminNET;Trusted_Connection=True;TrustServerCertificate=True;"
}
七、Migration 迁移命令(必背)
打开:工具 → NuGet 包管理器 → 程序包管理器控制台 默认项目选择:Admin.NET.Infrastructure 或 Admin.NET.API
1. 创建迁移文件
Add-Migration InitDb
2. 更新到数据库
Update-Database
3. 常用命令
Remove-Migration:删除最后一次迁移Update-Database 名称:回滚到某个版本Script-Migration:生成 SQL 脚本
八、数据注解 vs FluentAPI(面试必问)
1. 数据注解(DataAnnotations)
- 写在实体类属性上
- 简单直观
- 适合简单约束
常用:
[Key]主键[Required]非空[MaxLength(50)][Column(TypeName="varchar(50)")][ForeignKey("UserId")]
2. FluentAPI
- 在
OnModelCreating中写 - 功能更强:联合索引、多对多、复杂关系、种子数据
- 不污染实体
- 企业大型项目首选
九、高频面试题 + 标准答案(直接背)
1. EF Core 是什么?和 EF6 区别?
**答:**EF Core 是轻量级、跨平台的 ORM,支持 .NET Core/.NET 5+。EF6 是 Windows 版 .NET Framework 专用。EF Core 性能更好、更轻量、支持更多数据库、适合微服务。
2. CodeFirst、DbFirst、ModelFirst 区别?
答:
- CodeFirst:先写实体,自动生成库表(企业主流)
- DbFirst:从现有数据库生成实体
- ModelFirst:从设计器生成模型和库表(几乎不用)
3. DbContext 生命周期?
答: ASP.NET Core 中默认 Scoped(一次请求一个实例),线程安全,适合 Web。
4. EF Core 有几种查询方式?
答:
- LINQ 查询语法
- LINQ 方法语法
- FromSQL 执行原生 SQL
- 存储过程
5. 贪婪加载、延迟加载、显式加载区别?
答:
- 延迟加载:用到导航属性才查,默认关闭,易导致 N+1
- 贪婪加载 :
Include()联表一次性查,性能好 - 显式加载 :
Load()手动加载
企业优先 Include 贪婪加载。
6. 什么是 EF Core 迁移?
**答:**Migration 会记录表结构变更,生成版本文件,可自动同步数据库,支持回滚,适合团队协作。
7. AsNoTracking 有什么用?
答: 关闭跟踪,查询更快,减少内存占用,只读场景强烈推荐。