简介:面向.NET Framework 4.0平台的SQLite数据库连接引用库,完整包含32位与64位两套程序集,适合需要在桌面应用中实现离线数据存储的.NET开发者使用。压缩包内共50个文件,以System.Data.SQLite.dll为核心,同时提供pdb调试符号、config配置文件、exe示例程序、xml接口文档及测试数据库,整体大小4.26MB,目录区分Win32和x64,便于按目标架构直接引用。已有441人学习下载。该资源不仅涵盖ADO.NET接口下的SQLiteConnection、SQLiteCommand、SQLiteDataReader等常用对象,还支持事务处理、异步操作、DataAdapter与DataSet配合以及Entity Framework集成,能够帮助开发者快速搭建稳定高效的本地数据库方案。对于需要轻量级离线存储的小中型项目,选择对应位数的DLL即可完成连接配置,省去自行编译组件的繁琐,是上手.NET操作SQLite的实用工具包。
1. .net连接sqlite引用库:崩溃往往发生在SQLite.Interop这一层
很多人第一次用C#连接SQLite,以为把System.Data.SQLite.dll拖进引用就算完事。结果F5一跑,程序连窗体都弹不出来,直接抛出一个BadImageFormatException,或者一句“未能加载文件或程序集System.Data.SQLite”。真正干活的是SQLite.Interop.dll,一个原生C++库,进程是32位就认32位,64位就认64位,选错一个就翻车。这份“.net连接sqlite引用库”的rar,同时备齐了32位和64位两套程序集,还带了sqlite-netFx40这套面向.NET Framework 4.0的ADO.NET驱动,省去自己下两个官方包来回折腾的时间。适合正在维护WinForm、WPF老项目的工程师,也适合刚被位宽问题折磨得想砸电脑的人。
2. 为什么选sqlite-netFx40:版本矩阵与位宽的底层逻辑
2.1 netFx20 / netFx35 / netFx40:一套DLL,三代运行时
System.Data.SQLite的官方构建在历史上按目标运行时分成好几类:netFx20对应.NET Framework 2.0,netFx35对应3.5,netFx40对应4.0,再往后还有netFx45以及面向.NET Standard的版本。这个资源名字里的sqlite-netFx40,指的是绑定.NET Framework 4.0的那一套程序集。如果你的项目目标框架是.NET Framework 4.x,选它就是对的;如果你把netFx20那套硬塞进4.0项目,运行时大概率会看到“Mixed mode assembly is built against version 'v2.0.50727' of the runtime”这类异常。
很多老机器的部署环境其实很尴尬:装.NET Framework 3.5可能报错0x80072f8f导致离线安装失败,而4.0在Windows 7及之后的系统上基本都带着。这也让netFx40成了老系统上最稳妥的折中方案——不需要额外装3.5,4.0运行时几乎都在。如果目标机是Windows Server 2008 R2这种老服务器,先确认系统诊断里“.NET Framework 4.x”是否勾选,没勾就先把运行库补齐再谈SQLite。
另一个容易忽略的点是VC++运行库。SQLite.Interop.dll是原生C/C++代码,依赖MSVCR100.dll等运行时文件。开发机装了Visual Studio自然不缺,干净客户机上没有,会报“找不到SQLite.Interop.dll”的误导线索引。所以排查时要记住:找不到dll不一定是你文件没拷,可能是VC++运行时缺失。哪怕后来用.NET Framework 4.0把托管层问题解决了,原生依赖那一层还是绕不开。
2.2 为什么同一个库要带32位和64位兄弟
C#代码编译出来的是托管程序集,IL层面不区分位宽,但SQLite引擎本体是C写的,编译出来就是一个带x86或x64特征的native dll,进程位宽和dll位宽必须严格一致。32位进程加载64位dll会BadImageFormatException,反过来一样崩。Visual Studio里项目默认是AnyCPU,在64位系统上跑起来就是64位进程,在32位系统上跑起来就是32位进程——这也是同一个引用库必须同时给两套文件的原因。
| 进程位宽 | SQLite.Interop.dll位宽 | 结果 |
|---|---|---|
| 32 | 32 | 正常 |
| 32 | 64 | BadImageFormatException |
| 64 | 64 | 正常 |
| 64 | 32 | BadImageFormatException |
项目里“首选32位”勾选后,AnyCPU会在开发机上以x86方式调试,你把x86的dll拷进去能跑;发布时把勾去掉,部署到64位机器就变成64位进程,再用x86的dll立刻崩。这不是玄学,是AnyCPU的默认行为和你的本机调试设置不一致导致的。
这个包把两个位宽一次给齐,省去分别下载官方x86和x64安装包再对比文件名的工序。具体落地时,建议直接在配置管理器里复制出x86和x64两个配置,分别引用对应dll,发布时一个配置跑一遍,代码一行不用改。
3. 把引用库装进项目:六步操作从空工程到第一条查询
3.1 解压与工程准备:先把两样东西的版本对齐
从rar里解压后,先确认你手上是什么目录结构。常见做法是把x86和x64的System.Data.SQLite.dll分开放,SQLite.Interop.dll紧贴着各自版本的托管dll。保留这套结构复制到项目里的libs目录下,别自作聪明把两个System.Data.SQLite.dll混在一起——它们的文件名完全相同,一覆盖就废了。
对齐版本的另一个口径是目标框架。新建项目时选“.NET Framework 4.x”的Windows窗体或WPF模板,不要选“.NET Core”或“.NET 5+”,那份netFx40的驱动面向的是完整版.NET Framework。如果你非要在.NET 6上用SQLite,走NuGet的Microsoft.Data.Sqlite更合理,但这是另一套思路了。老项目维护场景下,引用库的方式更直接,不需要引入包管理器和上游依赖更新。
<Reference Include="System.Data.SQLite"> <HintPath>..\libs\System.Data.SQLite.dll</HintPath> <Private>True</Private> </Reference>这段是csproj里引用的标准写法。HintPath指向解压后放在libs根目录下的托管dll,Private为True表示生成时复制到输出目录,等价于Visual Studio里引用属性页的“复制本地”选项。注意这里只引了托管层System.Data.SQLite.dll,原生层SQLite.Interop.dll不能走引用通道,它需要在输出目录里存在。
3.2 添加引用与Copy Local:别让两个dll分家
把System.Data.SQLite.dll拖进项目引用后,马上膨胀两个开SysDetail目录里的文件确认是否真被复制。许多新手在解决方案里看到引用项就认为万事俱备,结果去bin\Debug下一看,SQLite.Interop.dll压根不在了。尤其是手头有老项目的人,csproj里WriteCopyLocal被改成False的情况很普遍。
ls -l bin/Debug/System.Data.SQLite.dll bin/Debug/SQLite.Interop.dll这一步是查缺补漏最简单的方式。两个文件必须同时出现在输出目录,且位宽和当前构建平台匹配。文件在但位宽不对,接下来就是BadImageFormatException;文件不在,就是DllNotFoundException。两种现象的排查路径完全不一样,先看清是“不存在”还是“加载不了”。
如果发现SQLite.Interop.dll没被复制,在csproj里把它声明成内容文件:
<None Include="..\libs\SQLite.Interop.dll"> <Link>SQLite.Interop.dll</Link> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None>CopyToOutputDirectory设为PreserveNewest表示每次编译时若源文件更新就复制,KeepNewer在大型项目里更常用。配合上面那条ls命令,确认输出目录两个文件齐了,再进行下一步。
3.3 连接串与第一条查询:Data Source、Version和参数化
C#打开sqlite数据库最典型的代码是这样:
string dbPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "app.db"); string connStr = $"Data Source={dbPath};Version=3;Pooling=True;"; using (var conn = new SQLiteConnection(connStr)) { conn.Open(); using (var cmd = new SQLiteCommand( "select count(*) from sqlite_master where type='table'", conn)) { int tableCount = Convert.ToInt32(cmd.ExecuteScalar()); Console.WriteLine($"表数量: {tableCount}"); } }逻辑说明:Data Source用的是进程工作目录加文件名,这种方式在调试和部署时不容易出现路径错位;Version=3是SQLite数据库文件格式版本,必须写,否则驱动不知道按什么格式打开;Pooling=True开启连接池,老驱动默认行为在不同版本里有差异,显式写出来能避免“数据库被占用”这种莫名错误。sqlite_master是SQLite内部维护的系统表,查它能得到当前库文件里有多少用户表,第一次连库时拿它做连通性验证最合适。
参数说明:conn.Open()在文件不存在时会自动以0字节创建空库,所以你第一次跑这段代码看到“成功打开”不代表表也建了,只代表路径可写。真正插入数据时,SQL语句里传值必须走参数化:
using (var cmd = new SQLiteCommand( "insert into user(name, age) values(@name, @age)", conn)) { cmd.Parameters.AddWithValue("@name", "张三"); cmd.Parameters.AddWithValue("@age", 28); cmd.ExecuteNonQuery(); }AddWithValue在SQLite驱动里是安全的,它内部会做类型推断,字符串转TEXT、整数转INTEGER,不会因为拼接单引号造成转义问题。尤其当用户输入里带单引号或反斜杠时,拼接SQL轻则报语法错误,重则构成注入,老项目里这种翻车是最多的。
4. 32位与64位程序的分工:加载机制与部署策略
4.1 谁在加载SQLite.Interop.dll:托管壳与原生库的纠葛
System.Data.SQLite.dll本身是托管程序集,里面用DllImport声明了对SQLite.Interop.dll的原生函数调用。运行时加载原生库时有自己的搜索顺序:已加载模块列表、应用程序目录、系统目录、PATH环境变量。也就是说,不管你把SQLite.Interop.dll放在哪个盘符下,只要不在应用程序目录或PATH里,它就找不到。
所以最省心的做法是把两个dll放在同一个目录,也就是程序集目录。有的团队习惯把原生dll放到子目录按位宽再分一层,这就要在app.config里配置探测路径:
<configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <probing privatePath="x86;x64" /> </assemblyBinding> </runtime> </configuration>这个配置的作用是让CLR在加载托管程序集时去x86或x64子目录里找。但注意:DllImport加载原生SQLite.Interop.dll时,Windows的搜索顺序不认privatePath,它只认标准dll搜索顺序。换句话说,app.config只能在托管层帮你在子目录里找到System.Data.SQLite.dll,原生dll被FindNextFile搜索时依然只看应用程序根目录、系统目录、PATH。按这个小细节,如果你真用子目录结构,还得额外调用SetDllDirectory或把子目录加进PATH,否则闪退。
因此回到这个引用库的场景,我建议保持最简单结构:把System.Data.SQLite.dll和SQLite.Interop.dll都放到输出根目录,不做子目录,让Windows的默认搜索顺序直接命中。要做32/64位切换,重点放在构建配置上,而不是运行时改探测路径。
4.2 平台配置隔离:同一份代码编出x86和x64两个版本
在配置管理器里新建x86和x64两个平台配置,csproj里用Condition按平台引用不同的dll路径:
<Reference Include="System.Data.SQLite" Condition="'$(Platform)'=='x86'"> <HintPath>..\libs\x86\System.Data.SQLite.dll</HintPath> <Private>True</Private> </Reference> <Reference Include="System.Data.SQLite" Condition="'$(Platform)'=='x64'"> <HintPath>..\libs\x64\System.Data.SQLite.dll</HintPath> <Private>True</Private> </Reference>Visual Studio在切换解决方案平台时会自动评估这些条件表达式。x86配置下编译器引用x86目录里的System.Data.SQLite.dll,输出目录里跟着的就是它旁边的SQLite.Interop.dll;x64配置同理。这个做法的价值是发布流程变成纯机械步骤:选配置、生成、打包,不会出现“开发机上是x86调试,发布产物却是AnyCPU跑成64位”的错位。
代码层面不需要任何#if条件判断。托管程序集加载的是同一个类名、同一个命名空间,SQLiteConnection的API在x86和x64下完全一致。平台差异被隔离在csproj引用层,这对维护多个OEM客户不同机器环境的情况特别有用。
4.3 部署机上还得补什么:VC++运行库与.NET Framework版本
| 缺失项 | 典型现象 | 解决方式 |
|---|---|---|
| .NET Framework 4.0 | 程序启动即报错,提示找不到运行时 | 安装.NET Framework 4.x运行库 |
| VC++ 2010运行库 | 报找不到SQLite.Interop.dll | 安装对应VC++可再发行组件 |
| SQLite.Interop.dll未复制 | DllNotFoundException,程序可启动但调用即崩 | 确认输出目录有该文件 |
| 写入目录无权限 | 连接串路径可读但创建库文件失败 | 用ProgramData或用户目录,不要用Program Files |
部署机的补丁清单和开发机差距很大,尤其是Windows Server Core或精简版系统,.NET Framework和VC++运行库都可能缺。还有一个反直觉的坑:在64位系统上,千万不要手动把32位的dll塞进System32,文件会被Windows on Windows重定向到SysWOW64,程序按System32路径加载到的还是64位版本。要验证就只能老老实实把dll放到应用程序目录。
最后提一句加密问题:SQLite明文库文件任何人拷走都能打开,System.Data.SQLite官方构建不提供加密。项目里有敏感数据,要么在应用层对字段先加密再存储,要么换SEE加密版本,别指望连接串里加个Password参数就万事大吉。
5. 避坑:五个加载失败现场与对应解法
5.1 BadImageFormatException:位宽不匹配的最具欺骗性表现
现象:程序崩在new SQLiteConnection或Open的时候,异常信息指向“试图加载格式不正确的程序”。在64位系统上调试时偶发,重新生成后又消失。
原因:进程以64位方式运行,加载的是x86版SQLite.Interop.dll。多见于AnyCPU解决方案在64位开发机上调试,或者在配置管理器里手动切到了x86平台但没有同步替换dll。
解决:先确认当前进程位宽——任务管理器里看“进程”标签,32位进程会标注*32。进程是64位就换x64版dll。更彻底的办法是按4.2节建x86和x64两套配置,每次发布都按目标平台全量生成,不混用。
5.2 Mixed mode assembly异常:A版驱动塞进B版运行时
现象:开窗时直接报“Mixed mode assembly is built against version 'v4.0.30319' of the runtime”,程序连Main方法都进不去。
原因:项目目标框架是.NET Framework 3.5,引用了netFx40的System.Data.SQLite.dll。这两个版本内部生成的CLR头不同,运行时直接拒绝加载。
解决:把项目目标框架升到4.x,或者换成netFx35版本的引用库。判断依据很简单:打开VS的项目属性,目标框架下拉框里当前选什么,就配什么版本的驱动。
5.3 DllNotFoundException:报错名字还是SQLite.Interop.dll
现象:System.Data.SQLite.dll正常加载,但一执行SQL就抛出DllNotFoundException,消息明确提到找不到SQLite.Interop.dll。
原因:原生库没在输出目录,或者依赖的VC++运行库缺失。这两类原因表面现象几乎一样,因为LoadLibrary失败最终都表现为“找不到模块”。
解决:先看输出目录两个dll在不在。在的话,用Dependency Walker或dumpbin /dependents查SQLite.Interop.dll依赖了哪些系统文件,最常见的缺的是MSVCR100.dll。装VC++ 2010可再发行组件,或把这几个msvc运行库也拷到程序目录。
5.4 未能加载文件或程序集:引用与运行时搜索顺序的连锁失败
现象:异常信息完整版是“未能加载文件或程序集System.Data.SQLite或它的某一个依赖项。系统找不到指定的文件。”但输出目录里dll是存在的。
原因:这个报错往往发生在dll存在但某个依赖链断裂时。典型情况是System.Data.SQLite.dll旁边的原生库位宽不对,CLR在解析依赖程序集时走到一半失败,错误信息最后落到“找不到指定的文件”,掩盖了真正的原因。
解决:打开程序集绑定日志查看器(Fusion Log Viewer),看到底是哪一层依赖解析失败。更快的做法是:把System.Data.SQLite.dll和SQLite.Interop.dll换成同一来源的同一版本。混用官方x86包和第三方编译的x64包,就是给自己埋雷。
5.5 开发机正常部署机崩:中间语言无关,原生库有关
现象:开发机Win11跑得流畅,拷到客户机Win Server 2012上双击就闪退,事件查看器里能看到.NET Runtime错误。
原因:开发机上Visual Studio装了完整的VC++工具链,系统目录里各种运行库齐全;客户机干干净净,缺的依赖全部暴露。SQLite.Interop.dll的开发机加载路径还可能从VS环境变量里命中,而部署机没有对应环境变量。
解决:把VC++运行库合并进部署程序,或者在安装包中预装可再发行组件。更加务实的做法是:在干净的虚拟机里建一个部署环境,安装包做完第一件事就是跑一次冒烟测试,别让“我本机可以”变成验收标准。这套流程血的教训:有一次客户紧急上线,我在自己机器上测了三轮都过,远程过去才发现客户机是32位系统,而我发布的是x64版。从那以后我每次下发.NET连接SQLite的程序,都强制在目标机上用DB Browser打开一次库文件,再跑一遍PRAGMA integrity_check和核心查询,这套流程帮我抓住了好几次拷错文件、选错位宽的乌龙。希望帮到你。
本文还有配套的精品资源,点击获取