导出 (0) 打印
全部展开
信息
您所需的主题如下所示。但此主题未包含在此库中。

演练:更新 Windows Phone 8 本地数据库应用

2014/6/18

适用于:Windows Phone 8 和 Windows Phone Silverlight 8.1 | Windows Phone OS 7.1

从 Windows Phone OS 7.1 开始,您可以将关系数据存储在驻留在应用本地文件夹的本地数据库中。随着应用的发展,您可能需要在应用已经部署到手机后,对数据库的架构做出更改。对于大部分架构更新,可以使用 DatabaseSchemaUpdater 类。有了 DatabaseSchemaUpdater,您可以在应用更新过程中向本地数据库中添加列、索引、表和关联。本演练以本地数据库示例应用为例,介绍如何更新本地数据库。有关在 Windows Phone 应用中使用本地数据库的更多信息,请参见 Windows Phone 8 本地数据库

说明注意:

如果本地数据库需要的更改范围超出添加列/索引/表,则可能需要创建一个新的数据库,并将数据从旧数据库迁移到新数据库。有关更多信息,请参见 Windows Phone 8 的本地数据库迁移概述

在本演练中,将更新本地数据库示例两次。第一个更新将添加一列以存储每个任务的优先级。第二个更新将向 Items 表添加一个索引。在本演练的各个阶段之后,将使用独立存储资源管理器测试早期版本数据库中的更新。有关独立存储资源管理器的更多信息,请参见如何使用 Windows Phone 8 的独立存储资源管理器工具

在您完成本演练之后,更新的本地数据库示例将与以下示例类似。

AP_Con_LocalDatabaseUpdate_Features

在此示例中,优先级列(在第一次更新过程添加)允许每个任务的颜色根据任务的优先级进行更改。没有分配优先级的项目保留为白色。下图显示主页和新任务页如何使用新优先级功能。

本主题包括以下部分。

在本节中,运行本地数据库示例、向数据库添加一些任务,并保存数据库的副本以供稍后在本演练中测试更新。有关本地数据库示例工作原理的更多信息,请参见如何使用 MVVM 为 Windows Phone 8 创建本地数据库应用

说明注意:

由于创建数据库时未显示指定数据库架构版本,因此在本演练开始时,本地数据库示例的 DatabaseSchemaVersion 属性等于零。为了避免与数据库的下一个版本相混淆,本演练跳过版本 1。

为版本 0 创建基线数据库

  1. 下载本地数据库示例 (C#) 并将项目保存到计算机上的一个文件夹中。

  2. 解压缩该项目,并在 Visual Studio 中将其打开。

  3. 按 F5 开始调试并测试该应用。

  4. 从模拟器或手机中,点按应用栏中的“添加”按键向应用添加多个任务。若要查看每个应用 Pivot 页面中的任务,请按各个类别添加任务:“家庭”“工作”“爱好”

    提示提示:

    当使用 Windows Phone 模拟器时,按“Page Up”键可通过键盘输入文本值。

    下图显示包含三个任务的版本 0 数据库:“家庭任务”“工作任务”“爱好任务”

    AP_Con_LocalDatabaseUpdate_Baseline0
  5. “调试”菜单中单击“停止调试”。请勿关闭模拟器,解开手机或从模拟器或手机中启动应用。

  6. 在计算机上创建一个名为 LocalDatabaseVersion0 的文件夹。此文件夹将用于存储版本 0 数据库架构的基线数据库。

  7. 使用独立存储资源管理器将本地数据库从应用复制到 LocalDatabaseVersion0 文件夹。有关更多信息,请参见如何使用 Windows Phone 8 的独立存储资源管理器工具。下面的示例将数据库文件从模拟器复制到 c:\LocalDatabaseVersion0\ToDo.sdf

    ISETool.exe ts xd 77a80316-384d-40dc-a8c3-c4054676e85c "C:\LocalDatabaseVersion0"
    

    请注意,GUID 值与应用的 Product ID 相对应,它可以在应用清单文件中找到。您应用的 Product ID 可能与本示例中使用的 ID 不同。

  8. 现在您有了一个版本 0 数据库架构的数据库副本。通过此数据库文件,可以使用独立存储资源管理器的还原快照 (rs) 命令将本地数据库回滚到更新前的日期。

在本节中,准备第二版本的应用和本地数据库架构。版本 2 允许每个任务的颜色根据任务的优先级进行更改。

若要实现此功能,请更新或添加以下文件:

  • Model\ToDoDataContext.cs:更新此文件以定义新优先级列。

  • ViewModel\ToDoViewModel.cs:更新此文件以便为新任务提供有效的优先级列表。

  • NewTaskPage.xaml 和 NewTaskPage.xaml.cs:更新这些文件以添加一个 ListPicker 控件,用于指定与新任务关联的优先级。

  • PriorityToColorConverter.cs:添加此文件以将任务优先级转换为 SolidColorBrush 对象,该对象可以绑定到主页 UI 中显示的任务。

  • MainPage.xaml:更新此文件以将任务颜色绑定到相应的任务优先级。

  • App.xaml.cs:修改此文件以添加数据库更新逻辑。

准备版本 2

  1. 在文件 Model\ToDoDataContext.cs 中,将下面的代码添加到 ToDoItem 类。

    // Define Priority: field, public property, and database column.
    // Added in Version 2 of the application.
    private int? _priority;
    
    [Column(CanBeNull = true)]
    public int? Priority
    {
        get { return _priority; }
        set
        {
            if (_priority != value)
            {
                NotifyPropertyChanging("Priority");
                _priority = value;
                NotifyPropertyChanged("Priority");
            }
        }
    }
    
    

    此代码定义名为 Priority 的新数据库列。此代码在类中显示的顺序并不重要。CanBeNull 列属性允许数据库中的现有数据与新列兼容。

  2. 在文件 ViewModel\ToDoViewModel.cs 中,将下面的代码添加到 ToDoViewModel 类。

    // Valid priorities for new tasks.
    // Added in Version 2 of the application.
    private List<int> _prioritiesList = new List<int> { 1, 2, 3 };
    public List<int> PrioritiesList
    {
        get { return _prioritiesList; }
    }
    
  3. NewTaskPage.xaml 文件中,将下面的代码添加到名为 ContentPanelStackPanel(位于 categoriesListPicker 的正下方)。

    <!-- Added in Version 2 of the application. -->
    <TextBlock 
        Text="Priority"
        Style="{StaticResource PhoneTextNormalStyle}"
        />
    <toolkit:ListPicker
        x:Name="priorityListPicker"
        ItemsSource="{Binding PrioritiesList}">
    </toolkit:ListPicker>
    <!-- End of Version 2 update. -->
    
    

    此代码添加一个 ListPicker 控件,用于指定与新任务关联的优先级。

  4. NewTaskPage.xaml.cs 文件中,更新用于创建 newToDoItem 对象的代码以按如下方式指定 Priority 属性。

    // Create a new task.
    ToDoItem newToDoItem = new ToDoItem
    {
        ItemName = newTaskNameTextBox.Text,
        Category = (ToDoCategory)categoriesListPicker.SelectedItem,
    
        // Set the priority of the new task to the specified priority.
        // Added in Version 2 of the application.
        Priority = (int)priorityListPicker.SelectedItem
    };
    
    
  5. “解决方案资源管理器”中,右键单击您的项目,选择“添加”,然后选择“新项”

  6. “添加新项”窗口中,选择“代码文件”并将文件命名为“PriorityToColorConverter.cs”。然后单击“添加”

  7. 在文件 PriorityToColorConverter.cs 中,使用以下代码替换所有代码。

    using System;
    using System.Windows.Media;
    using System.Windows.Data;
    
    namespace LocalDatabaseSample
    {
        // Convert task priority to a brush that can be bound to in the UI.
        // Added in Version 2 of the application.
        public class PriorityToColorConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                // Allow for tasks that have no priority.
                int? priority = (int?)value;
    
                // Assign color based on priority.
                switch (priority)
                {
                    case null:
                        return new SolidColorBrush(Colors.White);
                    case 1:
                        return new SolidColorBrush(Colors.Red);
                    case 2:
                        return new SolidColorBrush(Colors.Yellow);
                    case 3:
                        return new SolidColorBrush(Colors.Green);
                    default:
                        return new SolidColorBrush(Colors.White);
                }
            }
    
            // Unused; required for IValueConverter implementation.
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            { throw new NotImplementedException();}
        }
    }
    
    
  8. MainPage.xaml 文件中,将以下属性添加到 phone:PhoneApplicationPage 元素。

        xmlns:local="clr-namespace:LocalDatabaseSample"
    

    本代码为要在主页上使用的 PriorityToColorConverter 添加所需的命名空间。

  9. MainPage.xaml 中,将以下元素添加到 phone:PhoneApplicationPage.Resources 元素(位于名为 ToDoListBoxItemTemplateDataTemplate 的上方)。

    <!-- Resource & namespace specified in Version 2 of the application. -->
    <local:PriorityToColorConverter x:Key="PriorityToColorConverter" />     
    
    

    此代码会将 PriorityToColorConverter 作为资源添加到主页上。

  10. MainPage.xaml 中名为 ToDoListBoxItemTemplateDataTemplate 内,通过按以下方式指定 Foreground 属性来更新 TextBlock

    <!-- Foreground specified in Version 2 of the application. -->
    <TextBlock 
        Text="{Binding ItemName}" 
        FontSize="{StaticResource PhoneFontSizeLarge}" 
        Grid.Column="1" Grid.ColumnSpan="2" 
        VerticalAlignment="Top" Margin="-36, 12, 0, 0"
        Foreground="{Binding Priority, Converter={StaticResource PriorityToColorConverter}}"
        />
    
    

    此代码根据 PriorityToColorConverter 资源,将任务文本的前景颜色绑定到优先级。

  11. App.xaml.cs 文件中,将以下指令添加到页面顶部。

    // Directive for DatabaseSchemaUpdater
    // Added in Version 2 of the application.
    using Microsoft.Phone.Data.Linq;
    
    

    此操作使用下列步骤之一创建 DatabaseSchemaUpdater 对象。

  12. App.xaml.cs 文件中,将以下代码添加到 App 类。

    // The current version of the application.
    public static int APP_VERSION = 2;
    
    
  13. App.xaml.cs 中,按以下方式为名为 dbToDoDataContext 替换 using 语句。

    using (ToDoDataContext db = new ToDoDataContext(DBConnectionString))
    {
        // Create the database if it does not exist.
        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();
    
            // Set the new database version.
            DatabaseSchemaUpdater dbUpdater = db.CreateDatabaseSchemaUpdater();
            dbUpdater.DatabaseSchemaVersion = APP_VERSION;
            dbUpdater.Execute();
        }
        else
        {
            // Check whether a database update is needed.
            DatabaseSchemaUpdater dbUpdater = db.CreateDatabaseSchemaUpdater();
                                            
            if (dbUpdater.DatabaseSchemaVersion < APP_VERSION)
            {
                // Add the Priority column (added in version 2).
                dbUpdater.AddColumn<ToDoItem>("Priority");
    
                // Add the new database version.
                dbUpdater.DatabaseSchemaVersion = 2;
    
                // Perform the database update in a single transaction.
                dbUpdater.Execute();
            }
        }
    }
    
    

    此代码将 else 子句添加到 if 语句,允许应用在必要时更新数据库。在从 dbUpdater 对象中调用 Execute 方法之前,不会对数据库做出更改。

  14. 通过在“生成”菜单中单击“重新生成”选项来重新生成解决方案。如果在 Visual Studio Express 中未找到“生成”菜单,可以通过单击“设置”,然后选择“导出设置”来在“工具”菜单中启用它。

  15. 您已经完成了本地数据库示例应用的版本 2 更新。按 F5 运行应用以测试应用的功能。

    说明注意:

    根据 Visual Studio 的状态,此时您保存在模拟器或手机中的数据可能不会显示在应用中。版本 0 数据库的数据将在下一节中进行还原。

在本节中,测试应用的数据库更新代码。测试时根据 Visual Studio 的状态,版本 0 数据库中的数据可能不会显示在模拟器或手机中。

为了模拟应用更新,将使用独立存储资源管理器还原版本 0 数据库(在将新版应用部署到手机之后)。当 Windows Phone 应用商店 更新手机上的应用时,仅更新应用代码;应用更新过程不会更改本地文件夹。

测试数据库更新

  1. 通过在“生成”菜单中单击“重新生成”选项来重新生成解决方案。如果在 Visual Studio Express 中未找到“生成”菜单,可以通过单击“设置”,然后选择“导出设置”来在“工具”菜单中启用它。

  2. 按 F5 开始调试。该操作会将新版应用部署到模拟器或手机。

    说明注意:

    若要复制到应用的本地文件夹,独立存储资源管理器要求在模拟器或手机上至少存在一个应用实例(具有相同的 Product ID)。运行调试器可满足此条件。

  3. “调试”菜单中单击“停止调试”。不要关闭模拟器或解开手机。这会关闭应用,释放在本地文件夹中对本地数据库文件的控制。

  4. 使用独立存储资源管理器将版本 0 数据库从 LocalDatabaseVersion0 文件夹还原到模拟器或手机。有关更多信息,请参见如何使用 Windows Phone 8 的独立存储资源管理器工具。下面的示例将版本 0 数据库文件从 c:\LocalDatabaseVersion0\ToDo.sdf 复制到模拟器。

    重要说明重要说明:

    若要成功还原数据库,请确保在执行此命令时应用未运行(启动或不启动调试器)。如果应用已经被逻辑删除,则可能还需要从应用堆栈中将其删除,方法是按“返回”按钮直到手机导航到“开始”屏幕。

    ISETool.exe rs xd 77a80316-384d-40dc-a8c3-c4054676e85c "C:\LocalDatabaseVersion0"
    

    请注意,GUID 值与应用的 Product ID 相对应,它可以在应用清单文件中找到。您应用的 Product ID 可能与本示例中使用的 ID 不同。

  5. 在新版应用使用版本 0 数据库运行之前,应用现在处于模拟 商店 更新的状态。若要逐句通过数据库更新代码,请在 App.xaml.cs 文件的以下代码行处设置一个调试断点。

    if (db.DatabaseExists() == false)
    
  6. 按 F5 开始调试。新版应用将被重新部署到手机并开始使用版本 1.0 数据库运行。

  7. 在调试器到达断点之后,单击“单步跳过”按钮以处理数据库更新代码。观察数据库更新前后 dbUpdater 对象的 DatabaseSchemaVersion 属性(将鼠标悬停在 dbUpdater 对象名称上面)。

    下面的示例演示在调用 Execute 方法之前(红色箭头)和之后(蓝色箭头)dbUpdaterDatabaseSchemaVersion

    AP_Con_LocalDatabaseUpdate_Debugging
  8. 删除断点并按 F5 开始调试,继续运行应用。应用将启动并显示用版本 0 基线数据库保存的任务,如下图中所示。

    AP_Con_LocalDatabaseUpdate_Baseline0

    由于使用版本 0 应用创建的任务没有与其关联的优先级值,因此 PriorityToColorConverter 为其分配了 White 色。

  9. 当您完成了测试更新时,请停止调试。从“调试”菜单中单击“停止调试”。不要关闭模拟器或解开手机。这会关闭应用,释放在本地文件夹中对本地数据库文件的控制。

在本节中,运行版本 2 应用、向数据库添加一些任务,并保存数据库的副本以测试下一版本数据库更新代码。

为版本 2 创建基线数据库

  1. 如果版本 2 应用未在运行,请按 F5 开始调试并测试应用。

  2. 从模拟器或手机中,点按应用栏中的“添加”按钮以向应用添加具有不同优先级和完成状态的新任务。根据需要,删除版本 0 基线中的任务以便为新任务留出空间。

    下图显示版本 2 数据库,其中包含从版本 0 中还原的一些任务及说明应用新优先级功能的一些新任务:“任务优先级 1”“任务优先级 2”“任务优先级 3”

    AP_Con_LocalDatabaseUpdate_Baseline2
  3. “调试”菜单中单击“停止调试”。不要关闭模拟器或解开手机。

  4. 在计算机上创建一个名为 LocalDatabaseVersion2 的文件夹。此文件夹将用于存储版本 2 数据库架构的基线数据库。

  5. 使用独立存储资源管理器将本地数据库从应用复制到 LocalDatabaseVersion2 文件夹。有关更多信息,请参见如何使用 Windows Phone 8 的独立存储资源管理器工具。下面的示例将数据库文件从模拟器复制到 c:\LocalDatabaseVersion2\ToDo.sdf

    ISETool.exe ts xd 77a80316-384d-40dc-a8c3-c4054676e85c "C:\LocalDatabaseVersion2"
    

    请注意,GUID 值与应用的 Product ID 相对应,它可以在应用清单文件中找到。您应用的 Product ID 可能与本示例中使用的 ID 不同。

  6. 现在您有了一个版本 2 数据库架构的数据库副本。继续下一节对数据库架构做进一步更新。

在本节中,准备第三版本的应用和本地数据库架构。版本 3 演示如何向数据库添加次要索引以及如何准备数据库更新逻辑以考虑多个升级路径。

重要说明重要说明:

您的客户可能不会选择安装应用的所有更新。在应用启动时考虑这一点非常重要,因为手机上的数据库文件可能处于任何以前的应用版本。

准备版本 3

  1. 在文件 Model\ToDoDataContext.cs 中,将下面的指令添加到文件顶部。

    // Directive for Index attribute.
    // Added in Version 3 of the application.
    using Microsoft.Phone.Data.Linq.Mapping;
    
    
  2. Model\ToDoDataContext.cs 中,将以下 LINQ to SQL 映射属性添加到 ToDoItem 类的 [Table] 属性下面。

    // Index added in version 3 of the application.
    [Index(Columns = "Priority", Name = "PriorityIndex")]
    

    此代码在 Priority 列上添加升序索引。将此索引添加到数据库仅供演示使用;更新应用以利用相应的性能优势不在本主题的讨论范围之内。

  3. App.xaml.cs 文件中,更新 App 类中的 APP_VERSION 属性。

    // The current version of the application.
    public static int APP_VERSION = 3;
    
    
  4. App.xaml.cs 中,按以下方式为名为 dbToDoDataContext 更新 using 语句。

    using (ToDoDataContext db = new ToDoDataContext(DBConnectionString))
    {
        // Create the database if it does not exist.
        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();
    
            // Set the new database version.
            DatabaseSchemaUpdater dbUpdater = db.CreateDatabaseSchemaUpdater();
            dbUpdater.DatabaseSchemaVersion = APP_VERSION;
            dbUpdater.Execute();
        }
        else
        {
            // Check whether a database update is needed.
            DatabaseSchemaUpdater dbUpdater = db.CreateDatabaseSchemaUpdater();
    
            if (dbUpdater.DatabaseSchemaVersion < APP_VERSION)
            {
                // Perform version 2.0 update, as applicable.
                if (dbUpdater.DatabaseSchemaVersion < 2)
                {
                    // Add the Priority column (added in version 2.0).
                    dbUpdater.AddColumn<ToDoItem>("Priority");
                }
    
                // Add the Priority index (added in version 3.0).
                dbUpdater.AddIndex<ToDoItem>("PriorityIndex");
    
                // Set the new database version.
                dbUpdater.DatabaseSchemaVersion = 3;
    
                // Perform the database update in a single transaction.
                dbUpdater.Execute();
            }
        }
    }
    
    

    此代码会更新 else 子句以添加名为 PriorityIndex 的次要索引,并在必要时添加 Priority 列。您的客户可能不会选择安装应用的所有更新。在应用启动时考虑这一点非常重要,因为手机上的数据库文件可能处于任何以前的应用版本。

  5. 通过在“生成”菜单中单击“重新生成”选项来重新生成解决方案。如果在 Visual Studio Express 中未找到“生成”菜单,可以通过单击“设置”,然后选择“导出设置”来在“工具”菜单中启用它。

  6. 现在已经完成了应用的版本 3 更新。继续下一节以从较早版本的数据库测试数据库更新。

在本节中,通过从不同版本的数据库架构中模拟应用更新来测试版本 3 数据库更新逻辑。您的客户可能不会安装所有应用更新。请确保数据库更新逻辑根据需要从以前版本的数据库架构执行,这一点非常重要。

从版本 0 中测试版本 3 更新

  • 针对版本 0 数据库架构测试版本 3 数据库更新逻辑。使用本演练前面介绍的过程(测试数据库更新)通过存储在 LocalDatabaseVersion0 文件夹中的数据库进行测试。

    例如,下面的命令行语句将版本 0 数据库文件从 c:\LocalDatabaseVersion0\ToDo.sdf 复制到模拟器。

    ISETool.exe rs xd 77a80316-384d-40dc-a8c3-c4054676e85c "C:\LocalDatabaseVersion0"
    

    请注意,GUID 值与应用的 Product ID 相对应,它可以在应用清单文件中找到。您应用的 Product ID 可能与本示例中使用的 ID 不同。

    在使用版本 0 数据库启动版本 3 应用之后,应仅显示使用版本 0 基线保存的任务。

    AP_Con_LocalDatabaseUpdate_Baseline0

从版本 2 中测试版本 3 更新

  • 针对版本 2 数据库架构测试版本 3 数据库更新逻辑。使用本演练前面介绍的过程(测试数据库更新)通过存储在 LocalDatabaseVersion2 文件夹中的数据库进行测试。

    例如,下面的命令行语句将版本 2 数据库文件从 c:\LocalDatabaseVersion2\ToDo.sdf 复制到模拟器。

    ISETool.exe rs xd 77a80316-384d-40dc-a8c3-c4054676e85c "C:\LocalDatabaseVersion2"
    

    请注意,GUID 值与应用的 Product ID 相对应,它可以在应用清单文件中找到。您应用的 Product ID 可能与本示例中使用的 ID 不同。

    在使用版本 2 数据库启动版本 3 应用之后,应仅显示使用版本 2 基线保存的任务。

    AP_Con_LocalDatabaseUpdate_Baseline2

在本节中,使用独立存储资源管理器清除与应用关联的本地文件夹容器。在使用较早版本的数据库架构测试应用的同时,可能还要针对没有在手机上安装以前版本的新客户测试其体验。使用独立存储资源管理器删除数据库提供了一种替代重新启动模拟器或从手机中卸载应用的方便方法。

提示提示:

当在命令窗口 (Cmd.exe) 中使用独立存储资源管理器时,请使用向上键和向下键导航您的命令历史记录并快速访问和编辑以前的命令。

创建空文件夹的步骤

  1. 复制一个基线数据库文件夹,例如 LocalDatabaseVersion2

  2. 将此文件夹重命名为 LocalDatabaseEmpty

  3. 导航到包含本地数据库文件的文件夹。例如 c:\LocalDatabaseEmpty

  4. 删除名为 ToDo.sdf 的本地数据库文件。

  5. 现在,已经为空的本地文件夹制作了快照。将此文件夹还原到模拟器或手机上的应用会从应用的本地文件夹中删除本地数据库文件。

删除本地数据库

  • 还原在 LocalDatabaseEmpty 文件夹中捕获的空的本地文件夹。使用与本演练前面介绍的过程(测试数据库更新)类似的过程。

    例如,以下命令行语句将空的本地文件夹从 c:\LocalDatabaseEmpty 复制到模拟器。

    ISETool.exe rs xd 77a80316-384d-40dc-a8c3-c4054676e85c "C:\LocalDatabaseEmpty"
    

    请注意,GUID 值与应用的 Product ID 相对应,它可以在应用清单文件中找到。您应用的 Product ID 可能与本示例中使用的 ID 不同。

    下图显示在还原 LocalDatabaseEmpty 文件夹、模拟全新安装之后版本 3 应用的外观。

    AP_Con_LocalDatabaseUpdate_Empty

    现在已经完成了本地数据库更新演练。

显示:
© 2014 Microsoft