在.NET Standard 2.0的FiveM项目中使用Microsoft.Data.Sqlite遇阻
解决FiveM服务器端C#连接SQLite时的e_sqlite3.dll找不到问题
核心修复步骤
1. 调整NuGet包版本与引用
替换项目中的NuGet包为以下版本,确保兼容FiveM的Mono运行环境:
<ItemGroup> <PackageReference Include="CitizenFX.Core.Server" Version="1.0.*" /> <PackageReference Include="Microsoft.Data.Sqlite" Version="5.0.17" /> <PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.0.7" /> </ItemGroup>
选择5.0.x版本的Microsoft.Data.Sqlite是因为该版本对Mono环境的原生库支持更稳定,SQLitePCLRaw.bundle_e_sqlite3会包含预编译的原生e_sqlite3.dll文件。
2. 强制复制原生DLL到资源目录
FiveM不会自动加载NuGet包中的原生DLL,需在.csproj中添加配置,将原生库复制到资源输出目录:
<Target Name="CopySQLiteNativeDlls" AfterTargets="Build"> <Copy SourceFiles="$(NuGetPackageRoot)sqlitepclraw.lib.e_sqlite3\2.0.7\runtimes\win-x64\native\e_sqlite3.dll" DestinationFolder="$(OutputPath)" /> </Target>
若服务器为Linux系统,需替换为linux-x64目录下的libe_sqlite3.so文件。
3. 修正数据库文件路径
FiveM服务器端工作目录为服务器根目录,需用GetResourcePath获取资源绝对路径定位数据库文件:
string resourcePath = GetResourcePath(API.GetCurrentResourceName()); string dbPath = Path.Combine(resourcePath, "db.sqlite3");
需在Database类中添加using System.IO;和using static CitizenFX.Core.Native.API;引用。
4. 优化连接与资源管理
使用using语句自动释放数据库连接和命令资源,避免泄漏:
using (var connection = new SqliteConnection($"Data Source={dbPath}")) { connection.Open(); using (var command = connection.CreateCommand()) { // 命令执行逻辑 using (var reader = command.ExecuteReader()) { return Serialize(reader); } } }
修改后的完整代码
ServerMain.cs
using System; using System.Collections.Generic; using CitizenFX.Core; using static CitizenFX.Core.Native.API; namespace database.Server { public class ServerMain : BaseScript { public ServerMain() { RegisterCommand("dbTest", new Action<int, List<object>, string>((source, args, rawCommand) => { var db = new Database(); var result = db.Query("SELECT * FROM example_table WHERE example=8;"); foreach (var item in result) { foreach (var kv in item) { Debug.WriteLine($"{kv.Key}: {kv.Value.GetType().Name}"); } } }), false); } } }
Database.cs
using System; using System.Collections.Generic; using System.IO; using Microsoft.Data.Sqlite; using static CitizenFX.Core.Native.API; namespace database.Server { class Database { public List<Dictionary<string, object>> Query(string query, Dictionary<string, string> args=null) { string resourcePath = GetResourcePath(GetCurrentResourceName()); string dbPath = Path.Combine(resourcePath, "db.sqlite3"); using (var connection = new SqliteConnection($"Data Source={dbPath}")) { connection.Open(); using (var command = connection.CreateCommand()) { command.CommandText = query; if (args != null) { foreach (var item in args) { command.Parameters.AddWithValue(item.Key, item.Value); } } using (var reader = command.ExecuteReader()) { return Serialize(reader); } } } } public static List<Dictionary<string, object>> Serialize(SqliteDataReader reader) { var result = new List<Dictionary<string, object>>(); while (reader.Read()) { var row = new Dictionary<string, object>(); for (short i = 0; i < reader.FieldCount; i++) { string name = reader.GetName(i); row[name] = reader.GetValue(i); } result.Add(row); } return result; } } }
修改后的.csproj
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netstandard2.0</TargetFramework> <DebugType>portable</DebugType> <TargetName>$(AssemblyName).net</TargetName> <DefineConstants>SERVER</DefineConstants> </PropertyGroup> <ItemGroup> <PackageReference Include="CitizenFX.Core.Server" Version="1.0.*" /> <PackageReference Include="Microsoft.Data.Sqlite" Version="5.0.17" /> <PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.0.7" /> <Compile Include="../Shared/**/*.cs" /> </ItemGroup> <Target Name="CopySQLiteNativeDlls" AfterTargets="Build"> <Copy SourceFiles="$(NuGetPackageRoot)sqlitepclraw.lib.e_sqlite3\2.0.7\runtimes\win-x64\native\e_sqlite3.dll" DestinationFolder="$(OutputPath)" /> </Target> </Project>
问题原因分析
- FiveM运行环境限制:FiveM使用自定义Mono运行时,无法自动识别NuGet包中嵌入的原生DLL,必须手动复制到资源目录才能加载。
- 版本兼容性:高版本
Microsoft.Data.Sqlite(如7.x)的原生库加载逻辑在Mono环境下存在兼容性问题,5.0.x版本适配性更好。 - 路径错误:默认相对路径指向服务器根目录而非资源目录,导致数据库文件或DLL无法被找到。
内容的提问来源于stack exchange,提问作者Ghostino
相关产品推荐
相关产品推荐

