SQLite-net 項(xiàng)目地址: https://github.com/praeclarum/sqlite-net
這個(gè)庫(kù)支持Xamarin.*(iOS,Android等)、 .NET, .NET Core、Mono、UWP等主流系統(tǒng)和程序。支持對(duì)數(shù)據(jù)庫(kù)文件的加密,其sqlcipher加密版為sqlite-net-sqlcipher,可以從Nuget獲取。
如果在開發(fā)iOS / macOS應(yīng)用中使用的也是基于sqlcipher實(shí)現(xiàn)的sqlite加密的庫(kù),如
SQLite.swift,那么這二種程序生成的數(shù)據(jù)文件應(yīng)該是可以互相兼容的。
安裝
使用VS新建一個(gè)UWP項(xiàng)目,右鍵解決方案資源管理器中項(xiàng)目節(jié)點(diǎn)下的的引用節(jié)點(diǎn),選擇管理Nuget程序包,打開NuGet包管理器。切換到瀏覽標(biāo)簽,搜索sqlite-net-sqlcipher,選擇第一項(xiàng),點(diǎn)擊右側(cè)的安裝,這個(gè)是sqlite-net帶sqlcipher加密功能的版本。

SQL方式操作SQLite
創(chuàng)建和連接數(shù)據(jù)庫(kù)
var connection = new SQLite.SQLiteConnection("Test.db", key: "Mandarava");
...
connection.Dispose();
直接實(shí)例一個(gè)SQLiteConnection對(duì)象,并提供數(shù)據(jù)庫(kù)的保存路徑和加密密碼(如果不需要可以提供null)來(lái)連接數(shù)據(jù)庫(kù),如果數(shù)據(jù)庫(kù)不存在,則會(huì)自動(dòng)創(chuàng)建數(shù)據(jù)文件。這里我只提供了文件名稱Test.db,密碼為Mandarava。最后,可以使用connection.Dispose方法來(lái)關(guān)閉數(shù)據(jù)庫(kù),當(dāng)然,因?yàn)?code>SQLiteConnection派生自IDisposable,所以使用using語(yǔ)句會(huì)更簡(jiǎn)潔一下。
那么
Test.db這個(gè)數(shù)據(jù)文件到底保存在了哪里呢?可以用下面的代碼來(lái)取得它的實(shí)際目錄:var currentLocalFolder = Windows.Storage.ApplicationData.Current.LocalFolder.Path;所以最終的保存位置大概是:
C:\Users\[用戶名]\AppData\Local\Packages\xxxx\LocalState目錄下。
創(chuàng)建表
var sql = @"CREATE TABLE [User] (
[Id] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
[Name] VARCHAR(50) NOT NULL,
[Sex] VARCHAR(10) NOT NULL)";
var command = connection.CreateCommand(sql);
command.ExecuteNonQuery();
使用connection.CreateCommand(sql)來(lái)獲得一個(gè)SQLiteCommand實(shí)例,使用command.ExecuteNonQuery來(lái)執(zhí)行建表操作。這里創(chuàng)建一個(gè)User表用于存放User用戶信息。這個(gè)表它有三個(gè)字段,分別是Id字段(Integer類型,主鍵),Name字段(字符串類型),Sex字段(字符串類型)。然后,根據(jù)這個(gè)表,可以創(chuàng)建一個(gè)對(duì)應(yīng)的User實(shí)體類。
public class User
{
[SQLite.PrimaryKey, SQLite.AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
public string Sex { get; set; }
}
插入記錄
sql = "INSERT INTO [User] VALUES(?, ?, ?)";
command = connection.CreateCommand(sql, null, "Manda", "M");
command.ExecuteNonQuery();
sql中的?表示需要接收參數(shù)的占位符,然后在connection.CreateCommand方法中提供它們需要接收的參數(shù)值即可。
查詢記錄
sql = "SELECT * FROM [User]";
command = connection.CreateCommand(sql);
var userList = command.ExecuteQuery<User>();
foreach (var user in userList)
{
UWPConsole.Console.WriteLine($"{user.Id}\t{user.Name}\t{user.Sex}");
}
這里使用command.ExecuteQuery方法來(lái)進(jìn)行查詢,查詢時(shí)需要提供一個(gè)結(jié)果所對(duì)應(yīng)的實(shí)體類型,這里就是User類。
注:
UWPConsole.Console.WriteLine是一個(gè)UWP控制臺(tái)工具提供的方法,你可以在NuGet中查找并安裝UWPConsole后來(lái)使用。
問題:
command.ExecuteQuery<User>()必須提供查詢結(jié)果對(duì)應(yīng)的實(shí)體類型,這里就是User類,但如果我的sql是個(gè)join查詢,這就出現(xiàn)問題了,沒有對(duì)應(yīng)的類可用。嘗試提供Dictionary<obect, object>,List<object>都是接收到不到任何數(shù)據(jù)的??戳艘幌?code>ExecuteQuery的實(shí)現(xiàn),似乎確實(shí)沒辦法,而且ORM方式也似乎不支持join操作。
運(yùn)行結(jié)果
到這里的全部代碼如下:
//連接數(shù)據(jù)庫(kù),如果數(shù)據(jù)庫(kù)不存在則自動(dòng)創(chuàng)建
using (var connection = new SQLite.SQLiteConnection("Test.db", key: "Mandarava"))
{
//新建表
var sql = @"CREATE TABLE IF NOT EXISTS [User] (
[id] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
[name] VARCHAR(50) NOT NULL,
[sex] VARCHAR(10) NOT NULL)";
var command = connection.CreateCommand(sql);
command.ExecuteNonQuery();
//插入二條記錄
sql = "INSERT INTO [User] VALUES(?, ?, ?)";
command = connection.CreateCommand(sql, null, "Manda", "M");
command.ExecuteNonQuery();
command = connection.CreateCommand(sql, null, "Flower", "F");
command.ExecuteNonQuery();
//查詢記錄
sql = "SELECT * FROM [User]";
command = connection.CreateCommand(sql);
var userList = command.ExecuteQuery<User>();
foreach (var user in userList)
{
UWPConsole.Console.WriteLine($"{user.Id}\t{user.Name}\t{user.Sex}");
}
}
運(yùn)行結(jié)果如下,創(chuàng)建的二條記錄成功被查詢到了(控制臺(tái)窗口由UWPConsole呈現(xiàn)):

刪除記錄
sql = "DELETE FROM [User] WHERE ID = 1";
command = connection.CreateCommand(sql);
command.ExecuteNonQuery();
這個(gè)只需要提供Delete語(yǔ)句即可。
ORM方式操作SQLite
這種方式就比較簡(jiǎn)潔了,避開了繁雜的SQL語(yǔ)句。
這種方式下就要?jiǎng)?chuàng)建表的實(shí)體類,本例只有一個(gè)表User表,其對(duì)應(yīng)的實(shí)體類就是User類,在前文中已經(jīng)創(chuàng)建過了。
public class User
{
[SQLite.PrimaryKey, SQLite.AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
public string Sex { get; set; }
}
在這個(gè)類中,用[SQLite.PrimaryKey, SQLite.AutoIncrement]將Id屬性聲明為數(shù)據(jù)庫(kù)自動(dòng)遞增的主鍵字段。更多ORM屬性可以查閱官方文檔 ORM Attributes(注意MaxLength屬性)。
創(chuàng)建表
connection.CreateTable<User>();
創(chuàng)建表時(shí)提供表的實(shí)體類型即可,這里就是User類,所創(chuàng)建的表的名稱就是類的名稱。
提示:這種ORM方式有一個(gè)問題,如果是C#/.Net app,如果想對(duì)代碼進(jìn)行混淆加密,混淆工具通常都會(huì)提供將類名、字段名混淆的功能,每次混淆后,類名、字段名很大可能都不同于上一次混淆結(jié)果(不過,有些工具似乎可以設(shè)置為相同),所以對(duì)于這種情況,就要禁止對(duì)相關(guān)類進(jìn)行混淆了,否則你的app這次發(fā)布時(shí)運(yùn)行正常,下次發(fā)布時(shí)可能就找不到原來(lái)的數(shù)據(jù)表了(因?yàn)橄嚓P(guān)的類名、字段名可能變了)。
插入記錄
connection.Insert(new User() { Name = "鋼蛋", Sex = "男" });
connection.Insert(new User() { Name = "約漢", Sex = "女" });
connection.Insert(new User() { Name = "鐵錘", Sex = "男" });
插入很簡(jiǎn)單,就是提供一個(gè)User類的實(shí)例即可。
查詢記錄
var users = connection.Table<User>().Where(u => u.Sex == "男");
foreach (var user in users)
{
UWPConsole.Console.WriteLine($"{user.Id}\t{user.Name}\t{user.Sex}");
}
查詢也很簡(jiǎn)單,先用connection.Table<User>()取得要查詢的表,再給Where方法一個(gè)查詢條件即可。

刪除記錄
connection.Delete<User>(1);
刪除記錄時(shí),只需要提供一個(gè)主鍵值即可。比如這里要?jiǎng)h除第1條鋼蛋的記錄,因?yàn)樗闹麈I是Id,鋼蛋的Id是1,就提供其Id值即1即可。
其它
其它功能,比如異步處理、事務(wù)處理等可以參考官方文檔。