Опубликован: 08.07.2011 | Уровень: для всех | Доступ: платный
Лекция 5:

Взаимодействие приложения с базой данных

Поиск данных

При больших размерах базы данных по сотрудникам целесообразно, чтобы приложение поддерживало функцию поиска данных, например по фамилии и по должности. Для реализации функций поиска добавим на страницу PageEmployee элементы управления в соответствии с рис. 5.16рис. 5.16.

Дизайн страницы PageEmployee с элементами управления для поиска

увеличить изображение
Рис. 5.16. Дизайн страницы PageEmployee с элементами управления для поиска

XAML-описание элементов управления, поддерживающих поиск имеет следующий вид.

<TextBlock Name="TextBlockSurname" Text="Фамилия" />
<TextBlock Name="TextBlockTitle" Text="Должность" />
<TextBox Name="TextBoxSurname" TextChanged="TextBoxSurname_TextChanged"/>
<ComboBox Name="ComboBoxTitle"
ItemsSource="{Binding Source={StaticResource listTitle}}"
DisplayMemberPath="Title1"
SelectionChanged="ComboBoxTitle_SelectionChanged"/>
<Button Name="ButtonFindSurname" ToolTip="Поиск по фамилии"
IsEnabled="False" Click="ButtonFindSurname_Click">
<Image Source="Images/Search.jpg"/>
</Button>
<Button Name="ButtonFindTitle" ToolTip="Поиск по должности"
IsEnabled="False" Click="ButtonFindTitle_Click">
<Image Source="Images/Search.jpg" />
</Button>

Элементы управления размещаем в рамке BorderFind, для которой делаем градиентную заливку. В рамке располагаем сетку gridFind с тремя колонками и строками. Первая строка в объединенных колонках содержит текстовый блок find с текстом "Поиск". Во второй и третьей строках первой колонки размещены текстовые блоки TextBlockSurname и TextBlockTitle соответственно. Во второй колонке размещаются элементы управления для ввода информации: текстовый блок TextBoxSurname (вторая строка) и выпадающий список ComboBoxTitle (третья строка). В третьей колонке размещаются кнопки: для поиска по фамилии ButtonFindSurname (вторая строка) и для поиска по должности ButtonFindTitle (третья строка).

При загрузке страницы PageEmployee рамка BorderFind невидима, так как свойству Visibility задано значение "Hidden". При активизации команды Find из меню или панели инструментов запускается обработчик FindCommandBinding_Executed, который делает рамку ButtonFindTitle видимой ( рис. 5.17).

private void FindCommandBinding_Executed(object sender, 
ExecutedRoutedEventArgs e)
        {
            BorderFind.Visibility = System.Windows.Visibility.Visible;
        }
Страница PageEmployee с элементами управления для поиска

увеличить изображение
Рис. 5.17. Страница PageEmployee с элементами управления для поиска

Если в текстовом блоке TextBoxSurname не введена информация или в выпадающем списке ComboBoxTitle не сделан выбор, то кнопки ButtonFindSurname и ButtonFindTitle будут недоступны.

При вводе информации в текстовый блок TextBoxSurname запускается обработчик TextBoxSurname_TextChanged, который делает доступной кнопку ButtonFindSurname.

private void TextBoxSurname_TextChanged(object sender, TextChangedEventArgs e)
{
    ButtonFindSurname.IsEnabled = true;
    ButtonFindTitle.IsEnabled = false;
    ComboBoxTitle.SelectedIndex = -1;
}

При нажатии кнопки ButtonFindSurname запускается обработчик ButtonFindSurname_Click.

private void ButtonFindSurname_Click(object sender, RoutedEventArgs e)
{
    string surname = TextBoxSurname.Text;
    DataEntitiesEmployee = new TitlePresonalEntities();
    ListEmployee.Clear();
    ObjectQuery<Employee> employees = DataEntitiesEmployee.Employees;
    var queryEmployee = from employee in employees
                            where employee.Surname == surname
                            select employee;
    foreach (Employee emp in queryEmployee)
    {
        ListEmployee.Add(emp);
    }
    if (ListEmployee.Count > 0)
    {
        DataGridEmployee.ItemsSource = ListEmployee;
        ButtonFindSurname.IsEnabled = true;
        ButtonFindTitle.IsEnabled = false;
    }
    else
        MessageBox.Show("Сотрудник с фамилией \n"+surname+"\n не найдан",
             "Предупреждение", MessageBoxButton.OK, MessageBoxImage.Warning);
}

В данном обработчике события Click выполняется LINQ запрос на получение данных из базы TitlePersonal в соответствии с заданной фамилией сотрудника.

var queryEmployee = from employee in employees
                        where employee.Surname == surname
                        select employee;

При выполнении запроса по фамилии страница PageEmployee имеет вид, приведенный на рис. 5.18

Поиск по фамилии

увеличить изображение
Рис. 5.18. Поиск по фамилии

Найденные данные по сотруднику можно редактировать и удалять.

Если поиск в базе данных не привел к нахождению информации, то выдается информационное сообщение ( рис. 5.19).

Неудачный поиск по фамилии

увеличить изображение
Рис. 5.19. Неудачный поиск по фамилии

Для поиска информации из базы данных по должности сотрудников необходимо сделать выбор из выпадающего списка ComboBoxTitle. В результате выбора срабатывает обработчик ComboBoxTitle_SelectionChanged, который делает доступной кнопку ButtonFindTitle.

private void ComboBoxTitle_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    ButtonFindTitle.IsEnabled = true;
    ButtonFindSurname.IsEnabled = false;
    TextBoxSurname.Text = "";
}

При нажатии на кнопку ButtonFindTitle срабатывает обработчик ButtonFindTitle_Click.

private void ButtonFindTitle_Click(object sender, RoutedEventArgs e)
{
    DataEntitiesEmployee = new TitlePresonalEntities();
    ListEmployee.Clear();
    
    Title title = ComboBoxTitle.SelectedItem as Title;
    ObjectQuery<Employee> employees = DataEntitiesEmployee.Employees;
    var queryEmployee = from employee in employees
                        where employee.TitleID == title.ID
                        orderby employee.Surname
                        select employee;
    foreach (Employee emp in queryEmployee)
    {
        ListEmployee.Add(emp);
    }
    DataGridEmployee.ItemsSource = ListEmployee;
}

При запуске данного обработчика выполняется LINQ-запрос к базе данных TitlePersonal для выборки данных по сотрудникам, имеющим заданную должность. На рис. 5.20 приведены результаты поиска трейдеров инвестиционной компании.

Поиск сотрудников по должности

увеличить изображение
Рис. 5.20. Поиск сотрудников по должности

Для обновления выводимого списка сотрудников в приложение добавлена функция обновления, которая реализуется командой Refresh. Данная команда добавлена в коллекцию команд страницы PageEmployee.

<Page.CommandBindings>
....
        <CommandBinding Command="Refresh" Executed="RefreshCommandBinding_Executed" />
... 
    </Page.CommandBindings>

Вызов команды добавлен в меню

<MenuItem Header="Обновить" Command="Refresh"/>

и панель инструментов

<Button Name="Refresh" Margin="5,2,5,2"  Command="Refresh"
        ToolTip="обновить данные по сотрудникам">
    <Image Source="Images/Refresh.jpg" ></Image>
</Button>

Основное назначение обработчика команды RefreshCommandBinding_Executed – обновление списка ListEmployee.

private void RefreshCommandBinding_Executed(object sender, 
ExecutedRoutedEventArgs e)
{
    RewriteEmployee();
    DataGridEmployee.IsReadOnly = false;
    isDirty = false;
    SetUnvisibilityFind();
}

Команда "Обновить" обычно используется после поиска данных или ввода данных по новому сотруднику.

Ключевые термины

Модель "сущность-связь", модель EDM, концептуальная модель, тип сущности, тип ассоциации, привязка данных, проверка ввода данных, правило проверки, поиск данных.

Entity Data Model, EDM, ADO.NET, ObjectContext, ObservableCollection, ObjectQuery, Binding, ValidationRule

Краткие итоги

Рассмотрены вопросы построения EDM-модели в приложении. Выполнена привязка данных к интерфейсным элементам: текстовым, выпадающему списку, дате. Сконструирован код методов взаимодействия приложения с базой данных: редактирование, вставка, удаление данных и поиск данных. На основе пользовательских правил проиллюстриравана возможность проверки данных при их вводе.

Ресурсы для углубленного изучения

  1. Платформа ADO.NET Entity Framework // http://msdn.microsoft.com/ru-ru/library/bb399572.aspx.
  2. Привязка данных // http://msdn.microsoft.com/ru-ru/library/cc278072(v=VS.95).aspx.
  3. [ 1 ] , стр. 315 – 363.
  4. [ 4 ] , стр. 535 – 588.
  5. [ 6 ] , стр. 329 – 357, 978 – 1004.
  6. [ 8 ] , стр. 740 – 779, 832 – 866.
  7. [ 9 ] , стр. 463 – 492, 857 – 890, 1048 - 1102

Вопросы для самопроверки

  1. Объясните назначение и основные понятия EDM –модели.
  2. Какие структуры и типы данных может описывать EDM-модель?
  3. Какие основные понятия используются в модель EDM для описания структуры данных?
  4. Поясните содержание и назначение типа сущности в EDM модели.
  5. Поясните содержание и назначение типа ассоциации в EDM модели.
  6. Поясните содержание и назначение свойств в EDM модели.
  7. Как в проекте задается строка соединения с базой данных для EDM модели?
  8. Для чего необходимо в проекте иметь свойство контекста данных EDM модели?
  9. Поясните назначение и возможности коллекции типа ObservableCollection<Т>.
  10. Поясните назначение и возможности класса ObjectQuery<Т>.
  11. Поясните назначение и возможности свойства UpdateSourceTrigger, используемого при привязке данных.
  12. Поясните особенности привязки данных к колонкам таблиц типа DataGridComboBoxColumn.
  13. Поясните особенности привязки данных к колонкам таблиц с помощью шаблона DateTemplate.
  14. С помощью какого метода фиксируются проведенные изменения в источнике данных?
  15. Поясните назначение валидации данных.
  16. Каким требованиям должен соответствовать класс, используемый для валидации данных?
  17. Какими способами можно реализовать поиск и фильтрацию данных из источника данных?
Александр Петров
Александр Петров

При загрузке данных из БД возникает исключение InvalidOperationException с сообщением: Элемент коллекции должен быть пустым перед использованием ItemsSource. Знаю, что для заполнения DataGrid можно использовать коллекции Items или ItemsSource, но одновременно их использовать нельзя: если задано значение для свойства ItemsSource и в коде C# добавляется элемент в Items, возникает исключение. 
Вопрос, как отследить и отключить добавление элемента в Items?

Максим Спиридонов
Максим Спиридонов

В пятой лекции на второй странице в компиляторе выскакивает ошибка в строчке :

ObjectQuery<Employee> employees = DataEntitiesEmployee.Employees;

Ошибка CS0029

Не удается неявно преобразовать тип "System.Data.Entity.DbSet<WpfApplProject.Employee>" в "System.Data.Entity.Core.Objects.ObjectQuery<WpfApplProject.Employee>".

в using прописал все как положено, здесь похоже именно с преобразованием типов проблемы

Igor Chelyadinski
Igor Chelyadinski
Беларусь, Минск, №54, 2013
Валентина Алешина
Валентина Алешина
Россия