.NET与Mono跨平台SQLite解决方案

跨平台开发中,SQLite因其轻量级和易于部署的特性而广受欢迎。然而,.NET和Mono平台上的System.Data.Sqlite库在默认情况下并不支持同时在Windows和Linux上使用相同的二进制文件。本文将介绍一种解决方案,使得开发者可以在.NET和Mono平台上无缝使用SQLite数据库。

介绍

System.Data.Sqlite是一个ADO.NET提供程序库,它在Windows平台上表现良好,但在Linux上的Mono环境中则需要使用不同的提供程序。同时在同一个应用程序中使用两个不同的提供程序并不是一个好的实践。标准的System.Data.Sqlite.Core包虽然在Windows上工作得很好,但在Linux上并不能直接使用,而且它还有一个不好的特性——包安装程序会尝试将Interop库添加到源代码控制系统中。混合模式库没有这个特性,但它只能在一个平台上运行,不能在Linux上运行。因此,尝试创建一个简单的解决方案,可以在Windows/.NET(x86/x86_64)和Linux/Mono(x86/x86_64/ARM)上运行。将使用NuGet系统来部署生成的包。

如何使用包

首先,需要下载附带的包。然后,创建一个本地的NuGet包源,并将下载的包放置在这里。接下来,在Visual Studio或MonoDevelop中将NuGet包安装到项目中(从版本5开始)。需要注意的是,System.Data.Sqlite.Core.MSILstd包包含了管理的System.Data.Sqlite.dll,必须在任何使用SQLite库的项目中引用。而System.Data.Sqlite.SqliteBinaries包包含了sqlite3.dll(针对x86/x86_64),必须只在可执行项目(应用程序或测试项目)中引用。

逻辑演示与“沙箱”解决方案

沙箱解决方案包含三个项目:应用程序、库和测试。应用程序是一个控制台可执行文件,使用System.Data.Sqlite;库是一个C#库,也使用System.Data.Sqlite;测试是一个使用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)上运行。

构建System.Data.Sqlite forMono

System.Data.Sqlite由两个部分组成——托管和非托管(interop)部分。在Microsoft .NET中,它们可以被组合成一个混合程序集。需要修改System.Data.Sqlite以使用标准的sqlite3库。首先,下载System.Data.Sqlite的源代码以制作包。当前版本是1.0.93.0(3.8.5)。下载后,需要编译。标准的编译过程是:导航到Setup目录,选择.NET版本,然后设置MSBUILD_ARGS环境变量,使用build.bat脚本进行编译。编译完成后,将生成的库放入System.Data.Sqlite.Core.MSILstd包,并附加到本文中。但这只是库的托管部分。还需要为sqlite3.dll创建部署程序,因为库不能没有它的非托管部分工作(在Linux上,sqlite可以作为包安装,但在Windows上,它必须与应用程序一起提供)。最简单的方法是使用NuGetPackage Explorer,打开System.Data.Sqlite.Core.MSIL包,并将dll替换为创建的dll。

NuGet部署Sqlite库的程序

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)/x86_64" /> </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。

测试结果

在不同的平台上测试了解决方案。测试数据库包含两个表(Pets和Houses)和三个实体(Cat、Dog和House)。逻辑相当简单。Cat是Pet,Dog是Pet,Pets住在House里,House有地址。这个示例使用了NHibernate作为ORM库。应用程序项目创建数据库,添加一些测试数据,然后查询结果。测试项目演示了原子操作。应用程序和测试项目使用了库项目。

在Windows 8.1 x86_64/.NET/VisualStudio 2013 Update 3上,需要安装一个特殊的包('NUnit Test Adapter')才能将nunit集成到VS2013中——安装后可以在'Test Explorer'中看到nunit测试。示例代码包括'console runner',因此即使没有安装'NUnit Test Adapter',也可以执行。应用程序正常工作。

在Windows 8.1 x86_64/.NET4.5.2/Xamarin Studio 5上,警告:在.NET x86_64调试在MonoDevelop/Xamarin Studio中不起作用。应用程序在'Run'模式下正常工作(在.NET x86_64调试模式在MonoDevelop中不起作用)。

在OpenSUSE Factory x86/Mono/MonoDevelop 5上,首先需要将包添加到MonoDevelop的本地包源中。之后,恢复和构建。应用程序也正常工作。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485