跳到主要内容
SQLSugar 封装原理详解:架构与核心模块底层实现 | 极客日志
C#
SQLSugar 封装原理详解:架构与核心模块底层实现 综述由AI生成 SQLSugar 是.NET 生态下的轻量级 ORM 框架,详细解析其封装原理。内容涵盖整体架构设计(分层解耦、组件化)、实体映射机制(反射解析与缓存优化)、SQL 生成器(表达式树解析与多数据库适配)、连接管理(连接池与生命周期)、事务机制(手动与自动事务及嵌套事务)、AOP 模块(无侵入扩展)、缓存机制(内存与分布式)以及代码生成器。通过接口隔离、性能优化及安全性保障,实现了高效易用的数据访问层封装。
猫巷少女 发布于 2026/2/7 更新于 2026/6/1 532 浏览
一、SQLSugar 整体架构设计:轻量 ORM 的分层与组件化
SQLSugar 作为.NET 生态下的轻量级 ORM,其封装核心遵循'分层解耦、组件化复用'设计原则,整体架构分为基础设施层、核心功能层、应用适配层 三层,各层通过接口定义边界,既保证核心逻辑的独立性,又支持灵活扩展。
1.1 架构分层设计
层级
核心职责
关键组件 / 接口
基础设施层
提供底层依赖能力(连接管理、反射缓存、序列化),为上层提供基础支撑
IDbConnection、ICacheService、反射工具类
核心功能层
实现 ORM 核心逻辑(实体映射、SQL 生成、事务、AOP),是封装的核心载体
SqlSugarClient、ISqlSugarClient、SQL 生成器、AOP 模块
应用适配层
适配不同应用场景(IOC 集成、多数据库、代码生成),降低上层使用成本
IocConfig、IDbAdapter、CodeGenerator
1.1.1 核心组件依赖关系
SQLSugar 的核心组件通过'依赖注入 + 接口解耦'组织,关键依赖链如下:
SqlSugarClient(入口)
├─ 依赖 ConnectionConfig(配置)
├─ 依赖 IDbAdapter(数据库适配)
├─ 依赖 ICacheService(缓存)
├─ 依赖 AOP 委托链(日志、错误处理)
└─ 依赖 实体映射缓存(反射结果)
这种设计确保各组件可独立替换(如替换缓存为 Redis、新增数据库适配),符合'开闭原则'。
1.2 核心类与接口设计
1.2.1 入口类:SqlSugarClient 与 ISqlSugarClient
SQLSugar 通过 ISqlSugarClient 接口定义核心操作契约(CRUD、事务、查询构建),SqlSugarClient 作为实现类,是用户交互的唯一入口。其封装关键点:
构造函数封装 :接收 ConnectionConfig 或 List,内部初始化数据库适配器、连接池、映射缓存;
接口隔离 :将复杂操作拆解为子接口(如 IQueryable负责查询、IInsertable负责新增),避免类膨胀;
单例与多实例控制 :非 IOC 场景下支持手动创建实例,IOC 场景下通过 Scoped 生命周期避免线程安全问题。
1.2.2 适配接口:IDbAdapter(多数据库核心)
为支持多数据库,SQLSugar 封装了 IDbAdapter 接口,定义数据库专属语法的适配契约,不同数据库通过实现该接口完成差异化适配。接口核心方法:
public interface IDbAdapter
{
string ( ) ;
;
;
;
}
GetPageSql
string sql, long skip, long take, string orderBy
string GetDateFunc ()
string GetParamPrefix ()
Type GetCSharpType (string dbType )
SqlServerAdapter 实现 GetPageSql 生成 ROW_NUMBER() 分页;
MySqlAdapter 实现 GetPageSql 生成 LIMIT 分页;
OracleAdapter 实现 GetParamPrefix 返回:(Oracle 参数前缀)。
SqlSugarClient 初始化时,根据 ConnectionConfig.DbType 自动选择对应的 IDbAdapter 实例,确保 SQL 语法适配。
二、实体映射机制:ORM 的'对象 - 关系'桥梁封装 实体映射是 ORM 的核心,SQLSugar 通过'反射解析 + 缓存优化'封装实体类与数据库表的映射关系,避免重复反射开销,同时支持特性与约定两种映射方式。
2.1 映射信息的结构封装 SQLSugar 将实体映射信息封装为 EntityInfo 和 ColumnInfo 类,分别对应'表'和'字段'的映射元数据:
public class EntityInfo
{
public Type EntityType { get ; set ; }
public string TableName { get ; set ; }
public List<ColumnInfo> Columns { get ; set ; }
public ColumnInfo PrimaryKey { get ; set ; }
}
public class ColumnInfo
{
public string ColumnName { get ; set ; }
public string PropertyName { get ; set ; }
public Type PropertyType { get ; set ; }
public bool IsPrimaryKey { get ; set ; }
public bool IsIdentity { get ; set ; }
public bool IsNullable { get ; set ; }
public int Length { get ; set ; }
}
2.2 映射解析的封装流程 SQLSugar 在首次使用实体类(如 Queryable())时,触发映射解析,流程如下:
2.2.1 步骤 1:反射获取实体类信息 通过 Type.GetTypeInfo() 反射实体类,获取类特性([SugarTable])和属性信息:
var sugarTableAttr = entityType.GetCustomAttribute<SugarTableAttribute>();
var tableName = sugarTableAttr?.TableName ?? entityType.Name;
foreach (var prop in entityType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
var columnInfo = new ColumnInfo
{
PropertyName = prop.Name,
PropertyType = prop.PropertyType
};
var sugarColumnAttr = prop.GetCustomAttribute<SugarColumnAttribute>();
if (sugarColumnAttr != null )
{
columnInfo.ColumnName = sugarColumnAttr.ColumnName ?? prop.Name;
columnInfo.IsPrimaryKey = sugarColumnAttr.IsPrimaryKey;
columnInfo.IsIdentity = sugarColumnAttr.IsIdentity;
columnInfo.IsNullable = sugarColumnAttr.IsNullable;
columnInfo.Length = sugarColumnAttr.Length;
}
if (!columnInfo.IsPrimaryKey &&
(prop.Name.Equals("Id" , StringComparison.OrdinalIgnoreCase) ||
prop.Name.EndsWith("Id" , StringComparison.OrdinalIgnoreCase)))
{
columnInfo.IsPrimaryKey = true ;
if (prop.PropertyType.IsValueType && !prop.PropertyType.IsNullableType())
{
columnInfo.IsIdentity = true ;
}
}
entityInfo.Columns.Add(columnInfo);
}
2.2.2 步骤 2:缓存映射结果 为避免重复反射(反射性能开销较大),SQLSugar 将解析后的 EntityInfo 缓存到静态字典 ConcurrentDictionary<Type, EntityInfo>中,key 为实体类 Type,后续使用该实体类时直接从缓存获取:
private static readonly ConcurrentDictionary<Type, EntityInfo> _entityCache = new ();
public EntityInfo GetEntityInfo (Type entityType )
{
if (_entityCache.TryGetValue(entityType, out var entityInfo))
{
return entityInfo;
}
entityInfo = ParseEntityInfo(entityType);
_entityCache.TryAdd(entityType, entityInfo);
return entityInfo;
}
这一封装使映射解析的性能开销仅发生一次,显著提升后续操作效率。
2.3 类型映射的适配封装 不同数据库的字段类型与 C# 类型存在差异(如 SQL Server 的 nvarchar 对应 C# 的 string,MySQL 的 int 对应 C# 的 int),SQLSugar 通过 IDbAdapter 封装类型映射逻辑:
public Type GetCSharpType (string dbType )
{
return dbType.ToLower() switch
{
"varchar" or "char" or "text" => typeof (string ),
"int" or "tinyint" => typeof (int ),
"bigint" => typeof (long ),
"decimal" => typeof (decimal ),
"datetime" => typeof (DateTime),
_ => typeof (object )
};
}
在代码生成器或反向映射(数据库表→实体类)时,通过该方法自动匹配 C# 类型,避免手动转换错误。
三、SQL 生成器:从'对象操作'到'原生 SQL'的封装 SQL 生成是 SQLSugar 的核心能力之一,其通过'表达式树解析 + 数据库适配',将 Lambda 表达式(如 u => u.Age > 20)转化为适配目标数据库的参数化 SQL,同时避免 SQL 注入。
3.1 表达式树解析的封装逻辑 SQLSugar 的 IQueryable、Updateable等操作类,底层依赖 ExpressionVisitor(表达式访问器)解析 Lambda 表达式,将其转化为 SQL 条件、字段列表等片段。
3.1.1 核心类:SqlExpressionVisitor SqlExpressionVisitor 继承自 ExpressionVisitor,重写表达式树节点的访问方法(如 VisitBinary 处理二元表达式、VisitMember 处理成员访问),逐步构建 SQL 片段和参数列表。
以解析 u => u.Age > 20 && u.Name.Contains("张")为例,解析流程如下:
步骤 1:访问 Lambda 表达式根节点 public override Expression VisitLambda <T >(Expression<T> node )
{
return Visit(node.Body);
}
步骤 2:处理 AndAlso 二元表达式(&&) protected override Expression VisitBinary (BinaryExpression node )
{
if (node.NodeType == ExpressionType.AndAlso)
{
var leftSql = Visit(node.Left);
var rightSql = Visit(node.Right);
_sqlBuilder.Append($"({leftSql} AND {rightSql} )" );
}
return node;
}
步骤 3:处理 GreaterThan 表达式(>) protected override Expression VisitBinary (BinaryExpression node )
{
if (node.NodeType == ExpressionType.GreaterThan)
{
var left = Visit(node.Left) as string ;
var right = Visit(node.Right) as object ;
var paramName = $"@{_paramCounter++} " ;
_parameters.Add(new SugarParameter(paramName, right));
_sqlBuilder.Append($"{left} > {paramName} " );
}
return node;
}
步骤 4:处理 Contains 方法调用(u.Name.Contains("张")) protected override Expression VisitMethodCall (MethodCallExpression node )
{
if (node.Method.Name == nameof (string .Contains))
{
var member = Visit(node.Object) as string ;
var value = Visit(node.Arguments[0 ]) as object ;
var paramName = $"@{_paramCounter++} " ;
_parameters.Add(new SugarParameter(paramName, $"%{value } %" ));
_sqlBuilder.Append($"{member} LIKE {paramName} " );
}
return node;
}
最终生成的 SQL 条件的是:([Age] > @0 AND [Name] LIKE @1),参数列表为@0=20、@1='%张%',既完成了表达式解析,又通过参数化避免了 SQL 注入。
3.2 分页 SQL 的适配封装 不同数据库的分页语法差异较大(如 SQL Server 用 ROW_NUMBER(),MySQL 用 LIMIT),SQLSugar 通过 IDbAdapter.GetPageSql 封装分页逻辑,实现'一套代码,多库适配'。
3.2.1 SQL Server 分页实现 public string GetPageSql (string sql, long skip, long take, string orderBy )
{
var rowSql = $"SELECT *, ROW_NUMBER() OVER (ORDER BY {orderBy} ) AS RowNum FROM ({sql} ) AS Temp" ;
var pageSql = $"SELECT * FROM ({rowSql} ) AS Temp WHERE RowNum > {skip} AND RowNum <= {skip + take} " ;
return pageSql;
}
3.2.2 MySQL 分页实现 public string GetPageSql (string sql, long skip, long take, string orderBy )
{
return $"{sql} ORDER BY {orderBy} LIMIT {skip} ,{take} " ;
}
在 ToPageList 方法中,SQLSugar 先生成基础 SQL,再调用当前 IDbAdapter 的 GetPageSql 生成适配分页 SQL,无需用户关注数据库差异。
3.3 批量操作的 SQL 优化封装 批量新增、修改等操作若循环执行单条 SQL,会产生大量数据库交互开销。SQLSugar 通过'批量 SQL 拼接 + 参数复用'封装优化,减少交互次数。
3.3.1 批量新增的 SQL 封装 以 SQL Server 为例,批量新增时生成 VALUES 多行 SQL:
public string GenerateBatchInsertSql (List<User> users, EntityInfo entityInfo )
{
var columns = string .Join("," , entityInfo.Columns.Where(c => !c.IsIdentity).Select(c => $"[{c.ColumnName} ]" ));
var paramBuilder = new StringBuilder();
var valueBuilder = new StringBuilder();
int paramIndex = 0 ;
foreach (var user in users)
{
var values = new List<string >();
foreach (var column in entityInfo.Columns.Where(c => !c.IsIdentity))
{
var prop = entityInfo.EntityType.GetProperty(column.PropertyName);
var value = prop.GetValue(user);
var paramName = $"@{paramIndex++} " ;
paramBuilder.Append($"{paramName} ={value } ," );
values.Add(paramName);
}
valueBuilder.Append($"({string .Join("," , values)} )," );
}
var sql = $"INSERT INTO [{entityInfo.TableName} ] ({columns} ) VALUES {valueBuilder.ToString().TrimEnd(',' )} " ;
return sql;
}
这种封装将 N 条新增操作转化为 1 条 SQL,数据库交互次数从 N 次减少到 1 次,显著提升性能。
四、连接管理:从'创建'到'释放'的生命周期封装 SQLSugar 基于 ADO.NET 连接池,封装了连接的'获取 - 使用 - 释放'生命周期,避免连接泄露,同时支持多数据库连接管理。
4.1 连接池的集成封装 SQLSugar 默认使用 ADO.NET 内置连接池(无需额外配置),连接池的核心参数(如最大连接数、连接超时)通过连接字符串配置:
// SQL Server 连接字符串(配置连接池)
Server =localhost
Max Pool Size:连接池最大连接数(默认 100);
Connect Timeout:连接超时时间(默认 15 秒)。
SQLSugar 不重复造轮子,而是基于原生连接池优化连接获取逻辑,确保连接复用率。
4.2 连接生命周期的封装 SQLSugar 通过 IsAutoCloseConnection 配置,封装连接的自动释放逻辑,生命周期如下:
4.2.1 自动释放(IsAutoCloseConnection=true,推荐)
public List <T > Query <T >(string sql, List<SugarParameter> pars )
{
IDbConnection conn = null ;
try
{
conn = GetConnection();
var result = conn.Query<T>(sql, pars).ToList();
return result;
}
catch (Exception ex)
{
_aop.OnError?.Invoke(sql, pars, ex);
throw ;
}
finally
{
if (IsAutoCloseConnection && conn != null && conn.State == ConnectionState.Open)
{
conn.Close();
}
}
}
关键:conn.Close()并非关闭物理连接,而是将连接归还到连接池,供后续操作复用,减少连接创建的开销。
4.2.2 手动释放(IsAutoCloseConnection=false) 适用于长事务场景,需用户手动调用 Close() 或 Dispose() 释放连接:
using (var conn = db.Ado.GetConnection())
{
conn.Open();
db.Ado.BeginTran();
db.Ado.CommitTran();
}
通过 using 语句确保连接最终释放,避免泄露。
4.3 多数据库连接的封装 当项目需操作多个数据库时,SQLSugar 通过 ConfigId 标识不同连接配置,封装多连接管理:
private readonly ConcurrentDictionary<string , ConnectionConfig> _connectionConfigs = new ();
public void AddConnectionConfig (ConnectionConfig config )
{
_connectionConfigs.TryAdd(config.ConfigId, config);
}
public IDbConnection GetConnection (string configId = "MainDB" )
{
if (!_connectionConfigs.TryGetValue(configId, out var config))
{
throw new Exception($"未找到 ConfigId 为{configId} 的连接配置" );
}
IDbConnection conn = config.DbType switch
{
DbType.SqlServer => new SqlConnection(config.ConnectionString),
DbType.MySql => new MySqlConnection(config.ConnectionString),
DbType.Oracle => new OracleConnection(config.ConnectionString),
_ => throw new Exception("不支持的数据库类型" )
};
return conn;
}
用户通过 db.GetConnection("MySqlDB")即可切换到指定数据库,无需重新创建 SqlSugarClient 实例。
五、事务机制:'原子性'操作的封装实现 SQLSugar 封装了手动事务与自动事务两种模式,确保一组数据库操作的原子性(要么全成功,要么全回滚),同时支持嵌套事务。
5.1 手动事务的封装 手动事务基于 ADO.NET 的 IDbTransaction,封装事务的'开启 - 提交 - 回滚'流程:
private IDbTransaction _currentTransaction;
public void BeginTran ()
{
var conn = GetConnection();
if (conn.State != ConnectionState.Open)
{
conn.Open();
}
_currentTransaction = conn.BeginTransaction();
_isInTransaction = true ;
}
public void CommitTran ()
{
if (_currentTransaction != null )
{
_currentTransaction.Commit();
_currentTransaction.Dispose();
_currentTransaction = null ;
_isInTransaction = false ;
if (IsAutoCloseConnection)
{
GetConnection().Close();
}
}
}
public void RollbackTran ()
{
if (_currentTransaction != null )
{
_currentTransaction.Rollback();
_currentTransaction.Dispose();
_currentTransaction = null ;
_isInTransaction = false ;
if (IsAutoCloseConnection)
{
GetConnection().Close();
}
}
}
关键:开启事务后,后续所有 SQL 操作会自动绑定到_currentTransaction,确保在同一事务上下文执行。
5.2 自动事务的封装(基于 AOP 与 IOC) 在 ASP.NET Core 等 IOC 场景下,SQLSugar 通过 [Transaction] 特性 + AOP 拦截,实现事务自动管理,封装流程如下:
5.2.1 步骤 1:注册事务 AOP 服务
builder.Services.AddScoped<TransactionInterceptor>();
builder.Services.AddControllers(options =>
{
options.Filters.Add<TransactionInterceptor>();
});
5.2.2 步骤 2:事务拦截器实现 public class TransactionInterceptor : IActionFilter
{
private readonly ISqlSugarClient _db;
public TransactionInterceptor (ISqlSugarClient db )
{
_db = db;
}
public void OnActionExecuting (ActionExecutingContext context )
{
var hasTransactionAttr = context.ActionDescriptor.EndpointMetadata
.Any(em => em is TransactionAttribute);
if (hasTransactionAttr)
{
_db.Ado.BeginTran();
context.HttpContext.Items["IsInTransaction" ] = true ;
}
}
public void OnActionExecuted (ActionExecutedContext context )
{
if (context.HttpContext.Items.TryGetValue("IsInTransaction" , out var isInTransaction) &&
(bool )isInTransaction)
{
if (context.Exception == null )
{
_db.Ado.CommitTran();
}
else
{
_db.Ado.RollbackTran();
}
}
}
}
5.2.3 步骤 3:使用 [Transaction] 特性 [HttpPost("AddUserAndOrder" ) ]
[Transaction ]
public IActionResult AddUserAndOrder (User user, Order order )
{
_db.Insertable(user).ExecuteReturnIdentity();
_db.Insertable(order).ExecuteCommand();
return Ok();
}
这种封装使开发者无需手动编写事务代码,只需添加特性即可确保方法内所有操作的原子性。
5.3 嵌套事务的封装(基于保存点) SQLSugar 通过数据库'保存点(Savepoint)'封装嵌套事务,支持内层事务独立回滚,而不影响外层事务:
public void BeginNestedTran (string savepointName )
{
if (_currentTransaction == null )
{
throw new Exception("需先开启外层事务" );
}
_currentTransaction.Save(savepointName);
}
public void RollbackNestedTran (string savepointName )
{
if (_currentTransaction != null )
{
_currentTransaction.Rollback(savepointName);
}
}
db.Ado.BeginTran();
try
{
db.Insertable(user1).ExecuteCommand();
db.Ado.BeginNestedTran("Savepoint1" );
try
{
db.Insertable(user2).ExecuteCommand();
throw new Exception("嵌套事务出错" );
db.Ado.CommitTran();
}
catch
{
db.Ado.RollbackNestedTran("Savepoint1" );
}
db.Ado.CommitTran();
}
catch
{
db.Ado.RollbackTran();
}
最终仅 user1 插入成功,user2 被回滚,实现嵌套事务的灵活控制。
六、AOP 模块:'无侵入'扩展的封装 SQLSugar 通过 AOP(面向切面编程)封装 SQL 执行的拦截能力,支持日志记录、性能监控、错误处理等扩展,且不侵入核心业务代码。
6.1 AOP 的委托链封装 SQLSugar 的 AOP 基于'委托链'实现,定义了 SQL 执行各阶段的委托事件:
public class AopConfig
{
public Action<string , List<SugarParameter>> OnLogExecuting { get ; set ; }
public Action<string , List<SugarParameter>, long > OnLogExecuted { get ; set ; }
public Action<string , List<SugarParameter>, Exception> OnError { get ; set ; }
}
这些委托通过'多播委托'支持多个方法注册,例如同时注册日志记录和性能监控:
db.Aop.OnLogExecuting += (sql, pars) => Console.WriteLine(sql);
db.Aop.OnLogExecuting += (sql, pars) => _performanceMonitor.Start(sql);
6.2 AOP 的触发流程封装 在 SQL 执行的关键节点,SQLSugar 触发对应的 AOP 委托,流程如下:
public int ExecuteNonQuery (string sql, List<SugarParameter> pars )
{
long startTime = DateTime.Now.Ticks;
try
{
_aop.OnLogExecuting?.Invoke(sql, pars);
var conn = GetConnection();
var cmd = CreateCommand(conn, sql, pars);
int rows = cmd.ExecuteNonQuery();
long executeTime = (DateTime.Now.Ticks - startTime) / 10000 ;
_aop.OnLogExecuted?.Invoke(sql, pars, executeTime);
return rows;
}
catch (Exception ex)
{
_aop.OnError?.Invoke(sql, pars, ex);
throw ;
}
}
这种封装确保 AOP 逻辑与核心 SQL 执行逻辑解耦,开发者可按需扩展,无需修改 SQLSugar 源码。
6.3 AOP 的扩展场景
6.3.1 SQL 日志记录 db.Aop.OnLogExecuting = (sql, pars) =>
{
LogHelper.Info($"SQL: {sql} " );
LogHelper.Info($"Params: {string .Join("," , pars.Select(p => $"{p.ParameterName} ={p.Value} " ))} " );
};
6.3.2 性能监控 db.Aop.OnLogExecuting += (sql, pars) =>
{
HttpContext.Current.Items[$"SqlStartTime_{sql.GetHashCode()} " ] = DateTime.Now;
};
db.Aop.OnLogExecuted += (sql, pars, executeTime) =>
{
Console.WriteLine($"SQL 执行时间:{executeTime} ms" );
if (executeTime > 500 )
{
LogHelper.Warn($"SQL 执行超时:{sql} ,耗时:{executeTime} ms" );
}
};
七、缓存机制:'减少数据库查询'的封装实现 SQLSugar 封装了多级缓存能力(内存缓存、分布式缓存如 Redis),通过'缓存 key 生成 + 过期策略 + 缓存同步',减少重复数据库查询,提升性能。
7.1 缓存 key 的生成封装 为避免缓存冲突,SQLSugar 根据'查询标识 + 参数'生成唯一缓存 key,核心逻辑:
public string GenerateCacheKey (string sql, List<SugarParameter> pars )
{
var paramStr = string .Join("," , pars.OrderBy(p => p.ParameterName)
.Select(p => $"{p.ParameterName} ={p.Value ?? "null" } " ));
using var md5 = MD5.Create();
var bytes = Encoding.UTF8.GetBytes($"{sql} _{paramStr} " );
var hash = md5.ComputeHash(bytes);
return BitConverter.ToString(hash).Replace("-" , "" ).ToLower();
}
SQL:SELECT * FROM Users WHERE Age > @0;
参数:@0=20;
生成 key:a3f2d4e5b6c7a8b9c0d1e2f3a4b5c6d7。
7.2 内存缓存的封装 SQLSugar 默认使用内存缓存(基于 ConcurrentDictionary),封装缓存的'添加 - 获取 - 删除'操作:
public class MemoryCacheService : ICacheService
{
private readonly ConcurrentDictionary<string , CacheItem> _cache = new ();
private readonly Timer _expireTimer;
public MemoryCacheService ()
{
_expireTimer = new Timer(RemoveExpiredCache, null , 0 , 30000 );
}
public void Add <V >(string key, V value , int expireSeconds )
{
var cacheItem = new CacheItem
{
Value = value ,
ExpireTime = DateTime.Now.AddSeconds(expireSeconds)
};
_cache.AddOrUpdate(key, cacheItem, (k, old) => cacheItem);
}
public V Get <V >(string key )
{
if (_cache.TryGetValue(key, out var cacheItem))
{
if (cacheItem.ExpireTime > DateTime.Now)
{
return (V)cacheItem.Value;
}
_cache.TryRemove(key, out _);
}
return default ;
}
public void Remove (string key )
{
_cache.TryRemove(key, out _);
}
private void RemoveExpiredCache (object state )
{
var expiredKeys = _cache.Where(kv => kv.Value.ExpireTime <= DateTime.Now)
.Select(kv => kv.Key)
.ToList();
foreach (var key in expiredKeys)
{
_cache.TryRemove(key, out _);
}
}
private class CacheItem
{
public object Value { get ; set ; }
public DateTime ExpireTime { get ; set ; }
}
}
7.3 分布式缓存的封装(以 Redis 为例) 通过 ICacheService 接口解耦,SQLSugar 支持自定义分布式缓存(如 Redis),封装逻辑:
public class RedisCacheService : ICacheService
{
private readonly IDistributedCache _redisCache;
private readonly JsonSerializerOptions _jsonOptions;
public RedisCacheService (IDistributedCache redisCache )
{
_redisCache = redisCache;
_jsonOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
}
public void Add <V >(string key, V value , int expireSeconds )
{
var json = JsonSerializer.Serialize(value , _jsonOptions);
_redisCache.SetString(key, json, new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(expireSeconds)
});
}
public V Get <V >(string key )
{
var json = _redisCache.GetString(key);
if (string .IsNullOrEmpty(json))
{
return default ;
}
return JsonSerializer.Deserialize<V>(json, _jsonOptions);
}
public void Remove (string key )
{
_redisCache.Remove(key);
}
}
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = "localhost:6379" ;
});
builder.Services.AddScoped<ICacheService, RedisCacheService>();
builder.Services.AddSqlSugar(options =>
{
options.ConnectionConfigs = new List<ConnectionConfig> { };
options.CacheService = new RedisCacheService(builder.Services.BuildServiceProvider().GetRequiredService<IDistributedCache>());
});
7.4 缓存同步的封装(数据更新触发缓存清除) 当数据发生修改(Update/Delete/Insert)时,SQLSugar 自动清除相关缓存,避免缓存脏数据。核心逻辑:
public int Update <T >(T entity )
{
var entityInfo = GetEntityInfo(typeof (T));
var rows = ExecuteNonQuery(GenerateUpdateSql(entity), GenerateUpdateParams(entity));
var tableCacheKeys = _cacheService.GetAllKeys().Where(key => key.Contains(entityInfo.TableName)).ToList();
foreach (var key in tableCacheKeys)
{
_cacheService.Remove(key);
}
return rows;
}
更精细的缓存同步可通过 AOP 实现,例如根据修改的主键值,清除包含该主键的查询缓存。
八、代码生成器:'数据库结构→代码'的自动化封装 SQLSugar 代码生成器通过'数据库元数据解析 + 代码模板拼接',自动生成实体类、仓储类、服务类,减少重复编码。
8.1 数据库元数据解析的封装 代码生成器首先连接数据库,通过'信息_schema'视图查询表、字段、主键等元数据:
public List<TableInfo> GetTables (string connectionString )
{
using var conn = new SqlConnection(connectionString);
var sql = @"
SELECT
TABLE_NAME AS TableName,
TABLE_COMMENT AS TableDescription
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_SCHEMA = 'dbo'
" ;
return conn.Query<TableInfo>(sql).ToList();
}
public List<ColumnInfo> GetColumns (string connectionString, string tableName )
{
using var conn = new SqlConnection(connectionString);
var sql = @"
SELECT
COLUMN_NAME AS ColumnName,
DATA_TYPE AS DbType,
IS_NULLABLE AS IsNullable,
CHARACTER_MAXIMUM_LENGTH AS Length,
COLUMN_COMMENT AS ColumnDescription,
COLUMN_DEFAULT AS DefaultValue
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = @TableName AND TABLE_SCHEMA = 'dbo'
" ;
return conn.Query<ColumnInfo>(sql, new { TableName = tableName }).ToList();
}
public string GetPrimaryKey (string connectionString, string tableName )
{
using var conn = new SqlConnection(connectionString);
var sql = @"
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE OBJECTPROPERTY(OBJECT_ID(CONSTRAINT_SCHEMA + '.' + CONSTRAINT_NAME), 'IsPrimaryKey') = 1
AND TABLE_NAME = @TableName AND TABLE_SCHEMA = 'dbo'
" ;
return conn.QueryFirstOrDefault<string >(sql, new { TableName = tableName });
}
8.2 实体类代码生成的封装 根据解析的元数据,通过字符串拼接生成实体类代码,处理特性、注释等:
public string GenerateEntityCode (TableInfo table, List<ColumnInfo> columns, string primaryKey )
{
var codeBuilder = new StringBuilder();
codeBuilder.AppendLine("using System;" );
codeBuilder.AppendLine("using SqlSugar;" );
codeBuilder.AppendLine();
codeBuilder.AppendLine($"[SugarTable(\"{table.TableName} \", \"{table.TableDescription} \")]" );
codeBuilder.AppendLine($"public class {table.TableName} " );
codeBuilder.AppendLine("{" );
foreach (var column in columns)
{
if (!string .IsNullOrEmpty(column.ColumnDescription))
{
codeBuilder.AppendLine($" /// <summary>" );
codeBuilder.AppendLine($" /// {column.ColumnDescription} " );
codeBuilder.AppendLine($" /// </summary>" );
}
var attrBuilder = new StringBuilder();
attrBuilder.Append("[SugarColumn(" );
if (column.ColumnName == primaryKey)
{
attrBuilder.Append("IsPrimaryKey = true, " );
if (IsIntType(column.DbType))
{
attrBuilder.Append("IsIdentity = true, " );
}
}
if (column.ColumnName != column.ColumnName)
{
attrBuilder.Append($"ColumnName = \"{column.ColumnName} \", " );
}
attrBuilder.Append($"IsNullable = {column.IsNullable.Equals("YES" , StringComparison.OrdinalIgnoreCase).ToString().ToLower()} , " );
if (IsStringType(column.DbType) && column.Length.HasValue)
{
attrBuilder.Append($"Length = {column.Length.Value} , " );
}
if (!string .IsNullOrEmpty(column.DefaultValue))
{
attrBuilder.Append($"DefaultValue = \"{column.DefaultValue} \", " );
}
if (attrBuilder.ToString().EndsWith(", " ))
{
attrBuilder.Length -= 2 ;
}
attrBuilder.Append(")] " );
codeBuilder.AppendLine($" {attrBuilder} " );
var csharpType = GetCSharpType(column.DbType, column.IsNullable);
codeBuilder.AppendLine($" public {csharpType} {column.ColumnName} {{ get; set; }}" );
codeBuilder.AppendLine();
}
codeBuilder.AppendLine("}" );
return codeBuilder.ToString();
}
private bool IsIntType (string dbType )
{
return dbType.ToLower() is "int" or "tinyint" or "bigint" ;
}
private bool IsStringType (string dbType )
{
return dbType.ToLower() is "varchar" or "char" or "text" or "nvarchar" or "ntext" ;
}
private string GetCSharpType (string dbType, string isNullable )
{
var baseType = dbType.ToLower() switch
{
"varchar" or "char" or "text" => "string" ,
"int" => "int" ,
"bigint" => "long" ,
"decimal" => "decimal" ,
"datetime" => "DateTime" ,
_ => "object"
};
if (isNullable.Equals("YES" , StringComparison.OrdinalIgnoreCase) && IsValueType(baseType))
{
return $"{baseType} ?" ;
}
return baseType;
}
8.3 仓储类与服务类生成的封装 除实体类外,代码生成器还支持生成仓储类(数据访问层)和服务类(业务逻辑层),以仓储类为例:
public string GenerateRepositoryCode (string entityName )
{
var codeBuilder = new StringBuilder();
codeBuilder.AppendLine("using SqlSugar;" );
codeBuilder.AppendLine($"using {_namespace} .Entities;" );
codeBuilder.AppendLine();
codeBuilder.AppendLine($"public class {entityName} Repository" );
codeBuilder.AppendLine("{" );
codeBuilder.AppendLine(" private readonly ISqlSugarClient _db;" );
codeBuilder.AppendLine();
codeBuilder.AppendLine(" public {entityName}Repository(ISqlSugarClient db)" );
codeBuilder.AppendLine(" {" );
codeBuilder.AppendLine(" _db = db;" );
codeBuilder.AppendLine(" }" );
codeBuilder.AppendLine();
codeBuilder.AppendLine(" /// <summary>" );
codeBuilder.AppendLine(" /// 查询所有数据" );
codeBuilder.AppendLine(" /// </summary>" );
codeBuilder.AppendLine($" public List<{entityName} > GetAll()" );
codeBuilder.AppendLine(" {" );
codeBuilder.AppendLine($" return _db.Queryable<{entityName} >().ToList();" );
codeBuilder.AppendLine(" }" );
codeBuilder.AppendLine();
codeBuilder.AppendLine(" /// <summary>" );
codeBuilder.AppendLine(" /// 根据主键查询" );
codeBuilder.AppendLine(" /// </summary>" );
codeBuilder.AppendLine($" public {entityName} GetById(int id)" );
codeBuilder.AppendLine(" {" );
codeBuilder.AppendLine($" return _db.Queryable<{entityName} >().FindById(id);" );
codeBuilder.AppendLine(" }" );
codeBuilder.AppendLine();
codeBuilder.AppendLine("}" );
return codeBuilder.ToString();
}
九、总结:SQLSugar 封装的设计思想与优势 SQLSugar 的封装并非简单的'API 包装',而是基于'轻量高效、灵活扩展、易用性优先'的设计思想,通过以下核心设计实现:
接口解耦 :通过 IDbAdapter、ICacheService 等接口,实现多数据库、多缓存的灵活替换;
性能优化 :反射缓存、表达式树缓存、连接池复用、批量 SQL,减少性能开销;
易用性封装 :自动事务、代码生成、AOP 日志,降低开发者使用成本;
安全性保障 :参数化 SQL 避免注入,事务确保数据一致性;
扩展性设计 :AOP 拦截、自定义适配器,支持业务个性化扩展。
这些封装设计使 SQLSugar 在'轻量级'与'功能全面'之间取得平衡,既适合小型项目快速开发,也能支撑中大型项目的复杂需求,成为.NET 生态中 ORM 框架的优秀选择。
相关免费在线工具 Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown转HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
HTML转Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
JSON 压缩 通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
JSON美化和格式化 将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online