Xamarin.Forms 访问本地 SQLite 数据库

这篇文章主要介绍使用 ORM 方式的 SQLite.NET。 开发程序的时候通常需要一个数据库作为程序数据存储之用。和用于网络的 MySQL 不同,SQLite 作为本地数据库,不需要部署服务器,只有一个数据库文件。并且大多数 Android 应用程序都会使用 SQLite 作为自己的数据存储工具。

关键词:C# Xamarin.Forms Xamarin 数据库 SQLite ORM

Xamarin.Forms 作为可移植类库(PCL)或 .NET Standard 类库,尽管有第三方的 Nuget 包支持 ADO.NET,但官方用于 PCL 的 Nuget 包似乎只能使用 ORM。

如果你在特定平台开发而不使用 Xamarin.Forms(两种方式的区别请参见 Xamarin 入门 1),则可以使用 Mono.Data.Sqlite 命名空间使用 ADO.NET。关于 ADO.NET,之后会详细描述,或参阅官方文档。

为 Xamarin.Forms 项目添加 Nuget 包。在 Nuget 中搜索 sqlite-net-pcl 并确认作者是 Frank A.Krueger,以确保此包是 SQLite 官方产品。

通过实例化一个 SQLiteAsyncConnection 类建立对数据库的连接。该类的构造函数中有一个参数,需要为其指定 .db 数据库文件的地址。下面例子中的 .db3 格式后缀是 SQLite 3 的数据库文件。

事实上后缀名可以自定义,如果要把 SQLite 2 数据库文件升级到 SQLite 3,需要通过 SQLite 2 导出并从 SQLite 3 导入,而不能通过直接更改后缀名实现。

在 Xamarin.Forms 中,通过 LocalApplicationData 获取特定平台存储文件的文件夹,并通过 Path.Combine() 方法,把获取的文件夹路径和目标数据库文件的文件名合并成一个完整的数据库文件路径。

//获取当前平台的用于数据存储的路径并和数据库文件的名称合并,其中 file.db3 是文件名
var dbPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "file.db3"));
//实例化一个 SQLite 异步连接类,并把上面获取的文件夹路径赋予它
var conn = new SQLiteAsyncConnection(dbPath);

使用异步连接的 SQLiteAsyncConnection 而不是 SQLConnection 可以让数据库操作在后台进行。

另外需要注意的是,实例化的时候无需检查文件是否存在,SQLite 会自动判定是创建还是打开。

MSDN 的范例限定于其待办事项应用程序中自定义的 TodoItem 类。为了更好地介绍如何使用 SQLite.NET-PCL 和 ORM,这里重新封装了一个静态的使用泛型的方法类,并且同时操作两个数据库文件,因此增加了一个 GetConnection(bool isSystem) 方法获取对应的连接类。

下面的范例中,IIDItem 是一个自定义的接口,包含一个 int 类型的 ID 属性,这样所有带有 ID 属性的类都可以应用到上面。

    public static class SQL
    {
        //实例化两个只读的异步连接类,并设定数据库文件名为 001.dat 和 002.dat
        private static readonly SQLiteAsyncConnection systemDatabase = 
            new SQLiteAsyncConnection(Path.Combine(Environment.GetFolderPath
                (Environment.SpecialFolder.LocalApplicationData), "001.dat"));

        private static readonly SQLiteAsyncConnection docDatabase =
            new SQLiteAsyncConnection(Path.Combine(Environment.GetFolderPath
                (Environment.SpecialFolder.LocalApplicationData), "002.dat"));
        //自定义一个 GetConnection 方法,通过指定 isSystem 的值,获取用于系统的数据库文件或用于文档的数据库文件
        private static SQLiteAsyncConnection GetConnection(bool isSystem) => isSystem ? systemDatabase : docDatabase;

        /// <summary>
        /// 执行语句查询并使用ORM映射返回每一行的结果
        /// </summary>
        /// <typeparam name="T">返回的结果类型</typeparam>
        /// <param name="query">查询</param>
        /// <param name="args">参数</param>
        /// <returns>每一行结果</returns>
        public static Task<List<T>> QueryAsync<T>(string query, bool isSystem, params object[] args) where T : new() => GetConnection(isSystem).QueryAsync<T>(query, args);

        /// <summary>
        /// 异步查询数据表
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <returns>异步查询</returns>
        public static AsyncTableQuery<T> TableQueryAsync<T>(bool isSystem) where T : new() => GetConnection(isSystem).Table<T>();

        public static void CreateTableAsync<T>(bool isSystem) where T : new() => GetConnection(isSystem).CreateTableAsync<T>().Wait();


        /// <summary>
        /// 获取指定ID的类实例(一行数据)
        /// </summary>
        /// <typeparam name="T">映射数据表的类</typeparam>
        /// <param name="id">指定的ID</param>
        /// <returns></returns>
        public static Task<T> GetItemByIDAsync<T>(int id, bool isSystem) where T : IIDItem, new() => TableQueryAsync<T>(isSystem).Where(i => i.ID == id).FirstOrDefaultAsync();

        /// <summary>
        /// 保存/更新类的实例(一行数据)
        /// </summary>
        /// <param name="item">要保存的实例</param>
        /// <returns>结果状态码</returns>
        public static Task<int> SaveItemAsync(IIDItem item, bool isSystem) => item.ID != 0 ? GetConnection(isSystem).UpdateAsync(item) : systemDatabase.InsertAsync(item);

        /// <summary>
        /// 删除类的实例(一行数据)
        /// </summary>
        /// <param name="item">要删除的类的实例</param>
        /// <returns>结果状态码</returns>
        public static Task<int> DeleteItemAsync(IIDItem item, bool isSystem) => GetConnection(isSystem).DeleteAsync(item);
    }

未完待续。

发表评论

电子邮件地址不会被公开。 必填项已用*标注