Статьи

Использование Entity Framework для создания баз данных на Windows Phone Часть 3

В первой и второй частях мы использовали Entity Framework для создания модели, отслеживающей идеи для другого приложения, сгенерировали файл базы данных .sdf, сгенерировали классы данных, а затем исправили ошибки в классе, чтобы он работал в Windows Phone. В этой части мы добавим некоторую структуру в наше приложение, настроим БД при первом запуске и добавим некоторые данные по умолчанию в некоторые таблицы. Затем, наконец, мы создадим пару представлений для отображения информации в базе данных.

Основываясь на отзывах, я хотел бы уточнить, что на данный момент мы закончили с использованием Entity Framework и используем LINQ to SQL для управления базой данных, которую мы использовали для разработки EF в Части 1.

Вы можете получить исходный код здесь.

Часть 3: Использование классов данных в приложении Windows Phone

Теперь, когда у нас есть сгенерированные классы в нашем проекте, пришло время их использовать. Нам нужно сначала немного настроить. Во второй части мы создали папку с названием Models. Это часть шаблона проектирования, который рекомендуется для всех, кроме самых простых приложений WP7. Мы будем использовать этот шаблон в нашем приложении.

Первое, что мы сделаем, это добавим в проект AppTracker.WP папку с именем Views.

Теперь мы собираемся создать класс для обработки данных по умолчанию в базе данных. Добавьте папку с именем DefaultData в проект AppTracker.WP. В нем добавьте класс DefaultData.cs. В этот класс мы включаем функции, которые:
проверяют, существует ли база данных, и удаляют ее при необходимости. Я использую это, чтобы облегчить первоначальное создание и повторное создание БД. Полезно, если вы хотите добавить опцию сброса.

public bool CreateDatabase(bool deleteExisting = false)
{
    try
    {
        if (_context.DatabaseExists())
        {
            if(deleteExisting)
            {
                _context.DeleteDatabase();
            }
            else
            {
                return false;
            }
        }   
        _context.CreateDatabase();
        return true;
    }
    catch (Exception ex)
    {
        if (System.Diagnostics.Debugger.IsAttached)
        {
            MessageBox.Show(ex.Message);
        }
        return false;
    }
}

Populate 5 tables with default data:
public bool PopulateStatusTable()
{
    try
    {
        var statuses = new List<Status>();

        var status = new Status { Id = 1, Name = "In Progress", Description = "Description Description Description Description Description" };
        statuses.Add(status);

        status = new Status { Id = 2, Name = "Games", Description = "Description Description Description Description Description" };
        statuses.Add(status);

        status = new Status { Id = 3, Name = "Other", Description = "Description Description Description Description Description" };
        statuses.Add(status);

        _context.Status.InsertAllOnSubmit(statuses);
        _context.SubmitChanges();

        return true;
    }
    catch (Exception ex)
    {
        if (System.Diagnostics.Debugger.IsAttached)
        {
            MessageBox.Show(ex.Message);
        }
        return false;
    }
}

public bool PopulatePlatformsTable()
{
    try
    {
        var platforms = new List<Platform>();

        var platform = new Platform { Id = 1, Name = "Windows Phone", Description = "Description Description Description Description Description" };
        platforms.Add(platform);

        platform = new Platform { Id = 2, Name = "Android", Description = "Description Description Description Description Description" };
        platforms.Add(platform);

        platform = new Platform { Id = 3, Name = "iOS", Description = "Description Description Description Description Description" };
        platforms.Add(platform);

        _context.Platforms.InsertAllOnSubmit(platforms);
        _context.SubmitChanges();

        return true;
    }
    catch (Exception ex)
    {
        if (System.Diagnostics.Debugger.IsAttached)
        {
            MessageBox.Show(ex.Message);
        }
        return false;
    }
}

public bool PopulateTagsTable()
{
    try
    {
        var tags = new List<Tag>();

        var category = new Tag { Id = 1, Name = "Tag 1", Description = "Description Description Description Description Description" };
        tags.Add(category);

        category = new Tag { Id = 2, Name = "Tag 2", Description = "Description Description Description Description Description" };
        tags.Add(category);

        category = new Tag { Id = 3, Name = "Tag 3", Description = "Description Description Description Description Description" };
        tags.Add(category);

        _context.Tags.InsertAllOnSubmit(tags);
        _context.SubmitChanges();

        return true;
    }
    catch (Exception ex)
    {
        if (System.Diagnostics.Debugger.IsAttached)
        {
            MessageBox.Show(ex.Message);
        }
        return false;
    }
}
public bool PopulateIdeasTable()
{
    try
    {
        var ideas = new List<Idea>();

        var idea = new Idea { Id = 1, Name = "Idea 1", Description = "Description Description Description Description Description", CategoryId = 1, StatusId = 1, DateAdded = DateTime.Now, DateUpdated = DateTime.Now };
        ideas.Add(idea);

        idea = new Idea { Id = 2, Name = "Idea 2", Description = "Description Description Description Description Description", CategoryId = 1, StatusId = 1, DateAdded = DateTime.Now, DateUpdated = DateTime.Now };
        ideas.Add(idea);

        idea = new Idea { Id = 3, Name = "Idea 3", Description = "Description Description Description Description Description", CategoryId = 1, StatusId = 1, DateAdded = DateTime.Now, DateUpdated = DateTime.Now};
        ideas.Add(idea);

        _context.Ideas.InsertAllOnSubmit(ideas);
        _context.SubmitChanges();

        return true;
    }
    catch (Exception ex)
    {
        if (System.Diagnostics.Debugger.IsAttached)
        {
            MessageBox.Show(ex.Message);
        }
        return false;
    }
}

Теперь, когда у нас есть способ заполнить таблицы, давайте сделаем это. Хотя для этого есть несколько мест, я предпочитаю использовать конструктор файла MainViewModel.cs. Это гарантирует, что БД заполнена при запуске приложения.

private const string ConnectionString = @"isostore:/AppTrackerDatabase.sdf";
private AppTrackerDataContext _context = new AppTrackerDataContext(ConnectionString);

public MainViewModel() { try { if (!_context.DatabaseExists()) { // create database if it does not exist var dd = new DefaultData.DefaultData(_context); if (dd.CreateDatabase(true)) { if (Debugger.IsAttached) { MessageBox.Show("Database created."); } } else { if (Debugger.IsAttached) { MessageBox.Show("Error creating database"); } } if (dd.PopulateCategoriesTable() && dd.PopulatePlatformsTable() && dd.PopulateStatusTable() && dd.PopulateTagsTable() && dd.PopulateIdeasTable())) { if (Debugger.IsAttached) { MessageBox.Show("Tables populated"); } } else { if (Debugger.IsAttached) { MessageBox.Show("Error populating tables."); } } } else { if (Debugger.IsAttached) { MessageBox.Show("Database Exists."); } } } catch (Exception ex ) { if (Debugger.IsAttached) { MessageBox.Show(ex.Message); } } }

Теперь мы убедились, что свойство Items в MainViewModel вызывает событие PropertyChanged, поэтому пользовательский интерфейс обновляется.

private ObservableCollection _ideas;
public ObservableCollection Ideas
{
    get
    {
        return _ideas;
    }
    set
    {
        if (value != _ideas)
        {
            _ideas = value;
            NotifyPropertyChanged("Ideas");
        }
    }
}

Затем мы обновляем функцию LoadData, чтобы извлечь все записи Idea и загрузить их в коллекцию Items ObservableCollection. Эта загрузка вызывает событие PropertyChanged и вызывает обновление пользовательского интерфейса.

public void LoadData()
{
    var ideas = _context.Ideas.Where(i => i.Id != 0);
    Ideas = new ObservableCollection(ideas.ToList());
    this.IsDataLoaded = true;
}

Затем мы обновляем файл MainPage.xaml для включения информации о CategoryId и StatusId. Я не буду освещать привязку данных в этом посте, но сделаю это в ближайшем будущем.

<ListBox x:Name="MainListBox" Margin="0,0,-12,0" ItemsSource="{Binding Ideas}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Margin="0,0,0,17" Width="432" Height="200">
                <TextBlock Text="{Binding Name}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
                <TextBlock Text="{Binding Description}" TextWrapping="Wrap" Margin="12,-6,12,5" Style="{StaticResource PhoneTextSubtleStyle}"/>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="CategoryId: " TextWrapping="Wrap" Margin="12,-6,12,5" Style="{StaticResource PhoneTextSubtleStyle}" Width="122" />
                    <TextBlock Text="{Binding CategoryId}" TextWrapping="Wrap" Margin="12,-6,12,5" Style="{StaticResource PhoneTextSubtleStyle}" Width="193" />
                </StackPanel>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="StatusId: " TextWrapping="Wrap" Margin="12,-6,12,5" Style="{StaticResource PhoneTextSubtleStyle}" Width="122" />
                    <TextBlock Text="{Binding StatusId}" TextWrapping="Wrap" Margin="12,-6,12,5" Style="{StaticResource PhoneTextSubtleStyle}"/>
                </StackPanel>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Теперь, если мы запустим проект, мы увидим страницу с 3-мя идеями.

На данный момент у нас есть отправная точка для приложения с базой данных, созданной из модели сущностей. Если нам необходимо обновить модель сущностей в будущем, мы можем выполнить действия, описанные во второй части, и просто обновить файл DataClasses.cs. Построение решения покажет вам все критические изменения и поможет найти то, что вам нужно обновить.

Еще предстоит проделать большую работу, чтобы сделать это приложение достойным рынка, но в течение следующих нескольких месяцев мы рассмотрим эти части, пока у нас не будет чего-то, что мы действительно представим.