FreeSql 不是“装上就能用”的 ORM,需显式配置提供程序和连接字符串、调用执行方法获取数据、手动管理事务及主键回填。

FreeSql 在 C# 里不是“装上就能用”的 ORM,它默认不自动管理连接生命周期,直接 new FreeSqlBuilder() 后就调用 Select
FreeSql 初始化时为什么不能只写 new FreeSqlBuilder()
FreeSql 构造必须显式指定数据库提供程序和连接字符串,否则 Ado 层为空,所有查询都会抛出 NullReferenceException 或 InvalidOperationException: Connection is not open。它不像 EF Core 那样有隐式默认配置。
- 必须传入
provider(如FreeSql.Provider.Sqlite、FreeSql.Provider.MySqlConnector),不能靠反射自动推断 -
connectionString要求格式严格:MySQL 必须带Database=xxx,SQLite 路径要绝对或带Data Source= - 建议启用
IsAutoSyncStructure = true,否则实体类改了字段,表结构不会自动更新(开发期很省事,上线前得关)
正确示例:
var fsql = new FreeSql.FreeSqlBuilder()
.UseConnectionString(FreeSql.DataType.Sqlite, "Data Source=database.db")
.UseAutoSyncStructure(true)
.Build();
查询数据时为什么 Select<T>() 返回空或报错
常见原因是没调用执行方法,Select<T>() 只返回 ISelect<T> 构建器,不是结果本身。直接打印或赋值给 List<T> 会得到类型对象,而非数据。
- 要取数据,必须链式调用
.ToList()、.First()、.Count()等终态方法 - 异步场景下要用
.ToListAsync(),但注意:FreeSql 的 async 方法底层仍是同步 I/O 封装,高并发时不如 Dapper 原生 async 真实 - 如果用了
.Where(x => x.Id == id)却查不到,检查实体类是否加了[Column(IsPrimary = true)],FreeSql 默认不认Id为主键
错误写法:var q = fsql.Select<User>(); Console.WriteLine(q);
正确写法:var users = fsql.Select<User>().Where(x => x.Status == 1).ToList();
插入/更新时事务没生效或主键不回填
FreeSql 默认关闭事务自动包装,Insert 和 Update 是单语句执行,不保证原子性;且 SQLite/MySql 对自增主键的回填行为差异大,容易误以为失败。
- 手动事务需用
fsql.Transaction(() => { ... }),不要依赖using (var t = fsql.CreateTransaction())—— 后者不自动提交 -
Insert后想获取新 ID,必须调用.ExecuteAffrows()或.ExecuteIdentity()(SQL Server/PostgreSQL 支持),SQLite 用.ExecuteInserted() - 批量插入别用循环
Insert,改用fsql.Insert(items).ExecuteAffrows(),否则 N 条数据触发 N 次连接开销
例如插入后取 ID:
var user = new User { Name = "张三" };
var newId = fsql.Insert(user).ExecuteInserted(); // SQLite 有效
FreeSql 的轻量和灵活性来自它的“不封装”——它把连接控制、事务边界、主键策略这些事都交还给开发者。你少写一行 .ToList(),或者漏掉一个 [Column],问题就藏在运行时,而不是编译期。


















