适用于 .NET 和 Mono 的通用 System.Data.Sqlite 二进制文件






4.74/5 (12投票s)
如何制作一个几乎通用的 NuGet 'System.Data.Sqlite' 包,适用于 .NET 和 Mono
适用于 .NET 和 Mono 的通用 System.Data.Sqlite 二进制文件
引言
System.Data.Sqlite 是一个非常出色的 ADO .NET 提供程序库,但同一个二进制文件不能同时在 Windows(.NET) 和 Linux (Mono) 上使用。
在 Mono/Linux 上存在 Mono.Data.SQLite 提供程序,但在一个应用程序中使用两个不同的提供程序是个坏主意。
标准的 System.Data.Sqlite.Core 包(带 2 个 Interop 库)在 Windows 上运行良好,但在 Linux 上无法开箱即用。它还有一个糟糕的“功能”——包安装程序试图将 Interop 库添加到源代码管理系统。
混合模式库没有这个糟糕的“功能”,但它只能在一个平台上运行,并且在 Linux 上无法运行。
所以我试图做一个简单的解决方案,它可以在 Windows/.NET (x86/x86_64) 和 Linux/Mono (x86/x86_64/ARM) 上运行
它将使用 nuget 系统来部署生成的包
如何使用包
- 下载附带的包
- 创建本地 NuGet 包源并将下载的包放在此处
- 在 Visual Studio 或 MonoDevelop (5.0 版本起) 中将 NuGet 包安装到您的项目中
System.Data.Sqlite.Core.MSILstd - 包含托管 System.Data.Sqlite.dll 的包 - 解决方案中任何使用 SQLite 库的项目都必须引用它
您应该**只**选择 1 种变体
- System.Data.Sqlite.SqliteBinaries - 包含 sqlite3.dll (x86/x86_64) 的包 - **仅**必须在可执行项目(应用程序或测试项目)中引用
- System.Data.Sqlite.SqliteBinaries.x86 - 包含 sqlite3.dll (x86) 的包 - **仅**必须在可执行项目(应用程序或测试项目)中引用
- System.Data.Sqlite.SqliteBinaries.x86_64 - 包含 sqlite3.dll (x86_64) 的包 - **仅**必须在可执行项目(应用程序或测试项目)中引用
使用“沙箱”解决方案进行逻辑演示
解决方案包含 3 个项目
- 应用程序 - 使用 System.Data.Sqlite 的控制台可执行文件
- 库 - 使用 System.Data.Sqlite 的 C# 库
- 测试 - 使用 System.Data.Sqlite 的 nunit 测试应用程序
'应用程序' 使用包:System.Data.Sqlite.Core.MSILstd & System.Data.Sqlite.SqliteBinaries
'库' 使用包:System.Data.Sqlite.Core.MSILstd
'测试' 使用包:System.Data.Sqlite.Core.MSILstd & System.Data.Sqlite.SqliteBinaries
应用程序可以在 Windows、Linux (x86, x86_x64, ARM) 上运行
历史
文章
1. 为 Mono 构建 System.Data.Sqlite
System.Data.Sqlite 由两部分组成 - 托管部分和非托管(互操作)部分。它们可以在 Microsoft .NET 中组合成单个混合程序集。我们需要更改 System.Data.Sqlite 以使用标准的 sqlite3 库
首先 - 下载 System.Data.Sqlite 源代码以创建包。当前版本是 1.0.93.0(3.8.5)
下载后必须进行编译。标准的编译过程是
- 导航到 Setup 目录
- 选择 .NET 版本
- .NET 2.0 - set_2005.bat
- .NET 3.5 - set_2008.bat
- .NET 4.0 - set_2010.bat
- .NET 4.5 - set_2012.bat
- .NET 4.5.1 - set_2013.bat
- 设置构建参数 ("SET MSBUILD_ARGS=/property:UseInteropDll=false /property:UseSqliteStandard=true")
- 构建它 - "build.bat ReleaseManagedOnly"
我将生成的库放入 System.Data.Sqlite.Core.MSILstd 包中并将其附在本篇文章中
但这只是库的托管部分。我们还需要为 sqlite3.dll 制定部署过程,因为库没有它的非托管部分就无法工作(在 Linux 上,sqlite 可以作为包安装,但在 Windows 上,它必须与应用程序一起“到来”)
创建包的最简单方法是使用 NuGet Package Explorer,打开 System.Data.Sqlite.Core.MSIL 包并用创建的 dll 替换它们。
2. Sqlite 库的 NuGet 部署过程
NuGet 有一个特殊功能,可以在构建时将文件复制到项目输出目录。我们可以使用它将 sqlite3.dll (x86 & x86_64) 复制到输出目录
'System.Data.Sqlite.SqliteBinaries' 包结构
Dll 放置在包的 build/native NuGet 文件夹中。之后,创建了一个包含部署逻辑的特殊 .target 文件(以包名命名)
System.Data.Sqlite.SqliteBinaries.targets 内容
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BuildDependsOn>
copy_sqlite3_ALL_to_outputpath;
$(BuildDependsOn);
</BuildDependsOn>
</PropertyGroup>
<Target Name="copy_sqlite3_ALL_to_outputpath">
<Message text = "Copying sqlite3.dll (x86 and x86_x64)" />
<Copy SourceFiles="$(MSBuildThisFileDirectory)/native/x86/sqlite3.dll" DestinationFolder="$(OutputPath)/x86" />
<Copy SourceFiles="$(MSBuildThisFileDirectory)/native/x64/sqlite3.dll" DestinationFolder="$(OutputPath)/x64" />
</Target>
</Project>
成功构建后,NuGet 将自动将 sqlite3.dll 二进制文件复制到输出目录
也可以为特定体系结构创建包。这更简单。
System.Data.Sqlite.SqliteBinaries.x86 包结构
System.Data.Sqlite.SqliteBinaries.x86.targets 内容
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BuildDependsOn>
copy_sqlite3_x86_to_outputpath;
$(BuildDependsOn);
</BuildDependsOn>
</PropertyGroup>
<Target Name="copy_sqlite3_x86_to_outputpath">
<Message text = "Copying sqlite3.dll x86" />
<Copy SourceFiles="$(MSBuildThisFileDirectory)/native/sqlite3.dll" DestinationFolder="$(OutputPath)"/>
</Target>
</Project>
System.Data.Sqlite.SqliteBinaries.x86_64 包具有相同的结构,除了 .target 名称 - System.Data.Sqlite.SqliteBinaries.x86_64.targets
3. 测试生成的解决方案
开发和测试平台
- PC - Windows 8.1/.NET 4.5.2 (x86_64),配备 Visual Studio 2013 Update 3 和 Xamarin Studio 5 (与 MonoDevelop 5 相同)
- PC - OpenSuse Factory/Mono (x86),配备 MonoDevelop 5
- 家庭服务器 - CentOS 6/Mono (x86_64 和 KVM 上的 x86)
- BeagleBone Black - Debian/Mono (ARM)
不幸的是,我没有任何 Linux/Mono (x86_64) 机器进行测试。我希望如果解决方案可以在 x86 和 ARM 体系结构上为 Mono 工作 - 那么它也能在 x86_64 上工作 :-)
测试数据库有 2 个表(Pets 和 Houses)和 3 个实体(Cat、Dog 和 House)。逻辑相当简单。Cat 是 Pet,Dog 是 Pet,Pets 住在一个 House 里,House 有地址。这个例子使用了 NHibernate 作为 ORM 库。
应用程序项目创建数据库,添加一些测试数据,然后查询结果
Tests 项目演示了原子操作。
Application 和 Test 项目使用 Library 项目
4. 不同平台上的测试结果
4.1. PC/Windows 8.1 x86_64/.NET/VisualStudio 2013 Update 3
要将 nunit 集成到 VS2013 中,必须安装一个特殊的包('NUnit Test Adapter')- 安装后,您可以在“测试资源管理器”中看到 nunit 测试。示例代码包含“控制台运行程序”,因此即使未安装“NUnit Test Adapter”,它也可以执行
应用程序工作正常
4.2. PC/Windows 8.1 x86_64/.NET 4.5.2/Xamarin Studio 5
警告:在 .NET x86_64 上,MonoDevelop/Xamarin Studio 中的调试不起作用
应用程序在“运行”模式下工作正常(在 MonoDevelop 中,.NET x86_64 上的调试模式不起作用)
4.3. PC/OpenSUSE Factory x86/Mono/MonoDevelop 5
Sqlite3 本地库版本 - 3.8.5
首先,我们需要将我们的包添加到 MonoDevelop 的本地包源
之后 - 恢复并构建。应用程序也工作正常
4.4.a. 家庭文件服务器/CentOS 6 x86_64/Mono/在控制台中运行
Mono 版本 - 3.10.1 (master/ca51c3b) - 最新
Sqlite3 本地库版本 - 3.6.20
不工作。异常“SQL 逻辑错误或数据库丢失”
SQLite 版本是否太旧了?
搜索“CentOS SQLite 3.7”会给我们一个链接
ftp://ftp.pbone.net/mirror/ftp5.gwdg.de/pub/opensuse/repositories/Application:/Geo/CentOS_6/x86_64/sqlite-3.7.17-102.1.x86_64.rpm
现在我们有了
它能工作。请注意,“System.Data.SQLite”将无法与非常旧版本的 sqlite3 库一起工作
4.5. BeagleBone Black/Debian ARM/Mono/在控制台中运行
Mono 版本 - 3.6.1 (master/ddfd29c)
Sqlite3 本地库版本 - 3.7.13
应用程序工作正常
结论
请记住!此解决方案**可能**无法在 NuGet 2.7 之前的版本中正常运行(包恢复问题,2.7 版本之后默认启用此功能)。它也**可能**在 MonoDevelop 5.0 版本之前的版本中无法正常工作(其 NuGet 集成很差)。此外,System.Data.Sqlite 将无法与非常旧的 Linux 版本 SQLite 一起工作(1.0.93.0(3.8.5) 可与 3.7.13 一起工作,但不能与 3.6.20 一起工作),因此如果您计划支持具有旧 SQLite 版本的系统(如 CentOS),您必须在应用程序中包含最新的预编译本地 SQLite 库。
建议的解决方案可在所有现代开发平台上运行。您还可以将其应用于需要将本地库部署到 NuGet 包内的其他情况。