导出 (0) 打印
全部展开

Windows Phone 本地数据库概述

2012/2/9

使用 Windows Phone OS 7.1,可以将关系数据存储在驻留在应用程序独立存储容器的本地数据库中。Windows Phone 应用程序使用 LINQ to SQL 执行所有数据库操作;LINQ to SQL 用于定义数据库架构、选择数据,并将更改保存到驻留在独立存储中的基础数据库文件。本主题提供了在 Windows Phone 应用程序中使用本地数据库的概述。关于创建使用本地数据库的应用程序的分步演练,请参阅如何为 Windows Phone 创建基本的本地数据库应用程序

为了存储和检索本地数据库中的数据,Windows Phone 应用程序使用 LINQ to SQL。LINQ to SQL 为处理数据提供了一种面向对象的方法,它由一个对象模型和运行时组成。

LINQ to SQL 对象模型主要是由 System.Data.Linq.DataContext 对象构成,可充当本地数据库的代理。LINQ to SQL 运行时负责桥接对象部分(DataContext 对象)和数据部分(本地数据库)。下图概括了这一关系。

Windows Phone DataContext 和本地数据库

数据上下文是一种代理,一个代表数据库的对象。数据上下文包含若干 Table 对象,其中的每一个对象都表示数据库中的一个表。每一个 Table 对象由对应数据库中数据行的实体所组成。每个实体都是一个具有属性的“简单传统 CLR 对象”(POCO)。每个实体上的属性决定数据库表结构,并定义数据对象模型与数据库架构之间的映射。例如,具有 NamePhoneNumber 属性的实体将生成具有 NamePhoneNumber 列的数据库表。

LINQ to SQL 提供了一些对象关系映射功能,托管应用程序可通过这些功能使用语言集成查询 (LINQ) 与关系数据库(仅指 Transact-SQL)进行通信。LINQ to SQL 将对象模型(通过 .NET Framework 托管代码表示)映射到关系数据库。当您的应用程序运行时,LINQ to SQL 将语言集成查询转换为 Transact-SQL,然后将查询发送至数据库进行执行。当数据库返回结果时,LINQ to SQL 将结果转换回可通过您自己的编程语言进行处理的对象。有关更多信息,请参阅 LINQ to SQL

注意注意:

Windows Phone 上的 LINQ to SQL 不能直接支持执行 Transact-SQL,包括数据定义语言 (DDL) 或数据模型语言 (DML) 语句。此外,Windows Phone 应用程序无法使用 LINQ to SQL 直接访问 ADO.NET 对象。有关更多信息,请参阅 Windows Phone 的 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 不受支持。

在标准应用程序部署中,会于该应用程序首次运行时在独立存储中创建本地数据库。然后在使用应用程序时,将应用程序数据添加到数据库。若要对应用程序预填充一组引用数据,请向应用程序中添一个本地数据库文件。有关分步说明,请参阅如何在 Windows Phone 应用程序中部署引用数据库

若要通过应用程序部署引用数据,您需要执行以下步骤:

  1. 创建帮助器应用程序:帮助器应用程序在您的开发计算机上运行、在独立存储中创建本地数据库,并为数据库加载所需的引用数据。

  2. 从帮助器应用程序中提取本地数据库:使用独立存储资源管理器 (ISETool.exe) 将数据库从帮助器应用程序复制到计算机上的文件夹。有关独立存储资源管理器的更多信息,请参阅如何使用独立存储资源管理器工具

  3. 创建主应用程序:创建将使用引用数据的应用程序。

  4. 将引用数据添加到主应用程序:使用 Visual Studio 将本地数据库文件从计算机上保存该文件的文件夹添加到主应用程序。若要最大程度地减少应用程序程序集大小,请将文件存储为“内容”

在本地数据库随应用程序部署后,它将驻留在安装文件夹中,并处于只读状态。安装文件夹不同于独立存储。若要处理位于此位置的数据库文件,请使用 appdata: 前缀。关于对数据库连接字符串使用前缀的示例,请参阅 Windows Phone 本地数据库连接字符串

若要修改包含引用数据的数据库,请首先将其移出安装文件夹并保存在独立存储中,然后再尝试进行数据库更改。若要移动数据库文件,可以通过 Application.GetResourceStream 方法执行基于流的复制操作来从安装文件夹创建一个流,并通过 IsolatedStorageFileStream.Write 方法将流写入独立存储。以下示例演示在您创建流对象时如何处理安装文件夹中的数据库文件。

Stream str = Application.GetResourceStream(new Uri("appdata:/MyReferenceDB.sdf", UriKind.Relative)).Stream;

若要创建本地数据库,必须首先定义数据上下文和实体。这些类定义数据对象模型和数据库架构之间的映射。LINQ to SQL 的对象关系功能根据这些映射详细信息来创建映射到对应数据上下文的关系数据库。

对于每个实体,使用 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;
}

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

注意注意:

这只是数据上下文代码的一部分。关于创建使用本地数据库的应用程序的分步演练,请参阅如何为 Windows Phone 创建基本的本地数据库应用程序

若要在代码中使用本地数据库功能,您需要在代码文件顶部添加以下指令。


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")]

指定用于表示关联的属性,例如表示主键关联的外键。

在创建 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();
    }
}

如该示例中所示,若要创建数据上下文,必须首先指定数据上下文和数据库文件的文件位置。DataContext 构造函数值指定数据库文件名称为 ToDo.sdf。该值的 isostore:/ 部分指定该文件位于独立存储中。接下来,在 DatabaseExists 方法确认数据库尚不存在之后,使用 CreateDatabase 方法创建数据库。

注意注意:

在创建数据库时,它会自动分配一个为 0 的版本。若要确定数据库版本,请使用 DatabaseSchemaUpdater 类,如本主题后文更改数据库架构中所示。

在本地数据库创建之后,您可以使用 LINQ 和数据上下文来处理本地数据库。以下小节介绍了如何在数据库中选择、插入、更新和删除数据。关于创建执行这些操作的应用程序的分步演练,请参阅如何为 Windows Phone 创建基本的本地数据库应用程序

选择数据(数据库查询)

在 Windows Phone 中,使用语言集成查询 (LINQ) 查询数据库。LINQ 可弥补对象部分和数据部分之间的间隙。LINQ to SQL 中的查询所使用的语法与 LINQ 中的查询相同。有关 LINQ 查询的更多信息,请参阅 LINQ 查询简介 (C#)

由于 LINQ to SQL 查询中引用的对象被映射到数据库中的记录,因此 LINQ to SQL 在查询的执行方式上与其他 LINQ 技术有所不同。典型的 LINQ 查询在应用程序层在内存中执行。通过 LINQ to SQL 使用运行时的对象关系功能,每一个 LINQ 查询都被转换为 Transact-SQL,然后在数据库中直接执行。这可以提高查询的性能,例如从一个较大的数据库中挑选几个记录。

在以下示例中,将使用 LINQ to SQL 查询名为 toDoDBDataContext 对象,然后其结果被放置在名为 ToDoItemsToDoItem 对象的 ObservableCollection 中。由于延迟执行,数据库查询直到实例化 ToDoItems 集合之后才会实际执行。

// 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 方法将数据保存为数据库中的一行。有关更多信息,请参阅如何将行插入数据库 (LINQ to SQL)

在以下示例中,创建了一个 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 方法将更改保存到本地数据库。有关更多信息,请参阅如何更新数据库中的行 (LINQ to SQL)

如果将数据上下文中的对象绑定到页面上的控件,则数据上下文会根据用户交互自动进行更新。然后,所需的唯一步骤是在需要时调用 SubmitChanges 方法。此方法的示例可在本地数据库示例应用程序中找到,如如何为 Windows Phone 创建基本的本地数据库应用程序中所述。以下代码示例显示了在用户导航离开页面时调用 SubmitChanges 方法的示例。

protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{ 
    //Call base method
    base.OnNavigatedFrom(e);
            
    //Save changes to the database
    toDoDB.SubmitChanges();
}
重要说明重要说明:

数据直到调用 SubmitChanges 方法之后才更新到数据库。

删除数据

删除数据库中的数据也包含三个步骤:首先,在数据库中查询要删除的对象。然后,根据您需要删除一个还是多个对象,分别调用 DeleteOnSubmitDeleteAllOnSubmit 方法,以将这些对象置于挂起删除状态。最后,调用 SubmitChanges 方法将更改保存到本地数据库。有关更多信息,请参阅如何从数据库中删除行 (LINQ to SQL)

在以下示例中,从名为 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 方法之后才会从数据库中删除。

对 Windows Phone 应用程序的更改可能需要更改您的本地数据库架构。对本地数据库架构所做的任何更改都从更改对应数据上下文的对象模型开始。Microsoft.Phone.Data.Linq 命名空间提供了 DatabaseSchemaUpdater 类以帮助对数据库架构进行更改。有关如何使用此类的示例,请参阅演练:更新 Windows Phone 本地数据库应用程序

DatabaseSchemaUpdater 类可执行对数据库的累积更改,例如添加表、列、索引或关联。对于更复杂的更改,需要在适当情况下创建新的数据库,并将数据复制到新架构。DatabaseSchemaUpdater 类提供了一个 DatabaseSchemaVersion 属性,它可用于以编程方式区分数据库的不同版本。

重要说明重要说明:

数据库在调用 Execute 方法之后才会进行更改,以反映 DatabaseSchemaUpdater 对象中的更改。当调用该方法时,所有更改(包括版本更新)都将作为单个事务提交到本地数据库。使用单个事务有助于数据库保持完整性,例如在用户于升级过程中退出应用程序的情况下。

以下示例演示如何使用 DatabaseSchemaUpdater 类来基于 DatabaseSchemaVersion 属性修改数据库。

using (ToDoDataContext db = new ToDoDataContext(("isostore:/ToDo.sdf")))
{
        //Create the database schema updater
        DatabaseSchemaUpdater dbUpdate = db.CreateDatabaseSchemaUpdater();

        //Get database version
        int dbVersion = dbUpdate.DatabaseSchemaVersion;

        //Update database as applicable
        if (dbVersion < 5)
        {   //Copy data from existing database to new database 
            MigrateDatabaseToLatestVersion();
        }
        else if (dbVersion == 5)
        {   //Add column to existing database to match the data context
            dbUpdate.AddColumn<ToDoItem>("TaskURL");
            dbUpdate.DatabaseSchemaVersion = 6;
            dbUpdate.Execute();
        }
}

注意注意:

在应用程序更新过程中,独立存储中保存的任何文件(包括本地数据库文件)都不会发生修改。

本地数据库提供了密码保护和加密功能来确保数据库的安全。在对数据库使用密码功能时,整个数据库都会被加密。若要加密数据库,请在创建数据库之前在数据库连接字符串(数据上下文构造函数)中提供密码。每次访问数据库时都需要提供密码。在数据库创建之后便无法对其加密。数据库是使用 AES-128 加密的,而密码是使用 SHA-256 进行哈希处理的。

以下示例演示如何通过在数据库连接字符串中指定密码来创建加密数据库。

// Create the data context, specify the database file location and password
ToDoDataContext db = new ToDoDataContext ("Data Source=’isostore:/ToDo.sdf’;Password=’securepassword’");

// Create an encrypted database after confirming that it does not exist
if (!db.DatabaseExists()) db.CreateDatabase();

提示提示:

如果仅有限数量的非索引化列需要加密,可以通过在将数据添加到数据库之前对数据进行加密(而不是加密整个数据库)来获得更好的性能。有关数据加密的更多信息,请参阅如何加密 Windows Phone 应用程序中的数据

有关对本地数据库使用连接字符串的更多信息,请参阅 Windows Phone 本地数据库连接字符串

显示:
© 2014 Microsoft