FreeSql 数据访问(Aegis.Core.FreeSql)
解决什么问题
Aegis.Core.FreeSql 负责数据库连接初始化、IFreeSql 实例注册和仓储自动扫描。它封装了 FreeSql ORM 的启动配置,让项目不需要手动构建 FreeSqlBuilder。
版本一致性
Aegis 框架当前基于 FreeSql 3.5.303。业务项目中如果需要直接引用 FreeSql 的扩展包(如数据库提供程序、FreeSql.DbContext 等),版本号必须与框架保持一致。版本不一致会导致运行时类型冲突或方法找不到。
需要保持一致的包:
| 包名 | 版本 |
|---|---|
FreeSql | 3.5.303 |
FreeSql.Repository | 3.5.303 |
FreeSql.Provider.PostgreSQL | 3.5.303 |
FreeSql.Provider.SqlServer | 3.5.303 |
FreeSql.DbContext | 3.5.303 |
只引用 Aegis.Core.FreeSql 而不单独安装 FreeSql 相关包的项目不需要关心这个问题,传递依赖会自动带进来。
框架升级时的注意事项
Aegis 框架升级时可能同步升级 FreeSql 版本。升级后需要注意:
- 业务项目中单独引用的 FreeSql 扩展包版本要同步更新,与框架保持一致
- FreeSql 大版本升级(如 3.x → 4.x)可能存在破坏性变更,升级前查阅 FreeSql 官方更新日志
- 框架的
Changelog.md中会标注 FreeSql 版本是否发生了变更
如何引入
NuGet 包:Aegis.Core.FreeSql
不通过 Component.deps.json 注册,在 Startup.cs 中手动调用:
services.AddDbSource<AegisDb>(options =>
{
options.ConnectionString = ConfigManager.Get("PostgreConnection");
options.DataType = "PostgreSQL";
});
services.AddDbRepositories<AegisDb>();
多数据源
项目需要访问多个数据库时,定义多个 IDbSource 实现类,分别注册:
services.AddDbSource<AegisDb>(options =>
{
options.ConnectionString = ConfigManager.Get("PostgreConnection");
options.DataType = "PostgreSQL";
});
services.AddDbRepositories<AegisDb>();
services.AddDbSource<HisDb>(options =>
{
options.ConnectionString = ConfigManager.Get("HisConnection");
options.DataType = "SqlServer";
});
services.AddDbRepositories<HisDb>();
每个数据源有独立的 IFreeSql<TDbSource> 泛型实例,仓储通过泛型参数自动关联到对应数据源。
配置项
AddDbSource<TDbSource>() 接收一个 DbOptions 配置回调:
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
DataType | string | — | 数据库类型:PostgreSQL、SqlServer |
ConnectionString | string | — | 数据库连接字符串 |
UseAutoSyncStructure | bool | false | 自动同步实体结构到数据库(仅开发环境) |
UseMonitorCommand | bool | false | 输出执行 SQL 到控制台(本地调试用) |
DataType 支持的值
FreeSql 支持的数据库类型均可用,Aegis 项目中常用的有:
PostgreSQLSqlServer
注册 API 说明
AddDbSource<TDbSource>
注册 IFreeSql<TDbSource> 实例到 DI 容器。完整签名:
services.AddDbSource<TDbSource>(
Action<DbOptions> setupAction,
Action<IFreeSql<TDbSource>> freeSqlSetup = null,
IEnumerable<EventHandler<ConfigEntityPropertyEventArgs>> freeSqlHandlers = null,
EventHandler exceptionHandler = null);
| 参数 | 说明 |
|---|---|
setupAction | 数据库配置(连接字符串、类型等) |
freeSqlSetup | 对 IFreeSql 实例的额外配置(如 AOP 订阅) |
freeSqlHandlers | 实体属性配置处理器(如统一设置 decimal 精度) |
exceptionHandler | 增删改查异常回调 |
AddDbRepositories<TDbSource>
扫描 TDbSource 所在程序集,注册所有继承自 BaseRepository 的仓储类到 DI 容器。
统一 decimal 精度
框架提供了 NewEvent() 辅助方法,统一将 decimal 类型映射为 decimal(18,6):
services.AddDbSource<AegisDb>(options =>
{
options.ConnectionString = connectionString;
options.DataType = "PostgreSQL";
}, null, new[] { ServiceCollectionExtensions.NewEvent() });
实体层约定
IDbSource 定义
每个数据库对应一个实现 IDbSource 的类:
public class AegisDb : IDbSource
{
public AegisDb(IFreeSql<AegisDb> sqlClient)
{
SqlClient = sqlClient;
}
public IFreeSql<AegisDb> SqlClient { get; }
}
这个类不需要写复杂逻辑,它给数据库连接一个明确的泛型标识。
Entity 常用标注
[Table(Name = "UserInfo")]
public class UserInfoEntity
{
[Column(IsPrimary = true)]
public long UserSeq { get; set; }
public string UserCode { get; set; }
public string UserName { get; set; }
// 创建时间:插入时自动赋值,更新时不覆盖
[Column(ServerTime = DateTimeKind.Local, CanUpdate = false)]
public DateTime CreateTime { get; set; }
// 更新时间:更新时自动刷新
[Column(ServerTime = DateTimeKind.Local)]
public DateTime UpdateTime { get; set; }
// 默认值:插入时使用 SQL 表达式赋值
[Column(InsertValueSql = "'0'")]
public bool IsDeleted { get; set; }
}
软删除
实现 IDeletedEntity 接口的实体会被框架自动过滤已删除数据:
public class UserInfoEntity : IDeletedEntity
{
[Column(IsPrimary = true)]
public long UserSeq { get; set; }
public bool Deleted { get; set; }
}
在仓储中临时关闭软删除过滤:
public List<UserInfoEntity> GetAllWithDeleted()
{
using (this.DisableDeleted())
{
return this.ToList();
}
}
框架扩展的 PagedList
Aegis 在 FreeSql 的 ISelect<T> 上扩展了 ToPagedList / ToPagedListAsync 方法,返回 PagedList<T> 结构体。
支持单表和多表联查(最多 8 张表),详见 分页与列表数据。
配套阅读
- Repository 层 — 数据访问层的目录结构和写法
- 事务 — UnitOfWork 和事务最佳实践
- 分页与列表数据 — 分页查询和 Dto 转换
- FreeSql 官方文档