应使用 microsoft.data.sqlite:在包管理器控制台运行 install-package microsoft.data.sqlite,确认目标框架为 .net 6.0+,连接字符串用 data source=app.db,操作必须包裹 using 块并避免字符串拼接 sql。

直接用 Microsoft.Data.Sqlite,别碰 System.Data.SQLite —— 它已停止维护,.NET 6+ 项目里容易出兼容问题,尤其是跨平台部署时。
怎么装对的 NuGet 包
在 Visual Studio 的“包管理器控制台”里运行这行命令:
Install-Package Microsoft.Data.Sqlite
不是 System.Data.SQLite,也不是带 EF6 或 sqlite-net-pcl 的旧包。前者在 .NET Core/.NET 5+ 中缺少 async 支持,后者是 Xamarin 时代遗留,Microsoft.Data.Sqlite 是微软官方维护、专为现代 .NET 设计的轻量驱动。
- 确认项目目标框架是
.NET 6.0或更高(如.NET 8.0),否则可能提示“不兼容” - 如果项目用了 Entity Framework Core,
Microsoft.Data.Sqlite会自动作为Microsoft.EntityFrameworkCore.Sqlite的底层依赖被拉入,不用单独装 - 装完后检查
.csproj文件里是否出现<packagereference include="Microsoft.Data.Sqlite" version="8.0.4"></packagereference>这类条目(版本号随时间更新)
连接字符串怎么写才不出错
最简连接字符串就这一种写法,其他变体基本都埋雷:
Data Source=app.db
它会在应用当前目录(AppDomain.CurrentDomain.BaseDirectory)下创建或打开 app.db。别加 Version=3,也别写绝对路径(除非你明确要固定位置)。
-
Data Source=|DataDirectory|\app.db看起来规范,但|DataDirectory|默认为空,不显式设置会报IOException - 密码支持?
Microsoft.Data.Sqlite原生不支持加密,要加密必须用第三方扩展(如SQLitePCLRaw.bundle_e_sqlcipher),且需手动编译,普通项目别碰 - 如果数据库文件在子目录(比如
Data/app.db),用Path.Combine(AppContext.BaseDirectory, "Data", "app.db")拼路径,再传给Data Source=...,别硬写斜杠
执行 INSERT/UPDATE 为什么总丢数据
常见原因是没调 connection.Close() 或没用 using,导致连接未释放、事务未提交、缓存未刷盘。
正确写法必须包裹在 using 块里:
using var connection = new SqliteConnection("Data Source=app.db");
connection.Open();
using var command = connection.CreateCommand();
command.CommandText = "INSERT INTO Users (Name) VALUES (@name)";
command.Parameters.AddWithValue("@name", "Alice");
command.ExecuteNonQuery(); // 这行执行完,数据才真正落盘
- 别用字符串拼接 SQL(如
"INSERT INTO ... VALUES ('" + name + "')),100% 触发 SQL 注入,哪怕只是本地工具也别惯着自己 -
AddWithValue在某些边界值(如null、DateTime.MinValue)上推断类型不准,建议改用Add显式指定类型:command.Parameters.Add("@name", SqliteDbType.Text).Value = "Alice" - 批量插入超过 100 行?必须套
BeginTransaction(),否则性能暴跌,还可能触发 WAL 模式下的锁等待
查询结果读不出来或字段名对不上
根本原因:SQLite 是动态类型,列名默认是 SQL 语句里的原始别名,不一定是实体属性名;而且 SqliteDataReader 默认不支持按属性名索引。
安全读取方式只有两种:
- 用序号索引:
reader.GetString(0)、reader.GetInt32(1),前提是你知道 SELECT 字段顺序 - 用列名索引:
reader["UserName"],但要求 SQL 中显式起别名:SELECT Name AS UserName FROM Users - 如果用 Dapper 或 EF Core,它们内部做了映射层,可以按属性名绑定,但底层仍依赖列名或序号 —— 所以别在 SQL 里写
SELECT *,字段顺序一变就崩
另外注意:reader.Read() 必须先调一次才能读第一行,漏掉这步会返回空值或抛 InvalidOperationException。
最易被忽略的一点:SQLite 的 CREATE TABLE 语句里,如果主键字段声明为 INTEGER PRIMARY KEY,它会自动成为 rowid 别名,并支持自增;但写成 INT PRIMARY KEY 就不行 —— 类型必须是 INTEGER,大小写敏感,少个字母都会让 last_insert_rowid() 返回 0。










