Microsoft.Data.Sqlite是.NET 6+新项目的默认选择,纯托管、无原生依赖、体积小、与EF Core天然协同;System.Data.SQLite则适合有加密需求或维护旧WinForms/WPF项目。

用 Microsoft.Data.Sqlite 就够了,别碰 System.Data.SQLite —— 除非你明确需要加密或 WinForms 旧项目兼容。
选哪个 NuGet 包?Microsoft.Data.Sqlite 是当前 .NET 6+ 的默认选择
它纯托管、无原生依赖、体积小、和 EF Core 天然协同,安装命令就是:dotnet add package Microsoft.Data.Sqlite。而 System.Data.SQLite 虽然功能全,但自带 x86/x64 混合架构问题,新手容易卡在“处理器架构不匹配”报错里;它更适合有加密需求或维护老 WPF/WinForms 项目的场景。
常见错误现象:
-
System.BadImageFormatException:典型是项目目标平台(x64)和引用的System.Data.SQLite.dll(x86)不一致 - 发布到 Linux/macOS 报
DllNotFoundException:因为System.Data.SQLite依赖原生 SQLite 库,跨平台需额外部署
所以,新项目起步直接用 Microsoft.Data.Sqlite,省掉一半调试时间。
SqliteConnection 的连接字符串怎么写?路径必须绝对或用 AppDomain.CurrentDomain.BaseDirectory
SQLite 数据库就是一个文件,但路径写错会导致“文件不存在”或“被拒绝访问”。不要写 Data Source=app.db 这种相对路径——调试时工作目录不固定,很容易连不上。
推荐写法:
- 开发期:用
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "data.db")确保落在输出目录(如bin/Debug/net8.0/)下 - 发布期:若需固定位置(如用户文档目录),改用
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) - 避免硬编码盘符(如
C:\my.db),否则换机器就崩
连接字符串完整示例:new SqliteConnection($"Data Source={dbPath}"),不需要加 Version=3 或其他参数——Microsoft.Data.Sqlite 默认就是 SQLite 3。
建表和插入必须用 CREATE TABLE IF NOT EXISTS 和参数化查询
第一次运行程序要建表,第二次再运行就不能报“表已存在”错误。所以建表语句一定要带 IF NOT EXISTS;插入数据也绝不能拼接字符串,否则中文会乱码、数字字段可能被截断、更严重的是 SQL 注入漏洞。
正确写法要点:
- 建表:
"CREATE TABLE IF NOT EXISTS Users (Id INTEGER PRIMARY KEY AUTOINCREMENT, Name TEXT, Age INTEGER)" - 插入:
"INSERT INTO Users (Name, Age) VALUES (@name, @age)",然后用cmd.Parameters.AddWithValue("@name", "张三") - 读取时注意类型安全:
reader.GetInt32(0)比Convert.ToInt32(reader[0])更可靠,避免空值引发异常
漏掉 IF NOT EXISTS 会导致第二次运行直接抛出 SqliteException: table Users already exists;不参数化则 @name 值含单引号(如 O'Connor)就会让 SQL 语法出错。
连接和命令对象必须用 using 包裹,否则数据库文件会被锁死
SQLite 是文件锁机制,一个连接没关,下次打开就会卡住或报 database is locked。最稳妥的方式是所有 SqliteConnection 和 SqliteCommand 都套 using,让 Dispose() 自动释放资源。
反面例子:connection.Open(); ... // 忘了 connection.Close() → 后续任何操作都失败,重启程序都未必能解。
正例结构:
using (var connection = new SqliteConnection(dbPath))
{
connection.Open();
using (var cmd = connection.CreateCommand())
{
cmd.CommandText = "...";
cmd.ExecuteNonQuery();
}
} // 这里 connection 自动关闭并释放哪怕只做一次查询,也别图省事去掉 using——SQLite 的锁行为比想象中更敏感,尤其在快速连续操作时。
真正麻烦的不是语法,而是路径、锁、参数化这三点没对齐;只要把这三个地方盯死,SQLite 在 C# 里就是个安静的单文件,连服务器都不用起。


















