1. 为什么选择SQLSugar构建数据访问层第一次接触SQLSugar是在三年前的一个电商项目里当时团队还在用传统的ADO.NET手写SQL。记得有天晚上赶进度我对着满屏的SqlConnection和SqlCommand写到凌晨三点突然意识到这种开发方式太原始了。第二天就研究起了ORM框架经过对比Entity Framework和Dapper后最终选择了SQLSugar——这个决定后来被证明非常正确。SQLSugar最吸引我的地方是它轻量级但功能齐全的特性。相比EF的庞大体系它只有几个核心DLL相比Dapper需要手动映射它提供了完整的对象映射能力。实际使用中我发现几个明显优势开发效率提升明显原先需要20行代码的CRUD操作现在3-5行就能完成SQL可读性强通过Lambda表达式生成的SQL接近人工编写质量性能损耗小基准测试显示比EF Core快30%左右学习曲线平缓API设计符合直觉文档示例丰富特别是在.NET Core环境下SQLSugar对异步操作、依赖注入等现代特性的支持做得很好。上周我刚用它在半小时内完成了一个用户管理模块的数据层搭建这种效率在以前难以想象。2. 环境准备与基础配置2.1 创建ASP.NET Core项目建议使用Visual Studio 2022新建项目选择ASP.NET Core Web API模板。我习惯用.NET 6版本它对SQLSugar的支持最完善。创建完成后在解决方案资源管理器右键点击依赖项选择管理NuGet程序包。这里有个小技巧不要直接搜索SQLSugar而是找SqlSugarCore这个包。最近版本如5.1.4对Core项目优化更好。安装时注意勾选包括预发行版因为有些新功能会先放在预览版中。2.2 配置数据库连接在appsettings.json中添加连接字符串配置{ ConnectionStrings: { Default: Server.;DatabaseUserDemo;Trusted_ConnectionTrue; } }然后在Program.cs中注册SQLSugar服务builder.Services.AddScopedISqlSugarClient(provider { var config new ConnectionConfig() { ConnectionString builder.Configuration.GetConnectionString(Default), DbType DbType.SqlServer, IsAutoCloseConnection true }; return new SqlSugarClient(config); });我遇到过几个新手常见坑点SQL Server需要开启TCP/IP协议Linux环境下要注意大小写敏感问题连接池大小建议设为100以内默认是0表示不限制3. 实体映射与基础CRUD3.1 定义用户实体先创建Models/User.cs文件用特性标注表名和字段[SugarTable(SysUser)] public class User { [SugarColumn(IsPrimaryKey true, IsIdentity true)] public int Id { get; set; } [SugarColumn(Length 50)] public string UserName { get; set; } [SugarColumn(IsNullable false)] public string PasswordHash { get; set; } [SugarColumn(DefaultValue getdate())] public DateTime CreateTime { get; set; } }这里有几个实用技巧IsIdentity表示自增主键Length限制字段长度DefaultValue支持SQL函数表达式用IsNullable控制是否允许NULL3.2 实现基础操作在Controllers中注入ISqlSugarClient后可以这样写CRUD// 查询 var user _db.QueryableUser().Where(u u.Id 1).First(); // 分页查询 var pageUsers _db.QueryableUser() .Where(u u.UserName.Contains(admin)) .ToPageList(pageNumber, pageSize, ref totalCount); // 插入 var newUser new User { UserName test, PasswordHash 123 }; _db.Insertable(newUser).ExecuteCommand(); // 更新 user.UserName modified; _db.Updateable(user).ExecuteCommand(); // 删除 _db.DeleteableUser().Where(u u.Id 1).ExecuteCommand();实际项目中我发现批量操作的性能优化很重要// 批量插入1000条数据只要200ms _db.FastestUser().BulkCopy(userList); // 批量更新 _db.FastestUser().BulkUpdate(userList);4. 封装通用数据访问层4.1 设计仓储接口在项目根目录创建Repositories/IBaseRepository.cspublic interface IBaseRepositoryT where T : class, new() { TaskT GetByIdAsync(int id); TaskListT GetListAsync(ExpressionFuncT, bool where null); Taskbool InsertAsync(T entity); Taskbool UpdateAsync(T entity); Taskbool DeleteAsync(int id); TaskPageModelT GetPageListAsync(int pageIndex, int pageSize); }4.2 实现通用仓储创建Repositories/BaseRepository.cspublic class BaseRepositoryT : IBaseRepositoryT where T : class, new() { private readonly ISqlSugarClient _db; public BaseRepository(ISqlSugarClient db) { _db db; } public async TaskT GetByIdAsync(int id) { return await _db.QueryableT().InSingleAsync(id); } public async TaskListT GetListAsync(ExpressionFuncT, bool where null) { return await _db.QueryableT() .WhereIF(where ! null, where) .ToListAsync(); } public async Taskbool InsertAsync(T entity) { return await _db.Insertable(entity).ExecuteCommandAsync() 0; } public async TaskPageModelT GetPageListAsync(int pageIndex, int pageSize) { RefAsyncint total 0; var list await _db.QueryableT() .ToPageListAsync(pageIndex, pageSize, total); return new PageModelT(pageIndex, total, list); } }4.3 用户专属仓储创建Repositories/UserRepository.cspublic interface IUserRepository : IBaseRepositoryUser { TaskUser GetByUserNameAsync(string userName); Taskbool ChangePasswordAsync(int userId, string newPassword); } public class UserRepository : BaseRepositoryUser, IUserRepository { public UserRepository(ISqlSugarClient db) : base(db) { } public async TaskUser GetByUserNameAsync(string userName) { return await _db.QueryableUser() .Where(u u.UserName userName) .FirstAsync(); } public async Taskbool ChangePasswordAsync(int userId, string newPassword) { return await _db.UpdateableUser() .SetColumns(u u.PasswordHash newPassword) .Where(u u.Id userId) .ExecuteCommandAsync() 0; } }5. 高级特性实战5.1 事务处理SQLSugar提供了三种事务写法推荐使用UnitOfWork模式public class UserService { private readonly IUserRepository _userRepo; private readonly ISqlSugarClient _db; public async Task RegisterUser(User user, UserProfile profile) { try { _db.Ado.BeginTran(); await _userRepo.InsertAsync(user); profile.UserId user.Id; await _db.Insertable(profile).ExecuteCommandAsync(); _db.Ado.CommitTran(); } catch { _db.Ado.RollbackTran(); throw; } } }5.2 多表联查处理用户角色关系时常用联表查询var list await _db.QueryableUser() .LeftJoinUserRole((u, ur) u.Id ur.UserId) .LeftJoinRole((u, ur, r) ur.RoleId r.Id) .Where(u u.Status 1) .Select((u, ur, r) new UserRoleDto { UserName u.UserName, RoleName r.Name }) .ToListAsync();5.3 过滤器应用实现全局软删除过滤// 配置时添加 db.QueryFilter.Add(new TableFilterItemUser(u u.IsDeleted false)); // 查询时会自动加上 WHERE IsDeleted0 条件 var users db.QueryableUser().ToList(); // 需要查询已删除数据时 db.QueryableUser().Filter(null, false).ToList();6. 性能优化技巧6.1 查询优化避免SELECT * 操作// 只查询需要的字段 var users _db.QueryableUser() .Select(u new { u.Id, u.UserName }) .ToList();使用缓存// 缓存10分钟 var user _db.QueryableUser() .Where(u u.Id 1) .WithCache(10 * 60) .First();6.2 批量操作大数据量插入优化// 使用BulkCopy _db.FastestUser().BulkCopy(users); // 分批插入 _db.Insertable(users).SplitTable().ExecuteCommand();6.3 读写分离配置多个连接var db new SqlSugarClient(new ListConnectionConfig { new ConnectionConfig(){ ConfigIdwrite, ConnectionStringwriteConn }, new ConnectionConfig(){ ConfigIdread1, ConnectionStringreadConn1 }, new ConnectionConfig(){ ConfigIdread2, ConnectionStringreadConn2 } }); // 写操作 db.ChangeDatabase(write).Insertable(user).ExecuteCommand(); // 读操作随机选择从库 var user db.ChangeDatabase(Random(new[]{read1,read2})) .QueryableUser().First();7. 生产环境实践7.1 日志记录配置AOP日志var db new SqlSugarClient(config, db { db.Aop.OnLogExecuting (sql, pars) { logger.LogInformation(UtilMethods.GetNativeSql(sql, pars)); }; db.Aop.OnError exp { logger.LogError(exp, SQL执行出错); }; });7.2 健康检查添加数据库健康检查builder.Services.AddHealthChecks() .AddSqlSugar(user_db, tags: new[] { database }); // 在控制器添加 [HttpGet(health)] public async TaskIActionResult HealthCheck() { var report await healthCheckService.CheckHealthAsync(); return report.Status HealthStatus.Healthy ? Ok() : StatusCode(503); }7.3 数据迁移使用CodeFirst模式// 实体变更后执行 db.CodeFirst.InitTablesUser(); // 初始化种子数据 if (!db.QueryableUser().Any()) { db.Insertable(new User { UserName admin }).ExecuteCommand(); }8. 常见问题解决8.1 连接池耗尽症状出现Timeout expired. The timeout period elapsed...错误。解决方案// 修改连接字符串 Server.;Poolingtrue;Max Pool Size100;Min Pool Size10; // 或者在配置中设置 config.PoolMax 100; config.PoolMin 10;8.2 导航属性循环引用处理JSON序列化问题// 实体类添加 [Newtonsoft.Json.JsonIgnore] public virtual ListUserRole UserRoles { get; set; } // 或者全局配置 builder.Services.AddControllers() .AddNewtonsoftJson(options { options.SerializerSettings.ReferenceLoopHandling ReferenceLoopHandling.Ignore; });8.3 并发更新冲突使用乐观锁public class User { [SugarColumn(IsVersion true)] public long Version { get; set; } } // 更新时会自动检查Version var success _db.Updateable(user).ExecuteCommand() 0;9. 项目结构建议推荐的分层方案UserManagement/ ├── Controllers/ ├── Models/ │ ├── Entities/ # 数据库实体 │ └── DTOs/ # 数据传输对象 ├── Repositories/ │ ├── Interfaces/ # 仓储接口 │ └── Implementations # 仓储实现 ├── Services/ # 业务逻辑层 └── Migrations/ # 数据库迁移脚本在团队协作中我们约定控制器只做参数校验和结果返回业务逻辑放在Service层数据库操作全部通过Repository实体类保持纯净不加业务方法10. 扩展功能探索10.1 多租户支持通过过滤器实现// 添加租户ID过滤 db.QueryFilter.Add(new TableFilterItemUser(u u.TenantId currentTenantId)); // 插入时自动设置租户ID db.Aop.OnExecutingChangeSql (sql, pars) { if(sql.StartsWith(INSERT INTO User)) { sql sql.Replace(VALUES (, $VALUES ({currentTenantId},); } return (sql, pars); };10.2 动态查询构建实现高级搜索功能public async TaskListUser SearchUsers(UserSearchDto dto) { var query _db.QueryableUser(); if(!string.IsNullOrEmpty(dto.Keyword)) { query query.Where(u u.UserName.Contains(dto.Keyword)); } if(dto.RoleId.HasValue) { query query.Where(u u.Roles.Any(r r.Id dto.RoleId)); } return await query.ToListAsync(); }10.3 数据库表拆分处理大数据量表// 按月分表 [SugarTable(Order_{year}{month})] public class Order { [SplitField] public DateTime CreateTime { get; set; } } // 查询时自动路由 var orders _db.QueryableOrder() .Where(o o.CreateTime startDate o.CreateTime endDate) .SplitTable(startDate, endDate) .ToList();11. 测试策略11.1 单元测试使用内存数据库测试仓储层[Fact] public async Task InsertUser_ShouldReturnTrue() { // 使用SQLite内存模式 var db new SqlSugarClient(new ConnectionConfig { DbType DbType.Sqlite, ConnectionString DataSource:memory:, IsAutoCloseConnection true }); db.CodeFirst.InitTablesUser(); var repo new UserRepository(db); var result await repo.InsertAsync(new User { UserName test }); Assert.True(result); Assert.Equal(1, db.QueryableUser().Count()); }11.2 集成测试测试完整API流程[Fact] public async Task GetUser_ShouldReturnUser() { var client _factory.CreateClient(); // 先插入测试数据 var db _factory.Services.GetServiceISqlSugarClient(); db.Insertable(new User { Id 1, UserName test }).ExecuteCommand(); // 调用API var response await client.GetAsync(/api/users/1); var user await response.Content.ReadFromJsonAsyncUser(); Assert.Equal(test, user.UserName); }12. 部署注意事项12.1 连接字符串管理生产环境推荐使用// 从环境变量读取 var connStr Environment.GetEnvironmentVariable(DB_CONNECTION); // 或者使用密钥管理服务 var connStr await secretClient.GetSecretAsync(db-connection);12.2 数据库版本兼容处理不同数据库差异// 根据环境变量切换数据库类型 var dbType Environment.GetEnvironmentVariable(DB_TYPE) switch { MySQL DbType.MySql, PostgreSQL DbType.PostgreSQL, _ DbType.SqlServer }; // 在SQLSugar配置中 config.ConfigureExternalServices new ConfigureExternalServices { EntityNameService (type, entity) { if(dbType DbType.MySql) entity.DbTableName entity.DbTableName.ToLower(); } };12.3 性能监控添加Application Insights监控builder.Services.AddApplicationInsightsTelemetry(); // 在SQLSugar配置中 db.Aop.OnLogExecuting (sql, pars) { var telemetry new DependencyTelemetry { Type SQL, Data UtilMethods.GetNativeSql(sql, pars), Timestamp DateTime.UtcNow }; telemetryClient.TrackDependency(telemetry); };13. 持续演进建议随着项目发展可以考虑引入缓存层对热点数据使用Redis缓存实现CQRS模式分离查询和命令操作添加GraphQL支持灵活的前端数据查询探索分布式事务跨服务数据一致性保障最近我在一个微服务项目中实践了SQLSugarDapr的方案通过分布式事务协调器实现了跨服务的用户-订单数据一致性效果很不错。