[特殊字符]C# ASP.NET 架构封神之路:分层 + 仓储 + EFCore,写出企业级可维护代码!
目录
今天带来ASP.NET 企业级架构核心篇——MVC 扩展分层架构 + DAL 层 (Repository+EFCore)实战,纯干货、无废话,带代码、避坑、流程图,新手也能直接落地!
本篇主打:规范命名、低耦合、高可维护、易扩展,是中小厂到大厂通用的最佳实践!

一、先搞懂:什么是 MVC 扩展分层架构?(通俗类比)
小节:架构分层 = 公司部门分工
很多新手一上来就把代码写在 Controller 里,后期改不动、查错难,本质是没有分工!
我们把项目拆成5 层标准结构(MVC 基础上扩展),就像一家正规公司:
表格
| 层名称 | 英文缩写 | 职责 | 生活类比 |
|---|---|---|---|
| 表现层 | UI/Controller | 接收请求、返回结果 | 前台客服 |
| 业务逻辑层 | BLL | 处理核心业务规则 | 运营经理 |
| 数据访问层 | DAL | 只和数据库打交道 | 仓库管理员 |
| 模型层 | Model | 数据实体、DTO | 商品档案 |
| 核心公共层 | Core | 工具类、常量、枚举 | 公司行政部 |
标准分层流程图
小节:为什么必须分层?
- 解耦 : 改数据库不影响业务,改业务不影响页面
- 可维护: 代码各司其职,一眼找到问题
- 可测试: 业务逻辑可单独单元测试
- 规范: 多人协作不混乱
二、DAL 层核心:Repository 仓储模式 + EFCore
小节:仓储模式 = 数据库专属 “管家”
仓储模式(Repository)是DAL 层唯一和数据库交互的入口,作用:
- 统一 CRUD,避免重复代码
- 屏蔽 EFCore 细节,上层不用关心数据库
方便切换 ORM(以后不用 EFCore 也不影响业务)
一句话: Service 只管调用,Repository 只管干活,EFCore 只管执行 SQL。
三、实战代码:从 0 到 1 搭建标准架构
环境准备
- .NET 6/7/8(LTS 版本最佳)
- ASP.NET MVC
- EFCore + SQL Server
- 依赖注入(微软原生 DI)
1. 第一步:定义实体(Model 层)
小节:实体 = 数据库表的 “代码映射”
规范:
- 实体放在Models/Entities文件夹
- 类名 = 表名(大驼峰)
- 属性 = 字段(帕斯卡命名)
- 无业务逻辑,纯数据载体
// Models/Entities/User.cs
using System.ComponentModel.DataAnnotations;
/// <summary>
/// 用户实体(对应数据库User表)
/// </summary>
public class User
{
[Key] // 主键
public int Id { get; set; }
[Required] // 非空
[MaxLength(20)]
public string UserName { get; set; }
[MaxLength(50)]
public string Email { get; set; }
public bool IsActive { get; set; } = true; // 默认值
}
2. 第二步:搭建 DbContext(EFCore 核心)
小节:DbContext = 数据库连接 “总开关”
规范:
- 放在DAL/DbContexts
- 继承DbContext
- 构造函数注入配置
- 用DbSet映射表
// DAL/DbContexts/AppDbContext.cs
using Microsoft.EntityFrameworkCore;
using Models.Entities;
/// <summary>
/// EFCore 数据库上下文
/// </summary>
public class AppDbContext : DbContext
{
// 注入配置
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
// 映射数据库表
public DbSet<User> Users => Set<User>();
// 统一配置种子数据/约束
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}
3. 第三步:定义仓储接口(抽象规范)
小节:接口 = “管家的工作清单”
最佳实践: 先写接口,后写实现,面向接口编程!
// DAL/Repositories/IRepository/IRepository.cs
using System.Linq.Expressions;
/// <summary>
/// 通用仓储接口(所有实体通用CRUD)
/// </summary>
/// <typeparam name="T">实体类型</typeparam>
public interface IRepository<T> where T : class
{
// 查询
Task<T> GetByIdAsync(int id);
Task<List<T>> GetAllAsync();
Task<List<T>> GetListAsync(Expression<Func<T, bool>> where);
// 新增
Task AddAsync(T entity);
Task AddRangeAsync(List<T> entities);
// 修改
void Update(T entity);
void UpdateRange(List<T> entities);
// 删除
void Delete(T entity);
void DeleteRange(List<T> entities);
// 提交事务
Task<int> SaveChangesAsync();
}
4. 第四步:实现通用仓储(核心代码)
小节:实现类 = “管家真正干活”
csharp
运行
// DAL/Repositories/Impl/RepositoryBase.cs
using Microsoft.EntityFrameworkCore;
using System.Linq.Expressions;
/// <summary>
/// 仓储基类(所有实体共用实现)
/// </summary>
public class RepositoryBase<T> : IRepository<T> where T : class
{
protected readonly AppDbContext _dbContext;
protected readonly DbSet<T> _dbSet;
// 依赖注入DbContext
public RepositoryBase(AppDbContext dbContext)
{
_dbContext = dbContext;
_dbSet = dbContext.Set<T>();
}
#region 查询
public async Task<T> GetByIdAsync(int id)
{
return await _dbSet.FindAsync(id);
}
public async Task<List<T>> GetAllAsync()
{
return await _dbSet.AsNoTracking().ToListAsync();
}
public async Task<List<T>> GetListAsync(Expression<Func<T, bool>> where)
{
return await _dbSet.AsNoTracking().Where(where).ToListAsync();
}
#endregion
#region 增删改
public async Task AddAsync(T entity)
{
await _dbSet.AddAsync(entity);
}
public void Update(T entity)
{
_dbSet.Update(entity);
}
public void Delete(T entity)
{
_dbSet.Remove(entity);
}
#endregion
// 统一提交事务
public async Task<int> SaveChangesAsync()
{
return await _dbContext.SaveChangesAsync();
}
}
5. 第五步:注册服务(Program.cs)
小节:依赖注入 = “给系统分配员工”
// Program.cs
using DAL.DbContexts;
using DAL.Repositories.Impl;
using DAL.Repositories.IRepository;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// 1. 注册EFCore
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
// 2. 注册仓储(生命周期:Scoped 一次请求一个实例)
builder.Services.AddScoped(typeof(IRepository<>), typeof(RepositoryBase<>));
// 3. MVC控制器
builder.Services.AddControllersWithViews();
var app = builder.Build();
// 中间件省略...
app.Run();
6. 第六步:Controller 调用演示
小节:上层调用 = “客服找经理,经理找仓库”
// Controllers/UserController.cs
using DAL.Repositories.IRepository;
using Microsoft.AspNetCore.Mvc;
using Models.Entities;
public class UserController : Controller
{
// 直接注入仓储
private readonly IRepository<User> _userRepository;
public UserController(IRepository<User> userRepository)
{
_userRepository = userRepository;
}
// 查询用户列表
public async Task<IActionResult> Index()
{
var users = await _userRepository.GetAllAsync();
return View(users);
}
// 新增用户
[HttpPost]
public async Task<IActionResult> Add(User user)
{
await _userRepository.AddAsync(user);
await _userRepository.SaveChangesAsync();
return RedirectToAction("Index");
}
}
四、开发必看:Repository+EFCore 10 大经典坑(90% 人中招)
小节:踩坑 = 新手 “必经之路”,避开就是高手
1.忘记调用 SaveChangesAsync
- 坑:增删改执行了,但数据库没变化
- 原因:EFCore 是状态跟踪,必须提交才生效
- 类比:你把商品放进仓库,但没 “确认入库”
2.滥用 AsNoTracking
- 坑:查询快,但修改时报错
- 规则:只读用 AsNoTracking,要修改必须不用
3.在仓储外操作 DbContext
- 坑:架构失效,代码到处改数据库
- 规范:所有数据库操作必须走 Repository
4.同步方法代替异步
- 坑:高并发卡死,性能暴跌
- 规范:EFCore 全部用Async结尾方法
5.事务不统一
- 坑:部分成功部分失败,数据错乱
- 最佳实践:一个请求一个 SaveChanges
6.主外键懒加载死循环
- 坑:JSON 序列化爆栈
- 解决:关闭懒加载 or 使用 DTO
7.实体加业务逻辑
- 坑:实体不纯粹,难以维护
- 规范:实体只存数据,业务放 Service
8.泛型仓储写死条件
- 坑:无法复用,失去仓储意义
- 解决:用表达式树传条件
9.多个仓储多次 SaveChanges
- 坑:事务失效,数据不一致
- 解决:Service 层统一提交
10.连接字符串硬编码
- 坑:换环境要改代码,不安全
- 规范:配置文件读取
五、最佳实践总结(直接复制当团队规范)
小节:这一段直接收藏,团队开发统一标准
✅ 命名规范
- 接口:IXXXRepository
- 实现:XXXRepository
- 实体:表名大驼峰
- 上下文:XXXDbContext
✅ 结构规范
项目/
├─ Models/Entities 实体
├─ DAL/
│ ├─ DbContexts EFCore上下文
│ ├─ Repositories/
│ ├─ IRepository 仓储接口
│ └─ Impl 仓储实现
├─ BLL/Services 业务层
└─ Controllers 表现层
✅ 职责规范
- Controller:接收请求、返回视图
- Service:业务规则、校验、组合仓储
- Repository:只做 CRUD,无业务逻辑
- EFCore:只做数据库交互
六、结尾互动
今天把MVC 扩展分层 + DAL 仓储 + EFCore全套代码、架构图、避坑指南一次性讲完了,新手也能直接落地!
留言区聊聊
1.你在项目中踩过 EFCore / 仓储模式的什么坑?
2.下期想看:Service 层业务规范 还是 UnitOfWork 工作单元?
3.代码看不懂的地方,直接截图提问!
我会一一回复,帮你打通架构任督二脉~
总结
1.分层架构 = 分工合作,Controller/Service/Repository 各司其职
2.Repository+EFCore是.NET 企业级标准数据访问方案
3.避开 10 大经典坑,代码可维护性直接提升 10 倍
4.面向接口 + 依赖注入,让项目易扩展、易测试
觉得干货有用,点赞 + 收藏 + 关注,下期更精彩!
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)