65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.74/5 (12投票s)

2014年9月21日

CPOL

6分钟阅读

viewsIcon

66288

downloadIcon

3776

如何制作一个几乎通用的 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 系统来部署生成的包

如何使用包

附带的包

  1. 下载附带的包
  2. 创建本地 NuGet 包源并将下载的包放在此处
  3. 在 Visual Studio 或 MonoDevelop (5.0 版本起) 中将 NuGet 包安装到您的项目中

System.Data.Sqlite.Core.MSILstd - 包含托管 System.Data.Sqlite.dll 的包 - 解决方案中任何使用 SQLite 库的项目都必须引用它

您应该**只**选择 1 种变体

  1. System.Data.Sqlite.SqliteBinaries - 包含 sqlite3.dll (x86/x86_64) 的包 - **仅**必须在可执行项目(应用程序或测试项目)中引用
  2. System.Data.Sqlite.SqliteBinaries.x86 - 包含 sqlite3.dll (x86) 的包 - **仅**必须在可执行项目(应用程序或测试项目)中引用
  3. System.Data.Sqlite.SqliteBinaries.x86_64 - 包含 sqlite3.dll (x86_64) 的包 - **仅**必须在可执行项目(应用程序或测试项目)中引用

使用“沙箱”解决方案进行逻辑演示

沙箱解决方案

解决方案包含 3 个项目

  1. 应用程序 - 使用 System.Data.Sqlite 的控制台可执行文件
  2. 库 - 使用 System.Data.Sqlite 的 C# 库
  3. 测试 - 使用 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)

下载后必须进行编译。标准的编译过程是

  1. 导航到 Setup 目录
  2. 选择 .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
  3. 设置构建参数 ("SET MSBUILD_ARGS=/property:UseInteropDll=false /property:UseSqliteStandard=true")
  4. 构建它 - "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. 测试生成的解决方案

开发和测试平台

  1. PC - Windows 8.1/.NET 4.5.2 (x86_64),配备 Visual Studio 2013 Update 3 和 Xamarin Studio 5 (与 MonoDevelop 5 相同)
  2. PC - OpenSuse Factory/Mono (x86),配备 MonoDevelop 5
  3. 家庭服务器 - CentOS 6/Mono (x86_64 和 KVM 上的 x86)
  4. 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 包内的其他情况。

© . All rights reserved.