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 Core 和 Mono 应用程序将数据存储到 SQLite 3 数据库中。最初设计是为了与 Xamarin.iOS 一起工作,但后来扩展到支持所有平台(包括 Xamarin 、.NET 、UWP 、Azure 等)。
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 对象以及 async 和 await 关键字。
创建表
一旦你定义了实体类,可以通过调用 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);
类似的,UpdateAsync
和 DeleteAsync
方法也可以用于异步更新和删除。
查询数据
查询数据最直接的方式是使用 Table
方法。它返回一个 AsyncTableQuery
实例,你可以添加谓词来进行 WHERE 条件约束,或者添加 ORDER BY 排序。直到你调用 ToListAsync 、FirstAsync 或 FirstOrDefaultAsync 等特殊检索方法时,数据库才会真正执行查询。
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(对象关系映射),使用 CreateTable
和 Table
方法来操作数据库。然而,你也可以通过手动执行 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);
在这个例子中:
-
SQLiteConnectionString 的
key
参数用于设置数据库的加密密码。 -
创建了一个 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

