WP 7 本地数据库
概述
为了存储和检索本地数据库中的数据,Windows Phone 应用程序使用 LINQ to SQL。
LINQ to SQL 对象模型主要是由 System.Data.Linq.DataContext 对象构成,可充当本地数据库的代理。LINQ to SQL 运行时负责桥接对象部分(DataContext 对象)和数据部分(本地数据库)。下图概括了这一关系。
数据上下文
数据上下文是一种代理,一个代表数据库的对象。数据上下文包含若干 Table 对象,其中的每一个对象都表示数据库中的一个表。每一个 Table 对象由对应数据库中数据行的实体所组成。每个实体都是一个具有属性的“简单传统 CLR 对象”(POCO)。每个实体上的属性决定数据库表结构,并定义数据对象模型与数据库架构之间的映射。例如,具有 Name 和 PhoneNumber 属性的实体将生成具有 Name 和 PhoneNumber 列的数据库表。
LINQ to SQL 提供了一些对象关系映射功能,托管应用程序可通过这些功能使用语言集成查询 (LINQ) 与关系数据库(仅指 Transact-SQL)进行通信。LINQ to SQL 将对象模型(通过 .NET Framework 托管代码表示)映射到关系数据库。当您的应用程序运行时,LINQ to SQL 将语言集成查询转换为 Transact-SQL,然后将查询发送至数据库进行执行。当数据库返回结果时,LINQ to SQL 将结果转换回可通过您自己的编程语言进行处理的对象。有关更多信息,请参阅 LINQ to SQL。
与使用 SQL Server 关系数据库的桌面应用程序类似,Windows Phone 应用程序可以通过 LINQ to SQL 使用本地数据库选择、插入、更新和删除数据。这样,您的 Windows Phone 应用程序就可以从 LINQ 的强大查询功能和关系数据库的存储效率中获益。由于手机所具有的资源少于 PC,因此本地数据库和典型数据库在某些方面存在差异。这些差异包括:
- 本地数据库将会在 Windows Phone 应用程序的进程中运行。和客户端服务器数据库不同(如 Microsoft SQL Server),它不会作为后台服务持续运行。
- 本地数据库仅可由对应的 Windows Phone 应用程序访问。由于数据库文件驻留在独立存储中,因此其他应用程序无法访问该数据。
- 本地数据库仅可通过 LINQ to SQL 访问;Transact-SQL 不受支持。
第一步:创建连接字符串
单个参数的用法
如果您只使用数据源属性,则不需要在连接字符串中包括属性名称,如以下示例中所示。
// Create the data context.
MyDataContext db = new MyDataContext ("isostore:/mydb.sdf")
在此示例中,isostore 前缀指示该文件位于独立存储中。
从安装文件夹中读取
安装文件夹不支持写入操作。当连接到该处的本地数据库时,必须使用 File Mode 属性将连接指定为只读。下面的示例演示如何建立与安装文件夹的只读连接。
// Create the data context.
MyDataContext db = new MyDataContext("Data Source = 'appdata:/mydb.sdf'; File Mode = read only;");
创建加密的数据库
如果需要加密数据库,则必须在连接字符串中指定一个密码,然后再创建数据库。在此示例中,在数据库创建之前指定了一个密码。
// Create the data context.
MyDataContext db = new MyDataContext("Data Source='isostore:/mydb.sdf';Password='securepassword';");
// Create an encrypted database after confirming that it does not exist.
if (!db.DatabaseExists()) db.CreateDatabase();
只读连接
下面的示例演示以只读方式连接到大型数据库。
// Create the data context.
MyDataContext db = new MyDataContext("Data Source = 'mydb.sdf'; File Mode = read only; Max Database Size = 256; Max Buffer Size = 1024;");
使用特定的区域性创建数据库
在此示例中,将创建一个具有德语区域性和区分大小写排序规则的数据库。
// Create the data context.
MyDataContext db = new MyDataContext("Data Source = 'mydb.sdf'; Culture Identifier = de-de; Case Sensitive = true;");
// Create a database after confirming that it does not exist.
if (!db.DatabaseExists()) db.CreateDatabase();
下表列出了本地数据库连接字符串支持的所有参数。
参数 |
说明 |
data source 或 datasource |
本地数据库文件的文件路径和文件名。如果仅指定此连接字符串属性,则只需要该属性值即可实例化一个数据上下文对象。 使用下面的前缀显式指定该路径的根位置。
如果未指定前缀,则文件路径适用于独立存储。 |
Password 或 Pwd 或 database password 或 ssce:database password |
数据库密码,最长为 40 个字符。如果未指定,则默认值为无密码。如果您在数据库上启用加密,则需要使用此属性。如果您指定密码,则会自动在数据库上启用加密。如果您指定一个空密码,则该数据库不会进行加密。 注意: 无法在数据库创建后进行加密。 数据库是使用 AES-128 加密的,而密码是使用 SHA-256 进行哈希处理的。 |
max buffer size 或 ssce:max buffer size |
本地数据库在开始将更改刷新到磁盘之前可以使用的最大内存量(以千字节为单位)。如果未指定,则默认值为 384。最大值为 5120。 |
max database size 或 ssce:max database size |
本地数据库的最大大小(以兆字节为单位)。如果未指定,则默认值为 32。最大值为 512。 |
Mode 或 file mode 或 ssce:mode |
打开数据库文件时要使用的模式。有效值如下:
|
Culture Identifier |
用于数据库的区域性代码。例如,en-US 代表“英语(美国)” 注意: 如果此属性在连接到现有数据库时使用,则会被忽略。 |
Case Sensitive 或 CaseSensitive |
用来确定数据库的排序规则是否区分大小写的 Boolean 值。必须设置为 true 才能启用区分大小写的排序规则;false 表示排序规则不区分大小写。如果未指定,则默认值为 false。 注意: 如果此属性在连接到现有数据库时使用,则会被忽略。 |
重要说明: |
|
某些 Microsoft SQL Compact 连接字符串参数可能适用于此 Windows Phone 应用程序平台 发行版。建议不要使用本主题中未列出的任何连接字符串参数。 |
第二步:创建表实体(表中有哪些属性)
[Table]
public class ToDoItem : INotifyPropertyChanged, INotifyPropertyChanging
{
// Define ID: private field, public property, and database column.
private int _toDoItemId;
[Column(IsPrimaryKey = true, IsDbGenerated = true, DbType = "INT NOT NULL Identity", CanBeNull = false, AutoSync = AutoSync.OnInsert)]
public int ToDoItemId
{
get { return _toDoItemId; }
set
{
if (_toDoItemId != value)
{
NotifyPropertyChanging("ToDoItemId");
_toDoItemId = value;
NotifyPropertyChanged("ToDoItemId");
}
}
}
// Define item name: private field, public property, and database column.
private string _itemName;
[Column]
public string ItemName
{
get { return _itemName; }
set
{
if (_itemName != value)
{
NotifyPropertyChanging("ItemName");
_itemName = value;
NotifyPropertyChanged("ItemName");
}
}
}
// Define completion value: private field, public property, and database column.
private bool _isComplete;
[Column]
public bool IsComplete
{
get { return _isComplete; }
set
{
if (_isComplete != value)
{
NotifyPropertyChanging("IsComplete");
_isComplete = value;
NotifyPropertyChanged("IsComplete");
}
}
}
// Version column aids update performance.
[Column(IsVersion = true)]
private Binary _version;
// Internal column for the associated ToDoCategory ID value
[Column]
internal int _categoryId;
// Entity reference, to identify the ToDoCategory "storage" table
private EntityRef<ToDoCategory>
> _category;
// Association, to describe the relationship between this key and that "storage" table
[Association(Storage = "_category", ThisKey = "_categoryId", OtherKey = "Id", IsForeignKey = true)]
public ToDoCategory Category
{
get { return _category.Entity; }
set
{
NotifyPropertyChanging("Category");
_category.Entity = value;
if (value != null)
{
_categoryId = value.Id;
}
NotifyPropertyChanging("Category");
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
// Used to notify that a property changed
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
#region INotifyPropertyChanging Members
public event PropertyChangingEventHandler PropertyChanging;
// Used to notify that a property is about to change
private void NotifyPropertyChanging(string propertyName)
{
if (PropertyChanging != null)
{
PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
}
}
#endregion
}
若要在代码中使用本地数据库功能,您需要在代码文件顶部添加以下指令。
using System.Data.Linq;
using System.Data.Linq.Mapping;
using Microsoft.Phone.Data.Linq;
using Microsoft.Phone.Data.Linq.Mapping;
下表显示了某些常见 LINQ to SQL 映射属性。有关完整列表,请参阅 System.Data.Linq.Mapping 命名空间。
属性 |
示例 |
说明 |
TableAttribute |
[Table] |
将某个类指定为与数据库表关联的实体类。 |
ColumnAttribute |
[Column(IsPrimaryKey = true)] |
将某个类与数据库表中的列关联。IsPrimaryKey 指定主键,默认情况下会为其创建一个索引。 |
IndexAttribute |
[Index(Columns="Column1,Column2 DESC", IsUnique=true, Name="MultiColumnIndex")] |
在表级别写入,指定表上的其他索引。每个索引都可涵盖一个或多个列。 |
AssociationAttribute |
[Association(Storage="ThisEntityRefName", ThisKey="ThisEntityID", OtherKey="TargetEntityID")] |
指定用于表示关联的属性,例如表示主键关联的外键。 |
第三步:创建上下文和表结构
若要创建本地数据库,必须首先定义数据上下文和实体。
这些类定义数据对象模型和数据库架构之间的映射。
LINQ to SQL 的对象关系功能根据这些映射详细信息来创建映射到对应数据上下文的关系数据库。
对于每个实体,使用 LINQ to SQL 映射属性指定映射详细信息。这些属性指定特定于数据库的功能,例如表、列、主键和索引
例如,以下代码显示名为 ToDoDataContext 的数据上下文以及名为 ToDoItem 的实体类的开头。
public class ToDoDataContext : DataContext
{
// Specify the connection string as a static, used in main page and app.xaml.
public static string DBConnectionString = "Data Source=isostore:/ToDo.sdf";
// Pass the connection string to the base class.
public ToDoDataContext(string connectionString): base(connectionString) { }
// Specify a single table for the to-do items.
public Table<ToDoItem> ToDoItems;// table
}
// Define the to-do items database table.
[Table]
public class ToDoItem : INotifyPropertyChanged, INotifyPropertyChanging
{
// Define ID: private field, public property, and database column.
private int _toDoItemId;
[Column(IsPrimaryKey = true, IsDbGenerated = true, DbType = "INT NOT NULL Identity", CanBeNull = false, AutoSync = AutoSync.OnInsert)]
public int ToDoItemId
{
get
{
return _toDoItemId;
}
set
{
if (_toDoItemId != value)
{
NotifyPropertyChanging("ToDoItemId");
_toDoItemId = value;
NotifyPropertyChanged("ToDoItemId");
}
}
}
. . .
. . .
. . .
第四步 :创建并连接创建好的数据库
在创建 DataContext 对象之后,可以创建本地数据库并执行一些其他数据库操作。以下代码示例演示如何创建基于 ToDoDataContext 类数据上下文的数据库。
// Create the database if it does not yet exist.
using (ToDoDataContext db = new ToDoDataContext("isostore:/ToDo.sdf"))
{
if (db.DatabaseExists() == false)
{
// Create the database.
db.CreateDatabase();
}
}
实例:
// Specify the local database connection string.
string DBConnectionString = "Data Source=isostore:/ToDo.sdf";
// Create the database if it does not exist.
using (ToDoDataContext db = new ToDoDataContext(DBConnectionString))
{
if (db.DatabaseExists() == false)
{
// Create the local database.
db.CreateDatabase();
// Prepopulate the categories.
db.Categories.InsertOnSubmit(new ToDoCategory { Name = "Home" });
db.Categories.InsertOnSubmit
(new ToDoCategory { Name = "Work" });
db.Categories.InsertOnSubmit(new ToDoCategory { Name = "Hobbies" });
// Save categories to the database.
db.SubmitChanges();
}
}
第五步:使用数据库(增删查改)
选择数据(查询)
在以下示例中,将使用 LINQ to SQL 查询名为 toDoDB 的 DataContext 对象,然后其结果被放置在名为 ToDoItems 的 ToDoItem 对象的 ObservableCollection 中。由于延迟执行,数据库查询直到实例化 ToDoItems 集合之后才会实际执行。
需要学习linq 的相关语法
// Define query to gather all of the to-do items.
var toDoItemsInDB = from ToDoItem todo in toDoDB.ToDoItems
select todo;
// Execute query and place results into a collection.
ToDoItems = new ObservableCollection<ToDoItem>(toDoItemsInDB);
插入数据(增加)
将数据插入数据库的过程分为两个步骤。首先在数据上下文中添加一个对象,然后调用数据上下文 SubmitChanges 方法将数据保存为数据库中的一行。
在以下示例中,创建了一个 ToDoItem 对象,并将其添加到 ToDoItems 可观察集合以及名为 toDoDB 的数据上下文中对应的数据库表。
// Create a new to-do item based on text box.
ToDoItem newToDo = new ToDoItem { ItemName = newToDoTextBox.Text };
// Add the to-do item to the observable collection.
ToDoItems.Add(newToDo);
// Add the to-do item to the local database.
toDoDB.ToDoItems.InsertOnSubmit(newToDo);
重要说明: |
数据直到调用 SubmitChanges 方法之后才保存到数据库。 |
更新数据(修改)
更新本地数据库中的数据分为三个步骤。首先,在数据库中查询要更新的对象。然后,按需要修改对象。最后,调用 SubmitChanges 方法将更改保存到本地数据库。
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
//Call base method
base.OnNavigatedFrom(e);
//Save changes to the database
toDoDB.SubmitChanges();
}
重要说明: |
数据直到调用 SubmitChanges 方法之后才更新到数据库。 |
删除数据(删除)
删除数据库中的数据也包含三个步骤:
首先,在数据库中查询要删除的对象。
然后,根据您需要删除一个还是多个对象,分别调用 DeleteOnSubmit 或 DeleteAllOnSubmit 方法,以将这些对象置于挂起删除状态。
最后,调用 SubmitChanges 方法将更改保存到本地数据库。
在以下示例中,从名为 toDoDB 的数据库中删除了一个 ToDoItem 对象。由于只删除一个对象,因此在 SubmitChanges 之前调用 DeleteOnSubmit 方法。
//Get a handle for the to-do item bound to the button
ToDoItem toDoForDelete = button.DataContext as ToDoItem;
//Remove the to-do item from the observable collection
ToDoItems.Remove(toDoForDelete);
//Remove the to-do item from the local database
toDoDB.ToDoItems.DeleteOnSubmit(toDoForDelete);
//Save changes to the database
toDoDB.SubmitChanges();
重要说明: |
数据直到调用 SubmitChanges 方法之后才会从数据库中删除。 |