在UWP中使用SQLite數(shù)據(jù)庫(kù),支持加密

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加密功能的版本。

uwp_sqlite_01.png

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)):

uwp_sqlite_02.png

刪除記錄

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è)查詢條件即可。

uwp_sqlite_03.png

刪除記錄

connection.Delete<User>(1);

刪除記錄時(shí),只需要提供一個(gè)主鍵值即可。比如這里要?jiǎng)h除第1條鋼蛋的記錄,因?yàn)樗闹麈I是Id,鋼蛋的Id1,就提供其Id值即1即可。

其它

其它功能,比如異步處理、事務(wù)處理等可以參考官方文檔。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容