在UWP中使用SQLite数据库,支持加密

SQLite-net 项目地址: https://github.com/praeclarum/sqlite-net

这个库支持Xamarin.*(iOS,Android等)、 .NET, .NET Core、Mono、UWP等主流系统和程序。支持对数据库文件的加密,其sqlcipher加密版为sqlite-net-sqlcipher,可以从Nuget获取。

如果在开发iOS / macOS应用中使用的也是基于sqlcipher实现的sqlite加密的库,如SQLite.swift,那么这二种程序生成的数据文件应该是可以互相兼容的。

安装

使用VS新建一个UWP项目,右键解决方案资源管理器中项目节点下的的引用节点,选择管理Nuget程序包,打开NuGet包管理器。切换到浏览标签,搜索sqlite-net-sqlcipher,选择第一项,点击右侧的安装,这个是sqlite-net带sqlcipher加密功能的版本。

uwp_sqlite_01.png

SQL方式操作SQLite

创建和连接数据库

var connection = new SQLite.SQLiteConnection("Test.db", key: "Mandarava");
...
connection.Dispose();

直接实例一个SQLiteConnection对象,并提供数据库的保存路径和加密密码(如果不需要可以提供null)来连接数据库,如果数据库不存在,则会自动创建数据文件。这里我只提供了文件名称Test.db,密码为Mandarava。最后,可以使用connection.Dispose方法来关闭数据库,当然,因为SQLiteConnection派生自IDisposable,所以使用using语句会更简洁一下。

那么Test.db这个数据文件到底保存在了哪里呢?可以用下面的代码来取得它的实际目录:

var currentLocalFolder = Windows.Storage.ApplicationData.Current.LocalFolder.Path;

所以最终的保存位置大概是:C:\Users\[用户名]\AppData\Local\Packages\xxxx\LocalState目录下。

创建表

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)来获得一个SQLiteCommand实例,使用command.ExecuteNonQuery来执行建表操作。这里创建一个User表用于存放User用户信息。这个表它有三个字段,分别是Id字段(Integer类型,主键),Name字段(字符串类型),Sex字段(字符串类型)。然后,根据这个表,可以创建一个对应的User实体类。

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中的?表示需要接收参数的占位符,然后在connection.CreateCommand方法中提供它们需要接收的参数值即可。

查询记录

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方法来进行查询,查询时需要提供一个结果所对应的实体类型,这里就是User类。

注:UWPConsole.Console.WriteLine是一个UWP控制台工具提供的方法,你可以在NuGet中查找并安装UWPConsole后来使用。

问题:command.ExecuteQuery<User>()必须提供查询结果对应的实体类型,这里就是User类,但如果我的sql是个join查询,这就出现问题了,没有对应的类可用。尝试提供Dictionary<obect, object>,List<object>都是接收到不到任何数据的。看了一下ExecuteQuery的实现,似乎确实没办法,而且ORM方式也似乎不支持join操作。

运行结果

到这里的全部代码如下:

//连接数据库,如果数据库不存在则自动创建
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}");
    }
}

运行结果如下,创建的二条记录成功被查询到了(控制台窗口由UWPConsole呈现):

uwp_sqlite_02.png

删除记录

sql = "DELETE FROM [User] WHERE ID = 1";
command = connection.CreateCommand(sql);
command.ExecuteNonQuery();

这个只需要提供Delete语句即可。

ORM方式操作SQLite

这种方式就比较简洁了,避开了繁杂的SQL语句。

这种方式下就要创建表的实体类,本例只有一个表User表,其对应的实体类就是User类,在前文中已经创建过了。

public class User
{
    [SQLite.PrimaryKey, SQLite.AutoIncrement]
    public int Id { get; set; }
    public string Name { get; set; }
    public string Sex { get; set; }
}

在这个类中,用[SQLite.PrimaryKey, SQLite.AutoIncrement]Id属性声明为数据库自动递增的主键字段。更多ORM属性可以查阅官方文档 ORM Attributes(注意MaxLength属性)。

创建表

connection.CreateTable<User>();

创建表时提供表的实体类型即可,这里就是User类,所创建的表的名称就是类的名称。

提示:这种ORM方式有一个问题,如果是C#/.Net app,如果想对代码进行混淆加密,混淆工具通常都会提供将类名、字段名混淆的功能,每次混淆后,类名、字段名很大可能都不同于上一次混淆结果(不过,有些工具似乎可以设置为相同),所以对于这种情况,就要禁止对相关类进行混淆了,否则你的app这次发布时运行正常,下次发布时可能就找不到原来的数据表了(因为相关的类名、字段名可能变了)。

插入记录

connection.Insert(new User() { Name = "钢蛋", Sex = "男" });
connection.Insert(new User() { Name = "约汉", Sex = "女" });
connection.Insert(new User() { Name = "铁锤", Sex = "男" });

插入很简单,就是提供一个User类的实例即可。

查询记录

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}");
}

查询也很简单,先用connection.Table<User>()取得要查询的表,再给Where方法一个查询条件即可。

uwp_sqlite_03.png

删除记录

connection.Delete<User>(1);

删除记录时,只需要提供一个主键值即可。比如这里要删除第1条钢蛋的记录,因为它的主键是Id,钢蛋的Id1,就提供其Id值即1即可。

其它

其它功能,比如异步处理、事务处理等可以参考官方文档

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345