1. 为什么选择SqlSugar作为.NET Core的ORM工具
在.NET Core生态中选择ORM框架时,开发者通常会面临几个主流选项:Entity Framework Core、Dapper和SqlSugar。每种方案都有其独特的优势和应用场景。经过多个项目的实战验证,我发现SqlSugar在以下场景中表现尤为突出:
-
中小型项目快速开发:相比EF Core复杂的配置和迁移机制,SqlSugar提供了更简洁的API和更直观的代码结构。新建一个模型类后,几乎不需要额外配置就能立即进行CRUD操作。
-
高性能需求场景:基准测试显示,SqlSugar在批量插入和复杂查询场景下,性能比EF Core提升30%-50%。其内置的缓存机制和优化的SQL生成引擎,使得在高并发环境下仍能保持稳定表现。
-
多数据库支持:一个显著优势是同一套代码可无缝切换MySQL、SQL Server、PostgreSQL等数据库。我曾在一个项目中因客户需求从SQL Server迁移到Oracle,仅需修改连接字符串和方言配置。
-
国产化适配:对达梦、人大金仓等国产数据库的支持比EF Core更完善。在政务类项目中,这点尤为重要。
实际案例:在为某物流系统做技术选型时,我们对比了三种ORM。最终选择SqlSugar的关键因素是它处理分表查询(SplitTable)的优雅实现。通过[SplitTable]特性标注模型类,再调用SplitHelper方法,就能自动路由到正确的物理表,避免了手动拼接SQL的繁琐。
注意:虽然SqlSugar学习曲线平缓,但建议团队在引入前仍要进行充分的技术评估。特别是在大型复杂项目中,EF Core的变更追踪和LINQ提供程序可能更有优势。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与基础配置
2.1 创建.NET Core项目
推荐使用Visual Studio 2022或JetBrains Rider作为开发环境。以VS2022为例:
- 新建ASP.NET Core Web API项目,目标框架选择.NET 6+(长期支持版本)
- 通过NuGet安装核心依赖包:
bash复制Install-Package SqlSugarCore Install-Package Swashbuckle.AspNetCore # Swagger支持
2.2 数据库连接配置
在appsettings.json中添加数据库配置段:
json复制{
"ConnectionStrings": {
"Default": "Server=.;Database=DemoDb;User ID=sa;Password=yourStrongPassword;"
},
"DbConfig": {
"DbType": "SqlServer", // 可选MySql、Oracle等
"IsAutoCloseConnection": true
}
}
创建配置类强类型映射:
csharp复制public class DbConfig
{
public DbType DbType { get; set; }
public bool IsAutoCloseConnection { get; set; }
}
2.3 依赖注入配置
在Program.cs中注册SqlSugar服务:
csharp复制var builder = WebApplication.CreateBuilder(args);
// 读取配置
var dbConfig = builder.Configuration.GetSection("DbConfig").Get<DbConfig>();
// 注册SqlSugar
builder.Services.AddScoped<ISqlSugarClient>(provider =>
{
var scope = provider.CreateScope();
var config = new ConnectionConfig()
{
ConnectionString = builder.Configuration.GetConnectionString("Default"),
DbType = dbConfig.DbType,
IsAutoCloseConnection = dbConfig.IsAutoCloseConnection,
ConfigureExternalServices = new ConfigureExternalServices
{
EntityService = (c, p) => p.IsIgnore = false // 全局禁用默认忽略特性
}
};
return new SqlSugarScope(config);
});
3. 实体设计与CRUD实战
3.1 定义数据实体
创建用户实体示例:
csharp复制[SugarTable("sys_user")] // 指定表名
public class User
{
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
[SugarColumn(Length = 50, IsNullable = false)]
public string UserName { get; set; }
[SugarColumn(ColumnDataType = "varchar(100)")]
public string Password { get; set; }
[SugarColumn(IsIgnore = true)] // 不映射到数据库
public string TempToken { get; set; }
}
特性说明:
[SugarTable]:自定义表名(默认与类名相同)[SugarColumn]:控制字段类型、长度、主键等IsIgnore:排除字段不参与数据库操作
3.2 基础CRUD操作
创建通用仓储服务:
csharp复制public class BaseRepository<T> where T : class, new()
{
private readonly ISqlSugarClient _db;
public BaseRepository(ISqlSugarClient db)
{
_db = db;
}
// 新增
public async Task<int> AddAsync(T entity)
{
return await _db.Insertable(entity).ExecuteReturnIdentityAsync();
}
// 批量新增(事务)
public async Task<bool> AddBatchAsync(List<T> entities)
{
try
{
_db.Ado.BeginTran();
await _db.Insertable(entities).ExecuteCommandAsync();
_db.Ado.CommitTran();
return true;
}
catch
{
_db.Ado.RollbackTran();
throw;
}
}
// 分页查询
public async Task<PageModel<T>> QueryPageAsync(Expression<Func<T, bool>> where,
int pageIndex = 1, int pageSize = 20)
{
RefAsync<int> total = 0;
var list = await _db.Queryable<T>()
.Where(where)
.ToPageListAsync(pageIndex, pageSize, total);
return new PageModel<T>(pageIndex, pageSize, total, list);
}
}
3.3 高级查询示例
多表联查+动态条件:
csharp复制public async Task<List<UserDto>> GetUserList(UserQueryDto dto)
{
return await _db.Queryable<User>()
.LeftJoin<Department>((u, d) => u.DeptId == d.Id)
.WhereIF(!string.IsNullOrEmpty(dto.Keyword),
u => u.UserName.Contains(dto.Keyword) || u.Phone.Contains(dto.Keyword))
.OrderBy(u => u.CreateTime, OrderByType.Desc)
.Select((u, d) => new UserDto
{
Id = u.Id,
UserName = u.UserName,
DeptName = d.Name
})
.ToListAsync();
}
4. Swagger集成与跨域配置
4.1 Swagger基础集成
在Program.cs中添加:
csharp复制// Swagger配置
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
// 添加控制器注释
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
c.IncludeXmlComments(xmlPath);
});
// 启用中间件
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});
4.2 解决Swagger未授权访问
生产环境应添加安全控制:
csharp复制// 开发环境启用Swagger
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
else
{
// 生产环境添加Basic认证
app.UseSwaggerBasicAuth();
}
自定义认证中间件示例:
csharp复制public static class SwaggerBasicAuthMiddlewareExtensions
{
public static IApplicationBuilder UseSwaggerBasicAuth(this IApplicationBuilder builder)
{
return builder.UseMiddleware<SwaggerBasicAuthMiddleware>();
}
}
public class SwaggerBasicAuthMiddleware
{
private readonly RequestDelegate _next;
public SwaggerBasicAuthMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
if (context.Request.Path.StartsWithSegments("/swagger"))
{
string authHeader = context.Request.Headers["Authorization"];
if (authHeader != null && authHeader.StartsWith("Basic "))
{
// 验证逻辑...
}
else
{
context.Response.Headers["WWW-Authenticate"] = "Basic";
context.Response.StatusCode = 401;
return;
}
}
await _next(context);
}
}
4.3 跨域解决方案
配置全局CORS策略:
csharp复制builder.Services.AddCors(options =>
{
options.AddPolicy("AllowAll", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
});
});
app.UseCors("AllowAll");
生产环境推荐配置:
csharp复制builder.Services.AddCors(options =>
{
options.AddPolicy("ProductionPolicy", builder =>
{
builder.WithOrigins("https://yourdomain.com")
.WithMethods("GET", "POST", "PUT", "DELETE")
.AllowCredentials()
.SetPreflightMaxAge(TimeSpan.FromHours(1));
});
});
5. 实战技巧与性能优化
5.1 分表查询实现
SqlSugar对分表(Sharding)有原生支持。以订单表按月份分表为例:
- 定义分表实体:
csharp复制[SplitTable(SplitType.Month)] // 按月分表
[SugarTable("order_{year}{month}")] // 表名模式
public class Order
{
[SugarColumn(IsPrimaryKey = true)]
public string Id { get; set; }
[SplitField] // 分表依据字段
public DateTime CreateTime { get; set; }
}
- 分表查询示例:
csharp复制// 查询2023年1月数据
var janOrders = await _db.Queryable<Order>()
.Where(o => o.CreateTime >= new DateTime(2023, 1, 1) &&
o.CreateTime < new DateTime(2023, 2, 1))
.ToListAsync();
// 跨月查询(自动路由到多张表)
var multiMonthOrders = await _db.Queryable<Order>()
.Where(o => o.CreateTime >= new DateTime(2023, 1, 1) &&
o.CreateTime < new DateTime(2023, 3, 1))
.ToListAsync();
5.2 读写分离配置
在ConnectionConfig中配置读写分离:
csharp复制new ConnectionConfig
{
ConnectionString = "主库连接字符串",
DbType = DbType.MySql,
IsAutoCloseConnection = true,
SlaveConnectionConfigs = new List<SlaveConnectionConfig>
{
new SlaveConnectionConfig()
{
ConnectionString = "从库1连接字符串",
HitRate = 50 // 权重
},
new SlaveConnectionConfig()
{
ConnectionString = "从库2连接字符串",
HitRate = 50
}
}
}
提示:写操作会自动走主库,读操作随机选择从库。可通过
AsTenant().ChangeDatabase()手动切换。
5.3 性能监控与调优
启用SQL日志和性能分析:
csharp复制var db = new SqlSugarScope(config, db =>
{
db.Aop.OnLogExecuting = (sql, pars) =>
{
Console.WriteLine(sql);
// 可接入日志系统如NLog
};
db.Aop.OnError = exp =>
{
// 异常处理
};
db.Aop.OnExecutingChangeSql = (sql, pars) =>
{
// SQL重写
return new KeyValuePair<string, SugarParameter[]>(sql, pars);
};
});
缓存策略配置:
csharp复制// 二级缓存配置
ConfigureExternalServices = new ConfigureExternalServices
{
DataInfoCacheService = new RedisCache() // 实现ICacheService
}
// 查询缓存示例
var cachedData = await _db.Queryable<User>()
.WithCache() // 默认60秒
.WithCache(TimeSpan.FromMinutes(5)) // 自定义过期
.ToListAsync();
6. 常见问题排查
6.1 连接池耗尽问题
症状:出现"Timeout expired. The timeout period elapsed..."错误。
解决方案:
- 检查连接字符串是否添加了Pooling配置:
json复制"ConnectionStrings": { "Default": "Server=.;Database=DemoDb;...;Pooling=true;Max Pool Size=200;Min Pool Size=10;" } - 确保所有操作都正确释放连接:
csharp复制// 错误示例 - 忘记using var conn = _db.Ado.Connection; // 正确做法 using (var conn = _db.Ado.Connection) { // 操作代码 }
6.2 分页查询性能优化
当处理大数据量分页时,避免使用Skip/Take方式:
csharp复制// 低效写法
var slowQuery = await _db.Queryable<Order>()
.OrderBy(o => o.CreateTime)
.Skip((pageIndex - 1) * pageSize)
.Take(pageSize)
.ToListAsync();
// 高效写法 - 使用最后记录ID
var fastQuery = await _db.Queryable<Order>()
.Where(o => o.Id > lastId)
.OrderBy(o => o.Id)
.Take(pageSize)
.ToListAsync();
6.3 事务处理最佳实践
推荐使用工作单元模式:
csharp复制public interface IUnitOfWork : IDisposable
{
ISqlSugarClient Db { get; }
void BeginTran();
void CommitTran();
void RollbackTran();
}
public class UnitOfWork : IUnitOfWork
{
private readonly ISqlSugarClient _db;
public UnitOfWork(ISqlSugarClient db)
{
_db = db;
}
public ISqlSugarClient Db => _db;
public void BeginTran() => _db.Ado.BeginTran();
public void CommitTran() => _db.Ado.CommitTran();
public void RollbackTran() => _db.Ado.RollbackTran();
public void Dispose() => _db.Ado.RollbackTran();
}
使用示例:
csharp复制public class UserService
{
private readonly IUnitOfWork _uow;
public UserService(IUnitOfWork uow)
{
_uow = uow;
}
public async Task CreateUserWithProfile(User user, UserProfile profile)
{
try
{
_uow.BeginTran();
await _uow.Db.Insertable(user).ExecuteCommandAsync();
profile.UserId = user.Id;
await _uow.Db.Insertable(profile).ExecuteCommandAsync();
_uow.CommitTran();
}
catch
{
_uow.RollbackTran();
throw;
}
}
}
在实际项目开发中,我特别推荐将SqlSugar与Repository模式结合使用。通过创建泛型仓储基类,可以大幅减少重复代码。同时要注意,虽然SqlSugar配置简单,但在复杂查询场景下,仍需要遵循数据库优化原则,比如合理使用索引、避免N+1查询等问题。
