Использование локальной базы данных Windows

advertisement
WPH302ILL
Лабораторная работа
Использование локальной
базы данных Windows Phone
и её резервное
копирование на севере
Оглавление
ИСПОЛЬЗОВАНИЕ ЛОКАЛЬНЫХ БАЗ ДАННЫХ .................................................................................. 3
Цели
4
Предварительные требования
4
Архитектура
4
LINQ to SQL
5
Структура лабораторной работы
5
Примерное время выполнения
5
Упражнение
6
Резюме
19
ИСПОЛЬЗОВАНИЕ ФОНОВОЙ СЛУЖБЫ ПЕРЕДАЧИ ФАЙЛОВ ...................................................... 19
Цели
19
2
Предварительные требования
19
Структура лабораторной работы
20
Примерное время выполнения
20
Упражнение
20
Резюме
32
Microsoft Tech∙Ed Russia 2011. Лабораторная работа.
Использование локальной базы данных Windows Phone и её резервное копирование на севере.
Использование локальных баз данных
Заметка: Файлы для этого задания находятся в папке C:\MangoTrainingCourse\Labs\ TodoSQL
Windows® Phone Codenamed Mango предоставляет новую возможность для хранения и
управления структурированными данными вашего приложения - базы данных Microsoft SQL Server
Compact edition. База данных представляет собой файл, сохраненный в выделенном хранилище
приложения. Эта лабораторная работа использует приложение Tidy для демонстрации работы с
базами данных при написании приложений для Windows® Phone. Tidy приложение позволяет
управлять проектами, включающими в себя различные задачи. Каждая задача может содержать
вложения и иметь определенный набор данных, включающих расстановку приоритетов и сроков.
Вся эта информация сохраняется на локальной базе данных в нескольких основных таблица:

Проекты

Задачи

Вложения

Расположение
Следующее изображение иллюстрирует хранение данных в сущностях, поддерживаемых
приложением, а также их взаимодействие между собой.
3
Microsoft Tech∙Ed Russia 2011. Лабораторная работа.
Использование локальной базы данных Windows Phone и её резервное копирование на севере.
Рисунок 1
Сущности базы данных и их ассоциации
Приложения Window Phone Codenamed Mango используют LINQ to SQL API для доступа к
локальной базе данных. LINQ to SQL обрабатывает данные, сохраненные в базе данных, путем
объектно-ориентированного подхода. Для связи объектной модели приложения с данными в базе
данных используется класс System.Data.Linq.DataContext .
Цели
Данная лабораторная работа содержит инструкции для достижения следующих результатов:

Развитие нового подхода к локальным базам данных на Windows Phone Codenamed
Mango

Понимание, как реализовать локальные базы данных в приложении Tidy.
Предварительные требования
Для извлечения максимальной пользы из лабораторной работы, убедитесь, что выполнены
следующие требования:

Устновлены Microsoft Visual Studio 2010 или Microsoft Visual C# Express 2010 и Windows®
Phone Developer Tools, доступные по ссылке http://go.microsoft.com/?linkid=9772716

Вы обладаете навыками создания приложений для Windows Phone 7

Знакомы с основными терминами SQL.
Архитектура
Приложение Tidy построено с помощью шаблона MVVM. MVVM требует, чтобы каждый элемент
приложения соответствовал одной из трех областей:

View - Представляет пользовательский интерфейс и переносит действия пользователя в
View Model.

ViewModel - Проводник между действиями пользователя и данными приложения.

Model - Управляет данными приложения.
Разделение на разделы в приложении Tidy работает следующим образом:
Класс DataContextBase, который наследует класс System.Data.Linq.DataContext, упоминаемый
ранее, реализует модель. Этот класс вместе с другими классами, на которые он ссылается,
позволяет выполнять операции над локальными объектами приложения для изменения данных в
базе данных приложения.
4
Microsoft Tech∙Ed Russia 2011. Лабораторная работа.
Использование локальной базы данных Windows Phone и её резервное копирование на севере.
Класс ViewModelItemsBase и класс ViewModelBase (вместе с подклассами обоих) реализуют
ViewModel. Эти классы скрывают модель в пользовательском интерфейсе, как путем упрощения
доступа к содержанию модели, так и путем упрощения операций по управлению данными,
такими как создание новых задач, обновления проектов, и т.д. Различные страницы приложения,
составляющие пользовательский интерфейс реализуют View.
LINQ to SQL
LINQ to SQL - это платформа .NET Framework с объектно-реляционным отображением данных
(ORM), которая сопоставляет данные базы данных ("говорящие" только на transact-SQL) и объекты
приложения. Когда приложение выполняет заявление LINQ , платформа переводит его в transactSQL и выполняет в базе данных. Как только база данных выдает результат на запрос, LINQ to SQL
отображает его в объектах приложения.
Для получения большей информации о LINQ to SQL пройдите по ссылке
http://msdn.microsoft.com/en-us/library/bb425822.aspx
Заметка: Если вы знакомы с LINQ to SQL для стационарных компьютеров, пожалуйста,
обратите внимание, что некоторые возможности LINQ to SQL не реализованы на Windows
Phone. Данная реализация LINQ to SQL не поддерживает "сырой" transact-SQL, DML (язык
моделирования данных), DDL (язык описания данных) и не предоставляет прямой доступ
к объектам ADO.NET.
Структура лабораторной работы
Лабораторная работа состоит из одного упражнения, включающего в себя семь заданий:
1. Определение контекста данных
2. Создание базы данных
3. Развертывание существующей базы данных
4. Получение данных
5. Внесение данных
6. Обновление данных
7. Удаление данных
Примерное время выполнения
Данная лабораторная работа должна быть выполнена в течение 30 минут.
5
Microsoft Tech∙Ed Russia 2011. Лабораторная работа.
Использование локальной базы данных Windows Phone и её резервное копирование на севере.
Упражнение
Лабораторная работа опирается на существующую функциональность Model и ViewModel. Она
предлагает экскурсию по соответствующим фрагментам кода и позволяет глубже понять
возможности использования локальных баз данных в вашем будущем приложении.
Задание 1 - Определение контекста данных
Класс System.Data.Linq.DataContext сопоставляет объекты приложения и сущности базы данных.
Сопоставление объектов приложения и объектов базы данных требует от вас реализации класса,
который наследуется из System.Data.Linq.DataContext. Вы также должны будете добавить
атрибуты к вашей модели объектов. Затем контекст данных сопоставит ваши объекты с
соответствующей схемой базы данных.
Рекомендуется начинать с кода при создании базы данных на Windows Phone. Вы вручную
создаете классы и определяете их атрибуты, и затем (во время работы приложения), контекст
данных создает базу данных с отношениями, заданными в вашей модели объектов.
Также есть возможность взять существующую базу данных и автоматически запустить сравнение
контекста данных используя SqlMetal tool. Стоит отметить, что SqlMetal не полностью совместим с
Windows Phone и код, запущенный им, не скомпилируется, пока вы не измените его для
использования на этом устройстве.
Контекст данных приложения Tidy, был создан с помощью SqlMetal. Основное его преимущество это возможность вставлять дополнительные блоки в классы модели объектов в форме частичных
методов или событий, которые мы будем использовать для выполнения специальных действий
при изменении данных приложения.
1. Откройте решение для лабораторной работы в инсталяционной папке Source\End.
Найдите проект Todo.Business и откройте в нем папку Models, а затем файл
DataContextBase.cs. Вы увидите класс DataContextBase, который служит контекстом для
данных приложения.
2. Посмотрите, как каждая таблица в базе данных имеет соответствующие свойства в классе
DataContextBase типа Table<T>, где T - это тип сущности, представленной в таблице.
3. Заметьте, что для каждого свойства Table<T> в DataContextBase классу T присвоен
атрибут Table. Этот атрибут определяет таблицу, в которой содержатся данные для
сущностей типа T.
4. Все классы в модели объектов реализуют интерфейс IPropertyChangedNotifier, который в
свою очередь наследуется с INotifyPropertyChanged. Это позволяет вам связывать части
пользовательского интерфейса с данными, содержащимися в объектах. Классы сущности
также реализуют интерфейс INotifyPropertyChanging, который позволяет SQL CE
оптимизировать процессы кэширования и управления данными, и ITodoTable, который
определяет свойство ID.
6
Microsoft Tech∙Ed Russia 2011. Лабораторная работа.
Использование локальной базы данных Windows Phone и её резервное копирование на севере.
5. Ниже приведен кусок кода, в котором задается контекст данных. Код демонстрирует, как
таблица задач определяется классом DataContextBase, и как класс Task определяет
взаимосвязь между его свойствами и колонками базы данных, а также взаимосвязь
между различными сущностям, представленными в классе Attachment:
C#
public partial class DataContextBase : System.Data.Linq.DataContext
{
private static System.Data.Linq.Mapping.MappingSource mappingSource =
new AttributeMappingSource();
public DataContextBase(string connection) :
base(connection, mappingSource)
{
OnCreated();
}
public DataContextBase(string connection,
System.Data.Linq.Mapping.MappingSource mappingSource) :
base(connection, mappingSource)
{
OnCreated();
}
public System.Data.Linq.Table<Task> Items
{
get
{
return this.GetTable<Task>();
}
}
// Остальная часть класса опущена.
}
[Table( Name="Tasks")]
public partial class Task : INotifyPropertyChanging, INotifyPropertyChanged,
ITodoTable
{
[Column(Storage = "_EstimateTime", DbType = "DateTime")]
public System.Nullable<System.DateTime> EstimateTime
{
get
{
return this._EstimateTime;
}
7
Microsoft Tech∙Ed Russia 2011. Лабораторная работа.
Использование локальной базы данных Windows Phone и её резервное копирование на севере.
set
{
if ((this._EstimateTime != value))
{
this.OnEstimateTimeChanging(value);
this.SendPropertyChanging();
this._EstimateTime = value;
this.SendPropertyChanged("EstimateTime");
this.OnEstimateTimeChanged();
}
}
[Association(Name = "Attachment_Items", Storage = "_Attachment",
ThisKey = "ItemID", OtherKey = "ItemID", DeleteRule = "NO ACTION")]
public EntitySet<Attachment> Attachment
{
get
{
return this._Attachment;
}
set
{
this._Attachment.Assign(value);
}
}
// Остальная часть класса опущена.
}
Мы уже упоминали атрибуты в коде выше. Эти атрибуты позволяют вам задавать таблицы,
колонки, ключи и индексы.
Таблица ниже объединяет некоторые атрибуты заданные LINQ to SQL:
8
Microsoft Tech∙Ed Russia 2011. Лабораторная работа.
Использование локальной базы данных Windows Phone и её резервное копирование на севере.
Хотя мы используем SqlMetal для определения контекста данных в этом приложении,
давайте посмотрим как создать сущность полностью вручную с использованием класса
Task в качестве примера.
6. Начнем с определения класса и привязки к нему атрибута Table:
C#
[Table]
public partial class Task
{
}
7. Теперь зададим свойства класса:
C#
[Table]
public partial class Task
{
public TaskStatus Status { get; set; }
public PriorityValue Priority { get; set; }
public System.Guid Id { get; set; }
public System.Guid ProjectID { get; set; }
9
Microsoft Tech∙Ed Russia 2011. Лабораторная работа.
Использование локальной базы данных Windows Phone и её резервное копирование на севере.
public System.Guid LocationID { get; set; }
public bool Completed { get; set; }
public string Title { get; set; }
public System.Nullable<System.DateTime> DueDate { get; set; }
public EntitySet<Attachment> Attachment { get; set; }
public Project Projects { get; set; }
public Location Location { get; set; }
}
8. Добавим атрибут Column для определения колонок, которые будут сопоставлять
различные свойства. Заметьте, что некоторые свойства остаются без этого атрибута, мы
обратим на них внимание на следующем шаге:
C#
public partial class Task
{
[Column( Storage = "_Status", DbType="Int")]
public TaskStatus Status { get; set; }
[Column(Storage = "_Priority", DbType = "Int")]
public PriorityValue Priority { get; set; }
[Column(Storage = "_ItemID", DbType = "UniqueIdentifier NOT NULL",
IsPrimaryKey = true)]
public System.Guid Id { get; set; }
[Column(Storage = "_ProjectID", DbType = "UniqueIdentifier NOT NULL")]
public System.Guid ProjectID { get; set; }
[Column(Storage = "_LocationID", DbType = "UniqueIdentifier")]
public System.Guid LocationID { get; set; }
[Column(Storage = "_Completed", DbType = "Bit NOT NULL")]
public bool Completed { get; set; }
[Column(Storage = "_Title", DbType = "NVarChar(100) NOT NULL",
CanBeNull = false)]
public string Title { get; set; }
[Column(Storage = "_DueDate", DbType = "DateTime")]
public System.Nullable<System.DateTime> DueDate { get; set; }
10
Microsoft Tech∙Ed Russia 2011. Лабораторная работа.
Использование локальной базы данных Windows Phone и её резервное копирование на севере.
public EntitySet<Attachment> Attachment { get; set; }
public Project Projects { get; set; }
public Location Location { get; set; }
}
9. Добавим атрибут Association к оставшимся свойствам. Эти свойства представляют собой
ссылку на другую сущность:
C#
public partial class Task
{
[Column( Storage = "_Status", DbType="Int")]
public TaskStatus Status { get; set; }
[Column(Storage = "_Priority", DbType = "Int")]
public PriorityValue Priority { get; set; }
[Column(Storage = "_ItemID", DbType = "UniqueIdentifier NOT NULL",
IsPrimaryKey = true)]
public System.Guid Id { get; set; }
[Column(Storage = "_ProjectID", DbType = "UniqueIdentifier NOT NULL")]
public System.Guid ProjectID { get; set; }
[Column(Storage = "_LocationID", DbType = "UniqueIdentifier")]
public System.Guid LocationID { get; set; }
[Column(Storage = "_Completed", DbType = "Bit NOT NULL")]
public bool Completed { get; set; }
[Column(Storage = "_Title", DbType = "NVarChar(100) NOT NULL",
CanBeNull = false)]
public string Title { get; set; }
[Column(Storage = "_DueDate", DbType = "DateTime")]
public System.Nullable<System.DateTime> DueDate { get; set; }
[Association(Name = "Attachment_Items", Storage = "_Attachment",
ThisKey = "Id", OtherKey = "ItemID", DeleteRule = "NO ACTION")]
public EntitySet<Attachment> Attachment { get; set; }
[Association(Name = "Project_Item", Storage = "_Projects",
ThisKey = "ProjectID", OtherKey = "Id", IsForeignKey = true)]
public Project Projects { get; set; }
[Association(Name = "Items_Location", Storage = "_Location",
ThisKey = "LocationID", OtherKey = "Id", IsForeignKey=true)]
public Location Location { get; set; }
11
Microsoft Tech∙Ed Russia 2011. Лабораторная работа.
Использование локальной базы данных Windows Phone и её резервное копирование на севере.
}
Ассоциации, которые мы только что определили относятся к совокупности приложения
задачи, к проекту, к которому принадлежит задача и к расположению задачи. Сущность
Task теперь корректно отображена в базе данных. Реальный код будет выглядеть
несколько иначе, так как мы не включили различные дополнительные блоки, вносимые
SqlMetal автоматически. Мы также не реализовали интерфейс IPropertyNotifier,
упоминаемый ранее.
Задание 2 - Создание базы данных
Вы только что научились, определять модель объектов и атрибуты, необходимые для
преобразования в схеме базы данных. На этом шаге мы будем изучать создание базы данных на
основании этой схемы. Создание происходит во время работы приложения.
1. Создайте экземпляр контекста данных. Изучите следующий код, взятый из конструктора
класса App в файле App.xaml.cs проекта Todo:
C#
TodoDC = new DataContextBase("Data Source='" + DatabaseFilename + "'" +
(DatabasePassword.Length == 0 ? "" : ";Password='" + DatabasePassword +
"'"));
Таким образом мы создаем новый экземпляр DataContextBase для использования в
приложении. Резервный файл базы данных расположен, согласно содержанию константы
DatabaseFilename, установленной в “isostore:ToDo.sdf”.
2. Экземпляр DataContextBase , созданный выше, используется для класса DataHelper
(расположен в проекте Todo.Business, папке Data) для создания актуальной базы данных.
Класс DataHelper производит начальную установку базы данных путем предоставления
методов для проверки, существует ли база данных в выделенном хранилище, или, если не
существует, для создания ее. Класс DataHelper наполняет только что созданную базу
данных исходными данными, создает проект по умолчанию и определяет доступные типы
вложений.
3. Откройте файл DataHelper.cs в папке, упомянутой в предыдущем шаге, и изучите метод
CreateDatabase класса DataHelper.
C#
private static void CreateDatabase(DataContextBase todo)
{
try
{
// Сгенерируйте базу данных (вместе со структурой) из
// контекста данных, основанных на коде
todo.CreateDatabase();
12
Microsoft Tech∙Ed Russia 2011. Лабораторная работа.
Использование локальной базы данных Windows Phone и её резервное копирование на севере.
// Наполните базу данных системной информацией
GenerateSystemData(todo);
// Создайте исходную задачу
Task items = new Task();
items.ItemID = Guid.NewGuid();
items.Title = "Welcome to the \"Todo\"!";
items.Completed = true;
todo.Items.InsertOnSubmit(items);
todo.SubmitChanges();
}
catch (Exception ex)
{
MessageBox.Show("Error while creating the DB: " + ex.Message);
System.Diagnostics.Debug.WriteLine("Error while creating the DB: " +
ex.Message);
}
}
Фактически в методе выше только одна строка кода отвечает за создание базы данных, и
это запрос к методу CreateDatabase класса DataContextBase, наследованному от
System.Data.Linq.DataContext. Остальная часть метода заполняет новую базу данных
исходными данными. Эта порция кода выполняется только в первый запуск приложения.
Как только база данных создана, все последующие запуски приложения просто открывают
существующую базу данных. Это наглядно видно в методе InitializeDatabase и классе
DataHelper:
C#
public static void InitializeDatabase(DataContextBase todo)
{
using (IsolatedStorageFile iso =
IsolatedStorageFile.GetUserStoreForApplication())
{
if (iso.FileExists("ToDo.sdf"))
return;
CreateDatabase(todo);
}
}
Задание 3 - Развертывание существующей базы данных
Есть альтернатива созданию новой базы данных с нуля и это развертывание стандартной базы
данных. Исходная база данных включена в xap файл приложения, как любой другой ресурс (такой
13
Microsoft Tech∙Ed Russia 2011. Лабораторная работа.
Использование локальной базы данных Windows Phone и её резервное копирование на севере.
как изображение или звуковой файл), приложение загружает файл базы данных и сохраняет его в
выделенное хранилище. Как только база данных сохранена в выделенном хранилище, она готова
к использованию приложением.
Такой подход часто используется с базами данных, в которых будут хранится большие объемы
референтных значений. Хорошим примером такой базы данных может быть словарь. Поскольку в
приложении Tidy не такого количество исходных данных, мы не используем такой подход.
Развертывание готовой базы данных состоит из трех простых шагов:
1. Доступ к файлу исходной базы данных.
2. Создание файла хранилища, который будет выполнять роль файла базы данных
приложения.
3. Сохранение содержания файла исходной базы данных в файл хранилища.
Код ниже иллюстрирует перечисленные шаги:
C#
private void CreateDatabaseFromResourceFile(string inFilename, string
outFilename)
{
// Шаг 1
Stream str = Application.GetResourceStream(new Uri(inFilename,
UriKind.Relative)).Stream;
// Шаг 2
IsolatedStorageFileStream outFile = iso.CreateFile(outFilename);
// Шаг 3
outFile.Write(ReadToEnd(str), 0, (int)str.Length);
str.Close();
outFile.Close();
}
Команда “ReadToEnd” просто возвращает все содержание развернутой базы данных как
массив байтов.
Задание 4 - Получение данных
Теперь, когда мы научились производить начальную установку базы данных, у нас есть
возможность изучить получение данных из базы данных. Мы научимся этому на примере класса
TaskViewModel, содержащегося в проекте Todo, в папке ViewModels. TaskViewModel
запрашивает информацию в модуле приложения напрямую, используя контекст данных.
Заметка: Хотя в данной лабораторной работе мы используем TaskViewModel, реально любой
другой класс, наследуемый из ViewModelItemsBase , может служить примером.
14
Microsoft Tech∙Ed Russia 2011. Лабораторная работа.
Использование локальной базы данных Windows Phone и её резервное копирование на севере.
1. Давайте рассмотрим метод LoadData класса TaskViewModel :
C#
public override void LoadData()
{
PropertyChanged += new
PropertyChangedEventHandler(TasksViewModel_PropertyChanged);
var tasks = from t in todoDC.Items select t;
foreach (var task in tasks)
{
Items.Add(task);
task.PropertyChanged += task_PropertyChanged;
}
// Регистрируем этот момент сейчас, нам не нужно будет запускать
обновления каждый раз,
// когда загружается новый элемент.
Items.CollectionChanged += Items_CollectionChanged;
IsDataLoaded = true;
NotifyCollectionChanges();
}
Большая часть методов используется для установления дополнительных блоков
обновления пользовательского интерфейса, которые связаны с экземпляром ViewModel, а
не напрямую с данными, содержащимися в базе данных. Выделенная строка кода выше
необходима для выполнения всех задач, перечисленных в таблице задач базы данных Она
использует экземпляр контекста данных, содержащийся в “todoDC” (тот же экземпляр, что
мы создавали в шаге 1 задания 2).
Этот код помещает все экземпляры задач во внутреннюю коллекцию для использования
пользовательским интерфейсом, и регистрирует изменения в наборе доступных задач и
изменения в индивидуальных задачах, для поддержания актуальности интерфейса.
2. Давайте рассмотрим метод NotifyCollectionChanges класса TaskViewModel :
C#
private void NotifyCollectionChanges()
{
NotifyPropertyChanged("Today");
NotifyPropertyChanged("Urgent");
NotifyPropertyChanged("Completed");
NotifyPropertyChanged("ByDate");
}
15
Microsoft Tech∙Ed Russia 2011. Лабораторная работа.
Использование локальной базы данных Windows Phone и её резервное копирование на севере.
Представленный метод запускает уведомления об изменениях по нескольким свойствам
TaskViewModel’s и представляет отфильтрованный список задач базы данных.
3. Давайте рассмотрим свойство Today класса TaskViewModel : Это свойство включает в себя
все задачи, которые должны быть исполнены сегодня и обновлены как только дата
выполнения обновляется (смотрите обработчик task_PropertyChanged ) или когда
изменяется вся коллекция (смотрите обработчик Items_CollectionChanged):
C#
public IOrderedEnumerable<Task> Today
{
get
{
return from task in App.TasksViewModel.Items
where task.DueDate.HasValue && task.DueDate.Value.Date ==
DateTime.Now.Date
orderby task.Priority
select task;
}
}
Задание 5 - Внесение данных
В это лабораторной работе мы уже сталкивались с внесением новых данных в базу данных. Мы
проиллюстрируем эту возможность с помощью уже приводимого кода и изучим соответствующие
части TaskViewModel.
1. Давайте рассмотрим следующий отрывок из метода CreateDatabase в DataHelper.
C#
...
// Создайте исходную задачу
Task items = new Task();
items.ItemID = Guid.NewGuid();
items.Title = "Welcome to the \"Todo\" application!";
items.Completed = true;
todo.Items.InsertOnSubmit(items);
todo.SubmitChanges();
.
Код выше показывает, что добавить новые данные в базу данных достаточно просто.
Просто создайте объект, представляющий сущность, которую вы хотите добавить в базу
данных, задайте начальные настройки, и затем запустите метод InsertOnSubmit, добавив в
новый объект соответствующую таблицу с контекстом данных. Вы должны внести
изменения в базу данных с помощью метода контекста данных SubmitChanges для их
финализации.
16
Microsoft Tech∙Ed Russia 2011. Лабораторная работа.
Использование локальной базы данных Windows Phone и её резервное копирование на севере.
2. Экран редактирования/создания задач использует этот же подход. Откройте файл
EditTaskView.xaml.cs в проекте Todo, подпапка Views\Tasks. Ниже код файла для класса
EditTaskView. Откройте метод OnNavigatedTo и вы увидите следующий кусок кода:
C#
...
if
(NavigationContext.QueryString.ContainsKey(UIConstants.ProjectIdQueryParam))
{
// Мы находим страницу для создания новой задачи под конкретный проект.
PageTitle.Text = ApplicationStrings.TaskEditNewTaskTitle;
task = new Task();
.
3. Когда пользователь сохраняет новую задачу, метод Insert класса TaskViewModel
сохраняет ее в базе данных. Этот метод всего лишь надстройка для действий, которые мы
производили в шаге 1:
C#
public void Insert(Task item)
{
Items.Add(item);
todoDC.Items.InsertOnSubmit(item);
todoDC.SubmitChanges();
}
Задание 6 - Обновление данных
Обновление данных, уже внесенных в базу, еще проще, чем внесение новых. Первым шагом
будет получение ссылки на существующую сущность.
1. Откройте класс EditTaskView , с которым вы работали во втором шаге предыдущего
задания, но в этот раз найдите метод GetTaskFromQueryString:
C#
private void GetTaskFromQueryString()
{
Guid taskGuid = NavigationContext.GetGuidParam(
UIConstants.TaskIdQueryParam);
task = App.TasksViewModel.Items.FirstOrDefault(t => t.ItemID == taskGuid);
}
Этот метод получает доступ к существующим данным через TaskViewModel для
формирования ссылки на задачу с определенным ID.
17
Microsoft Tech∙Ed Russia 2011. Лабораторная работа.
Использование локальной базы данных Windows Phone и её резервное копирование на севере.
2. Как только ссылка получена, следующим шагом становится изменения одного из ее
свойств. В приложении нет такого кода, поскольку изменения происходят в результате
привязки данных. Следующий код, недоступный в приложении, демонстрирует
изменения происходящие в свойствах ссылки:
C#
task.Title = "New Title";
3. Изменения сущности, связанной с базой данных, приводят к задержке обновления и
постановке его в очередь контекста данных. Метод Update класса TaskViewModel
показывает как завершить задержанное обновление:
C#
public void Update(Task item)
{
todoDC.SubmitChanges();
}
Задание 7 - Удаление данных
Удаление данных схоже с добавлением или обновлением данных, и также может быть наглядно
представлено через класс TaskViewModel:
1. Давайте рассмотрим метод Delete класса TaskViewModel :
C#
public void Delete(Guid itemID)
{
App.AttachmentViewModel.DeleteByTaskID(itemID);
var res = from i in Items
where i.ItemID == itemID
select i;
Task itm = res.FirstOrDefault();
if (null != itm)
{
Items.Remove(itm);
todoDC.Items.DeleteOnSubmit(itm);
todoDC.SubmitChanges();
}
}
18
Microsoft Tech∙Ed Russia 2011. Лабораторная работа.
Использование локальной базы данных Windows Phone и её резервное копирование на севере.
Метод выше удаляет задачи, основываясь на их ID, путем поиска среди существующих
сущностей конкретной задачи. Если конкретное ID найдено, оно удаляется из локальной
коллекции TaskViewModel и затем из реальной базы данных, путем перенесения задачи в
соответствующую таблицу метода DeleteOnSubmit. Как и прежде, изменения необходим
завершить SubmitChanges.
Резюме
С помощью данной лабораторной работы вы изучили необходимые шаги для работы с локальной
базой данных в приложении Windows Phone. После исходной установки, которая в основном
включает в себя определение контекста данных, LINQ to SQL дает вам возможность забыть о
существовании базы данных. Эта новая возможность позволяет вам создавать приложения,
которые могут легко обрабатывать большие объемы данных.
Использование фоновой службы передачи файлов
Заметка: Файлы для этого задания находятся в папке C:\MangoTrainingCourse\Labs\ TodoBTS
При написании приложения для Windows® Phone Codenamed Mango вам возможно понадобится
настроить передачу файлов. Поскольку эти файлы иногда необходимы для функционирования
приложения, есть возможность загружать их асинхронно, с уведомлением после загрузки.
Подобные сценарии включают загрузку больших файлов (музыка и видео), загрузку длинных
отчетов на сервер или резервное копирование базы данных приложения.
Возможность вести передачу файлов в фоновом режиме и получать уведомления о статусе
процесса - одна из ключевых возможностей Windows® Phone Codenamed Mango. Важно отметить,
что передача файлов продолжается даже, если приложение неактивно или остановлено.
Данная лабораторная работа показывает как добавить фоновую службу передачи файлов в ваше
приложение используя Windows® Phone Codenamed Mango API и как обрабатывать запросы
BackgroundTransferService.
Цели
Данная лабораторная работа содержит инструкции для достижения следующих результатов:

Добавление фоновой службы в Ваше приложение для Windows® Phone.

Понимание как работать с BackgroundTransferService и управлять запросами вашего
приложения.
Предварительные требования
Для успешного выполнения лабораторной работы Вам необходимо следующее:
19
Microsoft Tech∙Ed Russia 2011. Лабораторная работа.
Использование локальной базы данных Windows Phone и её резервное копирование на севере.

Вам следует установить Microsoft Visual Studio 2010 или Microsoft Visual C# Express 2010 и
Windows® Phone Developer Tools, которые доступны по ссылке
http://go.microsoft.com/?linkid=9772716

Вам также понадобятся знания разработки приложений для Windows® Phone 7.
Структура лабораторной работы
Лабораторная работа состоит из одного упражнения. Упражнение состоит из следующих заданий:
1. Создание сервис синхронизации для приложения и реализация логики
копирования/восстановления базы данных.
2. Реализация пользовательского интерфейса для копирования/восстановления базы
данных.
Примерное время выполнения
Данная лабораторная работа должна быть выполнена в течение 30 минут.
Упражнение
Данная лабораторная работа выполняется с помощью приложения Tidy. Приложение Tidy
позволяет пользователю управлять проектами, содержащими задачи с потенциальной датой
завершения. Пользователь должен осуществлять резервное копирование и восстановление базы
данных приложения через интерфейс меню "Настройки". Мы начнем лабораторную работу с
копии приложения, в которой были удалены все возможности по резервному копированию и
восстановлению. Эта версия приложения находится в папке по установке лабораторной работы
под именем Sources\Begin. После выполнения лабораторной работы Ваша версия приложения
должна быть идентична той, что содержится в папке Sources\End.
Задание 1 - Добавление компонента фоновой передачи данных
Хотя Windows® Phone Mango API для работы с BackgroundTransferService не вызывает затруднений,
работа в контексте приложения Tidy может быть трудоемкой. В данном задании мы добавляем
класс для задач выгрузки/загрузки данных для приложения. Эти методы продемонстрируют как
использовать новые классы Microsoft.Phone.BackgroundTransfer.BackgroundTransferRequest и
Microsoft.Phone.BackgroundTransfer.BackgroundTransferService для выполнения резервного
копирования и восстановления.
1. Откройте файл Todo.sln, расположенный в папке установки лабораторной работы
Source\Begin.
Заметка: Это приложение использует REST WCF сервис на рабочей станции для
выгрузки/загрузки файлов и симуляции реального процесса резервного копирования.
20
Microsoft Tech∙Ed Russia 2011. Лабораторная работа.
Использование локальной базы данных Windows Phone и её резервное копирование на севере.
Проект, ответственный за данную функциональность, расположен в директории
FileUploaderWcfRestService и добавлен к решению. Для работы с WCF сервисом рабочей
станции Вы должны будете запустить Visual Studio 2010 с правами администратора.
Также, для успешной работы с SDF файлами базы данных (файлы базы данных SQL CE,
используемых на Windows Phone Mango) Вам необходимо добавить новый тип MIME к
IIS:
Расширение: .sdf
Тип MIME: application/octet-stream
Добавьте его либо во все сайты на IIS или to the Virtual directory (по умолчанию
FileUploaderWcfRestService), созданный для данной лабораторной работы by WCF REST
service project.
2. Изучите папку SERVER_FileUploader и найдите проект FileUploaderWcfRestService. Изучите
файлы проекта IUploaderService.cs и UploaderService.cs . В этих файлах содержится
функциональность, которая будет использоваться для запросов выгрузки/загрузки, .над
которыми мы будем работать в следующих шагах.
3. Найдите проект Todo.Business, откройте папку Interfaces и найдите файл ISyncProvider.cs.
Этот файл определяет интерфейс ISyncProvide, который мы будем использовать для
создания функциональности сервиса синхронизации.
C#
public interface ISyncProvider
{
string Name { get; }
void Upload(string username, string password, string filename);
void Download(string username, string password, string filename);
}
4. В том же проекте Todo.Business, откройте папку Misc и найдите файл SyncServices.cs. Для
обновления статуса процессов выгрузки/загрузки в приложении добавьте в файл два
класса с событиями, в качестве аргумента (с Todo.Misc пространством имен, которое уже
задано в файле) - мы будем использовать их в процессе выгрузки и загрузки для
информирования UI приложения о статусе задач:
C#
public class DownloadUploadFinishedEventArgs : EventArgs
{
public DownloadUploadFinishedEventArgs()
{
}
}
21
Microsoft Tech∙Ed Russia 2011. Лабораторная работа.
Использование локальной базы данных Windows Phone и её резервное копирование на севере.
public class DownloadUploadProgressEventArgs : EventArgs
{
private long progress, total;
private bool isUpload;
public DownloadUploadProgressEventArgs(bool isUpload, long progress, long
total)
{
this.progress = progress;
this.total = total;
this.isUpload = isUpload;
}
public long Progress
{
get { return progress; }
}
public long Total
{
get { return total; }
}
public bool IsUpload
{
get { return isUpload; }
}
}
5. Создайте новый класс и назовите его LocalhostSync. Разместите этот класс в папке Misc
проекта Todo.Business и реализуйте для него интерфейс ISyncProvider.
C#
public class LocalhostSync : ISyncProvider
{
#region ISyncProvider Members
public string Name
{
get { return LocalizedStrings.LocalhostSyncName; }
}
public void Upload(string username, string password, string filename)
{
// ...
}
public void Download(string username, string password, string filename)
22
Microsoft Tech∙Ed Russia 2011. Лабораторная работа.
Использование локальной базы данных Windows Phone и её резервное копирование на севере.
{
// ...
}
#endregion
}
6. Добавьте к классу следующие константы:
C#
const string serviceUploadLocationURL =
"http://localhost/FileUploaderWcfRestService/UploaderService/File/";
const string downloadLocationURL =
"http://localhost/FileUploaderWcfRestService/Backups/";
const string TransfersFiles = "shared\transfers";
const string downloadedDBName = "ToDo_NEW.sdf";
const string localDBName = "ToDo.sdf";
Обратите внимание, что если вы решите изменить расположение сервиса REST WCF, Вам
нужно будет соответствующим образом изменить URL выгрузки и загрузки.
7. Давайте реализуем функциональность выгрузки:
C#
public void Upload(string username, string password, string filename)
{
// Убедитесь, что база данных для выгрузки и копирования существует.
using (IsolatedStorageFile iso =
IsolatedStorageFile.GetUserStoreForApplication())
{
if (!iso.FileExists(localDBName))
return;
iso.CopyFile(localDBName,"/" + TransfersFiles + "/" +
localDBName,true);
}
Поставьте фоновую передачу данных для выгрузки копии базы данных в очередь
BackgroundTransferRequest btr = new BackgroundTransferRequest (new Uri
(serviceUploadLocationURL + localDBName,UriKind.Absolute));
btr.TransferPreferences = TransferPreferences.AllowBattery;
btr.Method = "POST";
btr.UploadLocation = new Uri("/" + TransfersFiles + "/" + localDBName,
UriKind.Relative);
btr.TransferStatusChanged += new
EventHandler<BackgroundTransferEventArgs>(
btr_UploadTransferStatusChanged);
23
Microsoft Tech∙Ed Russia 2011. Лабораторная работа.
Использование локальной базы данных Windows Phone и её резервное копирование на севере.
btr.TransferProgressChanged += new
EventHandler<BackgroundTransferEventArgs>(
btr_TransferProgressChanged);
Microsoft.Phone.BackgroundTransfer.BackgroundTransferService.Add(btr);
}
Смотрите, как при создании экземпляра BackgroundTransferRequest происходит subscribe
to progress events для отслеживания операций.
8. Добавьте следующий код к классу ряда событий:
C#
public delegate void DownloadFinishedEventHandler(object sender,
DownloadUploadFinishedEventArgs e);
public delegate void DownloadProgressEventHandler(object sender,
DownloadUploadProgressEventArgs e);
public event DownloadFinishedEventHandler DownloadFinished;
public event DownloadFinishedEventHandler UploadFinished;
public event DownloadProgressEventHandler DownloadUploadProgress;
9. Добавьте обработчики событий, обозначенные в шаге 7:
C#
void btr_TransferProgressChanged(object sender, BackgroundTransferEventArgs e)
{
// Если необходимо отправить байты, то это операция выгрузки
bool isUploading = e.Request.TotalBytesToSend > 0 ? true : false;
if (null != DownloadUploadProgress)
DownloadUploadProgress(this new
DownloadUploadProgressEventArgs(isUploading,
isUploading ?
e.Request.BytesSent : e.Request.BytesReceived,
isUploading ?
e.Request.TotalBytesToSend : e.Request.TotalBytesToReceive));
}
void btr_UploadTransferStatusChanged(object sender,
BackgroundTransferEventArgs e)
{
if (e.Request.TransferStatus == TransferStatus.Completed)
{
using (IsolatedStorageFile iso =
IsolatedStorageFile.GetUserStoreForApplication())
{
if (iso.FileExists(e.Request.UploadLocation.OriginalString))
iso.DeleteFile(e.Request.UploadLocation.OriginalString);
24
Microsoft Tech∙Ed Russia 2011. Лабораторная работа.
Использование локальной базы данных Windows Phone и её резервное копирование на севере.
}
BackgroundTransferService.Remove(e.Request);
if (null != e.Request.TransferError)
{
// Отметьте в журнале возникающую здесь ошибку, если позволяет
приложение.
}
else
{
if (null != UploadFinished)
UploadFinished(this, new DownloadUploadFinishedEventArgs());
}
}
}
Обработчик btr_TransferProgressChanged определяет, выполняется ли операция загрузки
или выгрузки, и запускает соответствующее событие DownloadUploadProgress . Мы будем
использовать его снова при работе с операциями загрузки.
Обработчик btr_UploadTransferStatusChanged используется только при запросе выгрузки.
Он отвечает за завершение операции выгрузки, выполняя следующее:
a. Удаление временных файлов из “transfers” location.
b. Удаление выполненных запросов из очереди запросов
BackgroundTransferService
c. Уведомление приложения о заверешении выгрузки.
10. Давайте обработаем загрузку файла. Добавьте следующий код к функции загрузки:
C#
public void Download(string username, string password, string filename)
{
BackgroundTransferRequest btr =
new BackgroundTransferRequest(
new Uri(downloadLocationURL + localDBName, UriKind.Absolute),
new Uri(TransfersFiles + @"\" + downloadedDBName,
UriKind.Relative));
btr.TransferPreferences = TransferPreferences.AllowBattery;
btr.TransferStatusChanged +=
new EventHandler<BackgroundTransferEventArgs>(
btr_DownloadTransferStatusChanged);
btr.TransferProgressChanged +=
new EventHandler<BackgroundTransferEventArgs>(
btr_TransferProgressChanged);
BackgroundTransferService.Add(btr);
25
Microsoft Tech∙Ed Russia 2011. Лабораторная работа.
Использование локальной базы данных Windows Phone и её резервное копирование на севере.
}
Процесс идентичен методу Upload, который мы реализовали ранее. Обратите внимание,
что в этот раз мы используем другой обработчик событий для отражения статуса
операции.
11. Теперь давайте добавим обработчик завершения загрузки:
C#
void btr_DownloadTransferStatusChanged(object sender,
BackgroundTransferEventArgs e)
{
if (e.Request.TransferStatus == TransferStatus.Completed)
{
BackgroundTransferService.Remove(e.Request);
if (null != e.Request.TransferError)
{
// Отметьте в журнале возникающую здесь ошибку, если позволяет
приложение.
}
else
{
//Перепишите базу данных
using (IsolatedStorageFile iso =
IsolatedStorageFile.GetUserStoreForApplication())
{
iso.CopyFile("/" + TransfersFiles + "/" + downloadedDBName,
"/" + localDBName, true);
iso.DeleteFile("/" + TransfersFiles + "/" + downloadedDBName);
if (null != DownloadFinished)
DownloadFinished(this, new
DownloadUploadFinishedEventArgs());
}
}
}
}
Как и в обработчике btr_UploadTransferStatusChanged , мы удаляем завершенный запрос
из очереди запросов и запускаем событие, информирующее о том, что загрузка
завершена, но помимо этого мы должны заменить существующую базу данных
загруженной.
12. Этим завершается задание. В следующем задании, мы будем добавлять UI для
выполнения описанной функциональности.
26
Microsoft Tech∙Ed Russia 2011. Лабораторная работа.
Использование локальной базы данных Windows Phone и её резервное копирование на севере.
Задание 2 - Отражение процессов резервного копирования/восстановления базы данных в
пользовательском интерфейсе
В предыдущем задании мы проделали основную работу по загрузке и выгрузке файлов базы
данных, что является основой для резервного копирования/восстановления базы данных. В этом
задании, мы изменим интерфейс приложения для включения в него функций резервного
копирования и восстановления базы данных.
1. Скомпилируйте и запустите приложение. Откройте экран "Настройки" (через меню
"Настройки" на панели инструментов приложения):
27
Microsoft Tech∙Ed Russia 2011. Лабораторная работа.
Использование локальной базы данных Windows Phone и её резервное копирование на севере.
Рисунок 2
Экран настроек с кнопками Резервное копирование/восстановление
Экран, отображенный на рисунке, позволяет запустить процессы резервного копирования
и восстановления данных с помощью функциональности, созданной в предыдущем
задании. На данном этапе, кнопки не рабочие.
28
Microsoft Tech∙Ed Russia 2011. Лабораторная работа.
Использование локальной базы данных Windows Phone и её резервное копирование на севере.
2. Мы начинаем с обновления настроек ViewModel, что позволит нам управлять
настройками приложения. В проекте Todo откройте папку ViewModels и затем файл
SettingsViewModel.cs. Добавьте следующее поле к классу SettingsViewModel:
C#
private LocalhostSync syncProvider;
Это действие приостановит работу поставщика синхронизации, которого мы будем
использовать для резервного копирования и восстановления базы данных.
3. Добавьте следующие свойства и резервные поля к классу SettingsViewModel:
C#
private bool syncInProgress;
/// <summary>
/// Выполняется ли сейчас операция синхронизации или нет.
/// </summary>
public bool SyncInProgress
{
get
{
return syncInProgress;
}
set
{
if (value != syncInProgress)
{
syncInProgress = value;
NotifyPropertyChanged("SyncInProgress");
}
}
}
private long syncTotal;
/// <summary>
/// Общий размер текущей операции синхронизации. Не информативно, если в
данный момент операция не выполняется
/// </summary>
public long SyncTotal
{
get
{
return syncTotal;
}
set
{
29
Microsoft Tech∙Ed Russia 2011. Лабораторная работа.
Использование локальной базы данных Windows Phone и её резервное копирование на севере.
if (value != syncTotal)
{
syncTotal = value;
NotifyPropertyChanged("SyncTotal");
}
}
}
private long syncProgress;
/// <summary>
/// Статус текущей операции синхронизации. Не информативно, если в данный
момент операция не выполняется
/// </summary>
public long SyncProgress
{
get
{
return syncProgress;
}
set
{
if (value != syncProgress)
{
syncProgress = value;
NotifyPropertyChanged("SyncProgress");
}
}
}
Эти свойства будут использоваться для отображения любого процесса резервного
копирования/восстановления данных в пользовательском интерфейсе, как и для
предупреждения запуска пользователем несколько операций одновременно.
4. Измените конструктор класса так, как это выглядит в следующем фрагменте (новый код
выделен желтым):
C#
public SettingsViewModel()
{
syncProvider = new LocalhostSync();
syncProvider.DownloadFinished += DownloadFinished;
syncProvider.UploadFinished += UploadFinished;
syncProvider.DownloadUploadProgress += OperationProgress;
periodicTask = ScheduledActionService.Find(PeriodicTaskName) as
PeriodicTask;
30
Microsoft Tech∙Ed Russia 2011. Лабораторная работа.
Использование локальной базы данных Windows Phone и её резервное копирование на севере.
if (periodicTask != null)
IsBackgroundProcessingAllowed = periodicTask.IsEnabled;
else
IsBackgroundProcessingAllowed = true; ;
LoadSettings();
}
Мы обновили конструктор таким образом, чтобы запустить поставщика синхронизации и
зарегистрировать его события, что нам позволяет теперь обновить свойства ViewModel в
зависимости от статуса поставщика синхронизации.
5. Обработчик событий из предыдущих шагов:
private void OperationProgress(object sender, DownloadUploadProgressEventArgs
e)
{
SyncTotal = e.Total;
SyncProgress = e.Progress;
}
private void UploadFinished(object sender, DownloadUploadFinishedEventArgs e)
{
SyncInProgress = false;
}
private void DownloadFinished(object sender, DownloadUploadFinishedEventArgs
e)
{
MessageBox.Show(ApplicationStrings.Msg_RestoreWarning);
SyncInProgress = false;
}
6. Добавьте следующие два метода к класс:
C#
public void UploadDatabase()
{
SyncProgress = 0;
SyncInProgress = true;
syncProvider.Upload("x", "x", "x");
}
public void DownloadDatabase()
{
SyncProgress = 0;
SyncInProgress = true;
31
Microsoft Tech∙Ed Russia 2011. Лабораторная работа.
Использование локальной базы данных Windows Phone и её резервное копирование на севере.
syncProvider.Download("x", "x", "x");
}
Эти методы используют поставщика синхронизации для резервного копирования и
восстановления базы данных. Так как для нашего поставщика мы не используем учетные
данные, вводим любую информацию.
7. Операции резервного копирования/восстановления данных привязаны к UI кнопкам с
помощью команд, отображенных в методах OnBackup и Onrestore, с помощью кода ниже:
C#
void OnBackup(object param)
{
UploadDatabase();
}
void Onrestore(object param)
{
DownloadDatabase();
}
8. Скомпилируйте и запустите приложение. Теперь у Вас должна быть возможность сделать
резервное копирование и восстановить базу данных.
Резюме
Эта лабораторная работа показала вам как, используя Windows® Phone Mango APIs, добавлять
фоновый режим загрузки и выгрузки файлов в вашем приложении. Вы также увидели, как
фоновый режим может использоваться для создания функциональности резервного копирования
и восстановления данных в вашем приложении.
32
Microsoft Tech∙Ed Russia 2011. Лабораторная работа.
Использование локальной базы данных Windows Phone и её резервное копирование на севере.
Download