在Unity中使用SQLite(Sqlite-net-pcl)

https://github.com/praeclarum/sqlite-net

  • sqlite-net-pcl:标准的 SQLite .NET 支持库,适用于大部分场景。

  • sqlite-net-sqlcipher:支持加密的 SQLite 版本,适用于需要加密数据库的场景。

  • sqlite-net-static :使用 P/Invoke 调用平台提供的 SQLite 实现,适合希望使用系统本地 SQLite 的场景。

  • sqlite-net-base:没有内嵌的 SQLitePCLRaw,适合需要自定义 SQLite 提供者的场景。

通常情况我们使用第一个

一. 简介

SQLite-net 是一个开源的轻量级库,允许 .NET.NET CoreMono 应用程序将数据存储到 SQLite 3 数据库中。最初设计是为了与 Xamarin.iOS 一起工作,但后来扩展到支持所有平台(包括 Xamarin.NETUWPAzure 等)。

SQLite-net 被设计为一个快速且方便的数据库层。其设计目标如下:

  • 非常容易与现有项目集成,并支持所有 .NET 平台。

  • 是一个对 SQLite 的轻量级封装,既快速又高效。(该库不应成为查询性能的瓶颈。)

  • 提供非常简单的方法来安全地执行 CRUD 操作和查询(使用参数),并以强类型的方式检索查询结果。

  • 无需强迫你修改类即可与数据模型配合使用。(包含一个小型的反射驱动的 ORM 层。)

二. 安装

推荐使用Nuget For Unity安装该库(因为有很多依赖),在Unity中仅安装该库还不够

先使用VS创建一个控制台或者类库,引入这个库然后编译一下,在bin目录找到

将里面的DLL放到Plugins下,你还需要发布到那个平台则将那个平台的依赖放进去(推荐保留目录结构)

三. 示例

完整文档:https://github.com/praeclarum/sqlite-net/wiki

该库包含了一些简单的属性,使用这些属性来控制表的构建。在一个简单的股票程序中,可能会这样使用:

复制代码
public class Stock
{
    [PrimaryKey, AutoIncrement]
    public int Id { get; set; }
    public string Symbol { get; set; }
}

public class Valuation
{
    [PrimaryKey, AutoIncrement]
    public int Id { get; set; }
    [Indexed]
    public int StockId { get; set; }
    public DateTime Time { get; set; }
    public decimal Price { get; set; }
    [Ignore]
    public string IgnoreField { get; set; }
}

一旦定义了模型中的对象,可以选择使用不同的 API。可以使用 "同步 API" ,其中每个调用会阻塞执行一个接一个;或者使用 "异步 API",它不会阻塞调用。

1.同步 API

一旦你定义了实体类,可以通过调用 CreateTable 自动在数据库中生成表:

复制代码
// 获取数据库文件的绝对路径
var databasePath = Path.Combine(Application.streamingAssetsPath, "MyData.db");

var db = new SQLiteConnection(databasePath);
db.CreateTable<Stock>();
db.CreateTable<Valuation>();
插入数据

可以使用 Insert 方法向数据库中插入数据。如果表中包含一个自动递增的主键,那么插入后该主键的值将自动返回:

复制代码
public static void AddStock(SQLiteConnection db, string symbol) {
    var stock = new Stock() {
        Symbol = symbol
    };
    db.Insert(stock);
    Debug.Log(stock.Id);
    Debug.Log(stock.Symbol);

}
更新和删除

类似地,也有用于更新 (Update) 和删除 (Delete) 的方法。

查询数据

最直接的查询数据方式是使用 Table 方法。你可以通过传递谓词来约束查询条件,或者添加 ORDER BY 子句:

复制代码
var query = db.Table<Stock>().Where(v => v.Symbol.StartsWith("A"));

foreach (var stock in query)
    Debug.Log("Stock: " + stock.Symbol);
低级查询

还可以使用 Query 方法进行低级查询,这允许你执行原生 SQL 查询:

复制代码
public static IEnumerable<Valuation> QueryValuations (SQLiteConnection db, Stock stock) {
    return db.Query<Valuation>("select * from Valuation where StockId = ?", stock.Id);
}

在这个例子中,Query 方法的泛型参数指定了要为每一行创建的对象类型。它可以是你的表类之一,也可以是任何其他类,只要该类的公共属性与查询返回的列匹配。例如,我们可以将上面的查询重写为:

复制代码
public class Val
{
    public decimal Money { get; set; }
    public DateTime Date { get; set; }
}

public static IEnumerable<Val> QueryVals(SQLiteConnection db, Stock stock) {
    return db.Query<Val>("select \"Price\" as \"Money\", \"Time\" as \"Date\" from Valuation where StockId = ?", stock.Id);
}
低级数据库更新

你可以使用 Execute 方法执行低级的数据库更新。例如:

复制代码
db.Execute("UPDATE Stock SET Symbol = ? WHERE Id = ?", "GOOG", stockId);

2.异步 API

异步库使用 任务并行库 (Task Parallel Library, TPL),因此你可以正常使用 Task 对象以及 asyncawait 关键字。

创建表

一旦你定义了实体类,可以通过调用 CreateTableAsync 异步方法自动生成数据库表:

复制代码
// 获取数据库文件的绝对路径
var databasePath = Path.Combine(Application.streamingAssetsPath, "MyData.db");

var db = new SQLiteAsyncConnection(databasePath);

// 异步创建表
await db.CreateTableAsync<Stock>();

Debug.Log("Table created!");
插入数据

你可以使用 InsertAsync 方法异步插入数据。如果表中包含一个自动递增的主键,那么插入后该主键的值将返回给你:

复制代码
var stock = new Stock()
{
    Symbol = "AAPL"
};

// 异步插入数据
await db.InsertAsync(stock);

Debug.Log(stock.Id);

类似的,UpdateAsyncDeleteAsync 方法也可以用于异步更新和删除。

查询数据

查询数据最直接的方式是使用 Table 方法。它返回一个 AsyncTableQuery 实例,你可以添加谓词来进行 WHERE 条件约束,或者添加 ORDER BY 排序。直到你调用 ToListAsyncFirstAsyncFirstOrDefaultAsync 等特殊检索方法时,数据库才会真正执行查询。

复制代码
var query = db.Table<Stock>().Where(s => s.Symbol.StartsWith("A"));

// 异步执行查询并返回列表
var result = await query.ToListAsync();

foreach (var s in result)
    Debug.Log("Stock: " + s.Symbol);
低级查询

你还可以通过 QueryAsync 方法直接执行 SQL 查询。除了 InsertAsync 等提供的修改操作外,你还可以使用 ExecuteAsync 方法直接在数据库中修改一组数据。

复制代码
public static async Task QueryValuationsAsync(SQLiteAsyncConnection db, Stock stock)
{
    var valuations = await db.QueryAsync<Valuation>("select * from Valuation where StockId = ?", stock.Id);
    foreach (var valuation in valuations)
    {
        Debug.Log($"Valuation Price: {valuation.Price}, Time: {valuation.Time}");
    }
}
获取标量值

ExecuteScalarAsync 方法允许你从数据库中轻松返回一个标量值(例如,计数、总和等):

复制代码
var count = await db.ExecuteScalarAsync<int>("select count(*) from Stock");

Debug.Log(string.Format("Found '{0}' stock items.", count));

3.手动 SQL

通常,sqlite-net 用作轻量级的 ORM(对象关系映射),使用 CreateTableTable 方法来操作数据库。然而,你也可以通过手动执行 SQL 查询来使用它,这提供了更灵活的控制。

示例:创建表、插入数据并查询
复制代码
// 创建一个名为 Stock 的表,包含一个 Symbol 字段
db.Execute("create table Stock(Symbol varchar(100) not null)");

// 使用参数化的 SQL 插入数据
db.Execute("insert into Stock(Symbol) values (?)", "MSFT");

// 查询所有 Stock 表中的数据
var stocks = db.Query<Stock>("select * from Stock");

在这个例子中:

  • 使用 Execute 方法执行创建表和插入数据的 SQL 语句。

  • Execute 方法执行 SQL 查询时使用参数化语句,避免了 SQL 注入问题。

  • 使用 Query 方法查询表中的所有数据并返回结果。


4.加密

如果你需要使用加密数据库,可以通过安装 sqlite-net-sqlcipher NuGet 包来实现。SQLCipher 为 SQLite 数据库提供了加密支持。

设置加密数据库
复制代码
var options = new SQLiteConnectionString(databasePath, true, key: "password");
var encryptedDb = new SQLiteAsyncConnection(options);

在这个例子中:

  • SQLiteConnectionStringkey 参数用于设置数据库的加密密码。

  • 创建了一个 SQLiteAsyncConnection 实例来连接加密数据库。

使用 PRAGMA 设置加密选项

你还可以通过 PRAGMA 设置来控制加密的行为。例如,控制加密的密钥导出函数(KDF)迭代次数等:

复制代码
var options2 = new SQLiteConnectionString(databasePath, true, 
    key: "password", 
    preKeyAction: db => db.Execute("PRAGMA cipher_default_use_hmac = OFF;"),
    postKeyAction: db => db.Execute("PRAGMA kdf_iter = 128000;"));

var encryptedDb2 = new SQLiteAsyncConnection(options2);

在这个例子中:

  • preKeyAction 设置了加密时的一些前置操作,如关闭 HMAC。

  • postKeyAction 设置了加密时的后续操作,如设置 KDF 迭代次数为 128000

这些设置可以帮助你自定义数据库加密的行为,增加安全性。

四. 可视化工具

推荐免费开源的可视化工具SqliteStudio

https://github.com/pawelsalawa/sqlitestudio

相关推荐
Forever_Hopeful5 小时前
华为鸿蒙 ArkTS 实战:基于 RelationalStore 的 SQLite 实现本地数据持久化
华为·sqlite·harmonyos
歪歪1005 小时前
介绍一下SQLite的基本语法和常用命令
数据库·sql·架构·sqlite
kobe_OKOK_5 小时前
有一次django开发实录
数据库·django·sqlite
重回19815 小时前
Python 操作 SQLite:Peewee ORM 与传统 sqlite3.connect 的全方位对比
数据库·oracle·sqlite
lph0095 小时前
Android compose Room Sqlite 应用 (注入式)
android·数据库·sqlite
大可门耳5 小时前
Qt读写SQLite示例
jvm·qt·sqlite
SmalBox1 天前
【光照】[高光反射specular]以UnityURP为例
unity·渲染
Crazy Struggle2 天前
一个拒绝过度设计的 .NET 快速开发框架:开箱即用,专注"干活"
.net·后台管理系统
唐青枫3 天前
比 AutoMapper 更快?C#.NET Mapster 深度解析
c#·.net