结合使用 SQLite.NET 和 Android
Xamarin 推荐的 SQLite.NET 库是一个非常基本的 ORM,可让你在 iOS 设备上的本地 SQLite 数据库中轻松存储和检索对象。 ORM 是对象关系映射的英文缩写,它是一个 API,可让你在数据库中保存和检索“对象”,而无需编写 SQL 语句。
若要将 SQLite.NET 库包含在 Xamarin 应用中,请将以下 NuGet 包添加到项目:
- 包名称:sqlite-net-pcl
- 作者:Frank A. Krueger
- ID:sqlite net pcl
- URL:nuget.org/packages/sqlite-net-pcl
有许多不同的 SQLite 包可供使用 - 请务必选择正确的一个(它可能不是搜索中排名最靠前的结果)。
重要
SQLite.NET 是 praeclarum/sqlite-net 存储库支持的第三方库。
获得可用的 SQLite.NET 库后,请按照以下三个步骤使用它来访问数据库:
添加 using 语句 - 将以下语句添加到需要数据访问的 C# 文件中:
using SQLite;
创建空白数据库 - 可以通过将文件路径传递给 SQLiteConnection 类构造函数来创建数据库引用。 无需检查文件是否已存在 - 如果需要,它将自动创建,否则将打开现有的数据库文件。 应根据本文档前面讨论的规则确定
dbPath
变量:var db = new SQLiteConnection (dbPath);
保存数据 - 创建 SQLiteConnection 对象后,将通过调用其方法(例如 CreateTable 和 Insert)来执行数据库命令,如下所示:
db.CreateTable<Stock> (); db.Insert (newStock); // after creating the newStock object
检索数据 - 要检索对象(或对象列表),请使用以下语法:
var stock = db.Get<Stock>(5); // primary key id of 5 var stockList = db.Table<Stock>();
基本数据访问示例
在 Android 上运行时,本文档的 DataAccess_Basic 示例代码如下所示。 该代码演示如何执行简单的 SQLite.NET 操作,并在应用程序的主窗口中以文本形式显示结果。
Android
以下代码示例演示了使用 SQLite.NET 库封装基础数据库访问的整个数据库交互。 该示例演示了以下操作:
创建数据库文件
通过创建对象来插入一些数据,然后保存它们
查询数据
需要包含以下命名空间:
using SQLite; // from the github SQLite.cs class
最后一个要求将 SQLite 添加到项目中。 请注意,SQLite 数据库表是通过向类(Stock
类)添加特性而不是通过 CREATE TABLE 命令来定义的。
[Table("Items")]
public class Stock {
[PrimaryKey, AutoIncrement, Column("_id")]
public int Id { get; set; }
[MaxLength(8)]
public string Symbol { get; set; }
}
public static void DoSomeDataAccess () {
Console.WriteLine ("Creating database, if it doesn't already exist");
string dbPath = Path.Combine (
Environment.GetFolderPath (Environment.SpecialFolder.Personal),
"ormdemo.db3");
var db = new SQLiteConnection (dbPath);
db.CreateTable<Stock> ();
if (db.Table<Stock> ().Count() == 0) {
// only insert the data if it doesn't already exist
var newStock = new Stock ();
newStock.Symbol = "AAPL";
db.Insert (newStock);
newStock = new Stock ();
newStock.Symbol = "GOOG";
db.Insert (newStock);
newStock = new Stock ();
newStock.Symbol = "MSFT";
db.Insert (newStock);
}
Console.WriteLine("Reading data");
var table = db.Table<Stock> ();
foreach (var s in table) {
Console.WriteLine (s.Id + " " + s.Symbol);
}
}
使用 [Table]
特性而不指定表名称参数将导致基础数据库表与类具有相同的名称(在本例中为“Stock”)。 如果直接针对数据库编写 SQL 查询而不是使用 ORM 数据访问方法,则实际的表名称非常重要。 同样,[Column("_id")]
特性是可选的,如果不存在,将向表中添加与类中的属性同名的列。
SQLite 特性
可应用于类以控制它们在基础数据库中的存储方式的常见特性包括:
[PrimaryKey] - 可以将此特性应用于整数属性,以强制其成为基础表的主键。 不支持复合主键。
[AutoIncrement] - 此特性将导致整数属性的值针对插入数据库的每个新对象自动递增
[Column(name)] -
name
参数设置基础数据库列的名称。[Table(name)] - 将类标记为能够存储在具有指定名称的基础 SQLite 表中。
[MaxLength(value)] - 尝试执行数据库插入时限制文本属性的长度。 使用代码应在插入对象之前验证此特性,因为仅在尝试数据库插入或更新操作时才会“检查”此特性。
[Ignore] - 导致 SQLite.NET 忽略此属性。 这对于具有无法存储在数据库中的类型的属性,或者对无法由 SQLite 自动解析的集合建模的属性特别有用。
[Unique] - 确保基础数据库列中的值是唯一的。
其中大多数特性都是可选的。 始终应该指定整数主键,以便可以对数据高效执行选择和删除查询。
更复杂的查询
SQLiteConnection
中的以下方法可用于执行其他数据操作:
Insert - 将新对象添加到数据库中。
Get<T> - 尝试使用主键检索对象。
Table<T> - 返回表中的所有对象。
Delete - 使用主键删除对象。
Query<T> - 执行返回多行(作为对象)的 SQL 查询。
Execute - 当你不希望从 SQL(例如 INSERT、UPDATE 和 DELETE 指令)返回行时,请使用此方法(而不是
Query
)。
按主键获取对象
SQLite.Net 提供了 Get 方法来根据主键检索单个对象。
var existingItem = db.Get<Stock>(3);
使用 Linq 选择对象
返回集合的方法支持 IEnumerable<T>
,因此可以使用 Linq 对表的内容进行查询或排序。 以下代码演示了使用 Linq 筛选掉以字母“A”开头的所有条目的示例:
var apple = from s in db.Table<Stock>()
where s.Symbol.StartsWith ("A")
select s;
Console.WriteLine ("-> " + apple.FirstOrDefault ().Symbol);
使用 SQL 选择对象
尽管 SQLite.Net 可以提供对数据的基于对象的访问,但有时你可能需要执行比 Linq 允许的查询更复杂的查询(或者可能需要更快的性能)。 可以将 SQL 命令与 Query 方法结合使用,如下所示:
var stocksStartingWithA = db.Query<Stock>("SELECT * FROM Items WHERE Symbol = ?", "A");
foreach (var s in stocksStartingWithA) {
Console.WriteLine ("a " + s.Symbol);
}
注意
直接编写 SQL 语句时,将会创建对数据库中表和列的名称的依赖关系,这些名称是从类及其特性生成的。 如果在代码中更改这些名称,请务必记得更新所有手动编写的 SQL 语句。
删除对象
主键用于删除行,如下所示:
var rowcount = db.Delete<Stock>(someStock.Id); // Id is the primary key
可以检查 rowcount
以确认有多少行受到影响(在本例中为已删除)。
结合多个线程使用 SQLite.NET
SQLite 支持三种不同的线程模式:单线程、多线程和序列化。 如果你希望不受任何限制地从多个线程访问数据库,可以将 SQLite 配置为使用序列化线程模式。 在应用程序中尽早设置此模式非常重要(例如,在 OnCreate
方法的开头)。
若要更改线程模式,请调用 SqliteConnection.SetConfig
。 例如,此代码行将 SQLite 配置为“序列化”模式:
using using Mono.Data.Sqlite;
...
SqliteConnection.SetConfig(SQLiteConfig.Serialized);
Android 版 SQLite 有一个限制,需要执行更多步骤。 如果对 SqliteConnection.SetConfig
的调用产生一个 SQLite 异常(如 library used incorrectly
),则必须使用以下解决方法:
链接到本机 libsqlite.so 库,使
sqlite3_shutdown
和sqlite3_initialize
API 可供应用使用:[DllImport("libsqlite.so")] internal static extern int sqlite3_shutdown(); [DllImport("libsqlite.so")] internal static extern int sqlite3_initialize();
在
OnCreate
方法的开头,添加此代码以关闭 SQLite,将其配置为“已序列化”模式,并重新初始化 SQLite:using using Mono.Data.Sqlite; ... sqlite3_shutdown(); SqliteConnection.SetConfig(SQLiteConfig.Serialized); sqlite3_initialize();
此解决方法也适用于 Mono.Data.Sqlite
库。 有关 SQLite 和多线程的详细信息,请参阅 SQLite 和多个线程。