Пошаговое руководство по сопоставлению наследования — одна таблица на иерархию (средства для работы с моделями EDM)

В этом разделе показана реализация наследования типа «одна таблица на иерархию» путем изменения концептуальной модели в EDMX-файле. Наследование типа «одна таблица на иерархию» использует одну таблицу базы данных для сопровождения данных для всех типов сущности в иерархии наследования.

В этом пошаговом руководстве будет реализовано наследование типа «одна таблица на иерархию» путем изменения концептуальной модели, используемой в приложении CourseManager (дополнительные сведения см. в подразделе «Предварительные условия» далее в этом разделе).

В концептуальной модели CourseManager тип сущности Person имеет два свойства: HireDate и EnrollmentDate, которые могут принадлежать к новым типам сущностей (Instructor и Student соответственно), наследуемым от Person. Следующие шаги подводят итог реализации наследования типа «одна таблица на иерархию» в этом случае. Процедуры в этом пошаговом руководстве содержат более подробные сведения.

  1. Создайте два новых типа сущности: Instructor и Student.

  2. Выберите Person как базовый тип для каждого нового типа сущности.

  3. Перенесите свойство HireDate с Person на Instructor и свойство EnrollmentDate с Person на Student.

  4. Сделайте тип сущности Person абстрактным.

  5. Сопоставьте тип сущности Instructor с таблицей Person по следующим двум условиям: HireDate Is Not Null и EnrollmentDate Is Null.

  6. Сопоставьте тип сущности Student с таблицей Person по следующим двум условиям: EnrollmentDate Is Not Null и HireDate Is Null.

Предварительные требования

Для работы с этим пошаговым руководством необходимо построить приложение CourseManager. Дополнительные сведения и инструкции см. в разделе Краткое руководство по платформе Entity Framework. После сборки этого приложения необходимо реализовать наследование типа «одна таблица на иерархию», изменив его концептуальную модель и сопоставления. После этого можно будет расширить функциональность приложения, отображая посещаемость выбранного курса.

Cc716683.note(ru-ru,VS.100).gifПримечание
Приложение CourseManager используется в качестве отправной точки во многих разделах пошагового руководства в данной документации, поэтому рекомендуется использовать для данного пошагового руководства копию приложения CourseManager, а не вносить изменения в первоначальный код CourseManager.

В этом пошаговом руководстве предполагается, что читатель обладает основными навыками работы со средой Visual Studio и платформой .NET Framework, а также навыками программирования на языке Visual C# или Visual Basic.

Реализация наследования типа «одна таблица на иерархию»

В этой процедуре будет изменена модель SchoolModel путем реализации наследования типа «одна таблица на иерархию». Видеопрезентацию следующей процедуры см. в разделе Как.

Реализация наследования типа «одна таблица на иерархию»

  1. Откройте решение CourseManager в среде Visual Studio.

  2. В обозревателе решений дважды щелкните файл School.edmx.

    Файл School.edmx открывается в конструкторе модели EDM ADO.NET (в конструкторе сущностей).

  3. Щелкните правой кнопкой мыши пустую часть области конструктора сущностей, укажите Добавить и выберите пункт Сущность.

    Появится диалоговое окно Создание сущности.

  4. Введите значение Instructor в поле Имя сущности и выберите пункт Person в раскрывающемся списке Базовый тип.

  5. Нажмите кнопку ОК.

    Новый тип сущности будет создан и отобразится в области конструктора.

  6. Повторите шаги с 3-го по 5-ый, но на шаге 4 введите значение Student в поле Имя сущности.

    Были созданы два новых типа сущности Instructor и Student, которые отображаются в области конструктора. Стрелка идет от новых типов сущности к типу сущности Person; это показывает, что тип Person является базовым для новых типов сущности.

  7. Щелкните правой кнопкой мыши свойство HireDate (в разделе Скалярные свойства) типа сущности Person. Выберите команду Вырезать.

  8. Щелкните правой кнопкой мыши свойство Скалярные свойства типа сущности Instructor и выберите пункт Вставить.

  9. Щелкните правой кнопкой мыши свойство HireDate и выберите пункт Свойства.

  10. В окне Свойства установите свойства Допускает значение null значение false.

  11. Повторите шаги с 7 по 10, при этом вырежьте свойство EnrollmentDate типа сущности Person и вставьте его в тип сущности Student.

  12. Выберите тип сущности Person. В окне Свойства установите для свойства Абстрактный значение true.

    Обычно нет необходимости использовать абстрактные типы для создания модели сценариев типа «одна таблица на иерархию». Абстрактные типы используются в этом примере для демонстрации их использования в концептуальной модели.

    Cc716683.note(ru-ru,VS.100).gifПримечание
    Для оставшихся шагов этой процедуры требуется окно Сведения о сопоставлении.Если это окно не отображается, щелкните правой кнопкой мыши область конструктора и выберите пункт Сведения о сопоставлении.

  13. Выберите тип сущности Instructor и щелкните <Добавить таблицу или представление> в окне Сведения о сопоставлении.

    Поле <Добавить таблицу или представление> становится раскрывающимся списком таблиц и представлений, с которым может быть сопоставлена выбранная сущность.

  14. Выберите пункт Person из раскрывающегося списка.

    Окно Сведения о сопоставлении обновляется с учетом сопоставления столбцов по умолчанию и параметра для добавления условия.

  15. Нажмите кнопку <Добавить условие>.

    Поле <Добавить условие> становится раскрывающимся списком столбцов, для которых могут быть заданы условия.

  16. Выберите пункт HireDate из раскрывающегося списка.

    Появится другое поле <Добавить условие>.

  17. В столбце Оператор окна Сведения о сопоставлении выберите Является из раскрывающегося списка.

  18. В столбце Свойство/значение выберите Не Null.

  19. Нажмите кнопку <Добавить условие>.

  20. Выберите пункт EnrollmentDate из раскрывающегося списка.

  21. В столбце Оператор в раскрывающемся списке выберите Is.

  22. В столбце Свойство/значение выберите Null.

    Cc716683.note(ru-ru,VS.100).gifПримечание
    Если свойство/значение используется в условии, оно не может быть также свойством сущности (если только условие не использует сравнение типа IS Null или Is Not Null).

  23. Повторите шаги с 13-го по 22-ый для типа сущности Student, но укажите условия HireDate Is Null и EnrollmentDate Is Not Null.

Теперь наследование типа «одна таблица на иерархию» успешно реализовано.

Создание связи между типами сущности Instructor и OfficeAssignment

В этом разделе рассматривается замена сопоставления между типами сущностей Person и OfficeAssignment на связь между Instructor и OfficeAssignment. Такое изменение сопоставления соответствует назначению модели.

Создание сопоставления между типами сущностей Instructor и OfficeAssignment

  1. Щелкните правой кнопкой мыши сопоставление между типами сущностей Person и OfficeAssignment и выберите Удалить.

  2. Щелкните правой кнопкой мыши пустую часть области конструктора сущностей, укажите Добавить и выберите пункт Связь.

  3. Для одного конца сопоставления выберите Instructor из раскрывающегося списка Сущности, а затем выберите 1 (один) из раскрывающегося списка Кратность.

  4. Для второго конца сопоставления выберите OfficeAssignment из раскрывающегося списка Сущности, а затем выберите 0..1 (ноль или один) из раскрывающегося списка Кратность.

  5. Нажмите кнопку ОК.

  6. Щелкните правой кнопкой мыши новое сопоставление между типами сущностей Instructor и OfficeAssignment и выберите Свойства.

  7. В окне «Свойства» щелкните Справочное ограничение, а затем нажмите кнопку с многоточием (…) в столбце значений.

    Откроется диалоговое окно «Справочные ограничения».

  8. Выберите пункт Instructor из раскрывающегося списка Основной.

  9. Нажмите кнопку ОК.

Было добавлено сопоставление между типами сущностей Instructor и OfficeAssignment.

Создание пользовательского интерфейса

Затем необходимо добавить кнопку к форме CourseViewer, которая загружает и отображает форму Enrollment. После этого добавьте два элемента управления ComboBox и один элемент управления ListBox в форму Enrollment. Первый элемент управления ComboBox позволит выбрать отдел. Второй элемент управления ComboBox позволит выбрать курс в зависимости от отдела, выбранного в первом элементе управления ComboBox. Список студентов и преподавателей выбранного курса показывается в элементе управления ListBox.

Создание пользовательского интерфейса

  1. Щелкните правой кнопкой мыши имя проекта CourseManager в окне Обозреватель решений, укажите пункт Добавить и выберите пункт Новый элемент.

    Появится диалоговое окно Добавление нового элемента.

  2. Выберите пункт Форма Windows, введите «Enrollment.vb» или «Enrollment.cs» в качестве имени формы (в зависимости от используемого языка) и нажмите кнопку Добавить.

    Новая форма будет добавлена к проекту и открыта в конструкторе форм. Для имени формы установлено значение Enrollment; для текста установлено значение Enrollment.

  3. Перетащите элемент управления ComboBox из области элементов в форму и укажите значение его имени departmentList в окне Свойства.

  4. Перетащите другой элемент управления ComboBox в форму и укажите значение его имени courseList.

  5. Перетащите элемент управления Listbox из области элементов в форму. Укажите значение его имени studentList в окне Свойства.

  6. Дважды щелкните форму CourseViewer.cs или форму CourseViewer.vb в Обозревателе решений.

    Форма CourseViewer откроется в конструкторе.

  7. Перетащите элемент управления Button из области элементов в форму CourseViewer.

  8. В окне Свойства укажите значение имени кнопки viewEnrollment и укажите текст кнопки View Enrollment.

  9. Дважды нажмите кнопку viewEnrollment.

    Откроется файл с фоновым кодом для формы CourseViewer.

  10. Добавьте следующий код к обработчику события viewEnrollment_click.

    Dim enrollmentForm As New Enrollment()
    enrollmentForm.Visible = True
    
    Enrollment enrollmentForm = new Enrollment();
    enrollmentForm.Visible = true;
    

Создание пользовательского интерфейса завершено.

Выполнение запроса к концептуальной модели

В этой процедуре выполняется запрос к концептуальной модели, а результаты привязываются к элементам управления Windows Forms. Дополнительные сведения о привязке объектов к элементам управления см. в разделе Binding Objects to Controls (Entity Framework).

Запрос к концептуальной модели

  1. При открытой форме Enrollment в конструкторе форм дважды щелкните форму Enrollment.

    Откроется файл с фоновым кодом для формы Enrollment.

  2. Добавьте следующие инструкции using (C#) или Imports (Visual Basic):

    Imports System.Data.Objects
    Imports System.Data.Objects.DataClasses
    
    using System.Data.Objects;
    using System.Data.Objects.DataClasses;
    
  3. Добавьте свойство, представляющее контекст данных, к классу Enrollment.

    ' Create an ObjectContext instance based on SchoolEntity.
    Private schoolContext As SchoolEntities
    
    // Create an ObjectContext instance based on SchoolEntities.
    private SchoolEntities schoolContext;
    
  4. В обработчике события Enrollment_Load добавьте код для инициализации контекста объекта и привяжите элемент управления ComboBox к запросу, который возвращает все отделы и связанную информацию о курсе.

          ' Initialize the ObjectContext.
          schoolContext = New SchoolEntities()
    
          ' Define a query that returns all Department objects and 
          ' related Course objects, ordered by name.
          Dim departmentQuery As ObjectQuery(Of Department) = _
              schoolContext.Departments.Include("Courses") _
              .OrderBy("it.Name")
    
          ' Bind the ComboBox control to the query, which is 
          ' executed during data binding.
          Me.departmentList.DataSource = departmentQuery _
    .Execute(MergeOption.OverwriteChanges)
          Me.departmentList.DisplayMember = "Name"
    
    // Initialize the ObjectContext.
    schoolContext = new SchoolEntities();
    
    // Define a query that returns all Department objects
    // and related Course objects, ordered by name.
    ObjectQuery<Department> departmentQuery =
        schoolContext.Departments.Include("Courses")
                                .OrderBy("it.Name");
    
    // Bind the ComboBox control to the query.
    this.departmentList.DataSource = departmentQuery
        .Execute(MergeOption.OverwriteChanges);
    this.departmentList.DisplayMember = "Name";
    
  5. Вернитесь в конструктор формы Enrollment и дважды щелкните элемент управления departmentList ComboBox.

    Обработчик события departmentList_SelectedIndexChanged создан в файле с фоновым кодом.

  6. Добавьте код в обработчик события для привязки элемента управления courseList ComboBox к свойствам Course выбранного Department.

    ' Get the object for the selected department
    Dim department As Department = CType(Me.departmentList _
            .SelectedItem, Department)
    
    ' Bind the ComboBox control Course properties of
    ' the selected Department.
    courseList.DataSource = department.Courses
    courseList.DisplayMember = "Title"
    
    // Get the object for the selected department.
    Department department =
            (Department)this.departmentList.SelectedItem;
    
    // Bind the ComboBox control to the Course  
    // properties of the selected Department.
    courseList.DataSource = department.Courses;
    courseList.DisplayMember = "Title";
    
  7. Вернитесь в конструктор формы Enrollment и дважды щелкните элемент управления courseList ComboBox.

    Обработчик события courseList_SelectedIndexChanged создан в файле с фоновым кодом.

  8. Добавьте код в обработчик события для отображения списка студентов в ListBox.

    Me.studentList.Items.Clear()
    
    ' Get the CourseID from the selected Course.
    Dim course As Course = CType(Me.courseList.SelectedItem,  _
         Course)
    Dim courseId As Integer = course.CourseID
    
    ' Get all StudentGrade objects for the supplied CourseID
    Dim studentQuery As Course = schoolContext.Courses.Where _
         ("it.CourseID = @courseID", New ObjectParameter _
          ("courseID", courseId)).Include("StudentGrades"). _
          FirstOrDefault()
    
    ' Get all students for each StudentGrade
    For Each cg As StudentGrade In studentQuery.StudentGrades
        cg.PersonReference.Load()
        studentList.Items.Add(cg.Person.LastName + ", " + _
                            cg.Person.FirstName)
    Next
    
    studentList.Items.Add(" ")
    
    ' Get all Instructor types for the supplied CourseID
    Dim instructorQuery As Course = schoolContext.Courses. _
         Where("it.CourseID = @courseID", New ObjectParameter _
               ("courseID", courseId)).Include("People") _
               .FirstOrDefault()
    
    ' Display each instructor for the specified Course
    For Each Instructor As Instructor In instructorQuery.People
        Me.studentList.Items.Add("Instructor: " + Instructor. _
                        LastName + ", " + Instructor.FirstName)
    Next
    
    studentList.Items.Clear();
    
    // Get the CourseID from the selected Course.
    Course course = (Course)courseList.SelectedItem;
    int courseId = course.CourseID;
    
    // Get all StudentGrade types for the supplied CourseID
    Course studentQuery = schoolContext.Courses.Where(
        "it.CourseID = @courseID", new ObjectParameter
            ("courseID", courseId)).Include("StudentGrades").
            FirstOrDefault();
    
    // Get all students for each StudentGrade
    foreach (StudentGrade sg in studentQuery.StudentGrades)
    {
        sg.PersonReference.Load();
        studentList.Items.Add(sg.Person.LastName + ", " +
            sg.Person.FirstName);
    }
    
    studentList.Items.Add(" ");
    
    // Get all Instructor types for the supplied CourseID
    Course instructorQuery = schoolContext.Courses.Where(
        "it.CourseID = @courseID", new ObjectParameter
            ("courseID", courseId)).Include("People").
            FirstOrDefault();
    
    // Display each instructor for the specified course.
    foreach (Instructor instructor in instructorQuery.People.
        OfType<Instructor>())
    {
        studentList.Items.Add("Instructor: " + instructor.
            LastName + ", " + instructor.FirstName);
    }
    

Создание приложения завершено. Нажмите клавиши Ctrl+F5, чтобы запустить приложение. Нажмите кнопку View Enrollment, чтобы загрузить форму Enrollment. Посещаемость и список преподавателей выбранного курса показываются в ListBox.

Листинг кода

В этом разделе приводится конечная версия файла с фоновым кодом для формы Enrollment.

Imports System.Data.Objects
Imports System.Data.Objects.DataClasses

Public Class Enrollment

    ' Create an ObjectContext instance based on SchoolEntity.
    Private schoolContext As SchoolEntities

    Private Sub Enrollment_Load(ByVal sender As System.Object, _
                ByVal e As System.EventArgs) Handles MyBase.Load
        ' Initialize the ObjectContext.
        schoolContext = New SchoolEntities()

        ' Define a query that returns all Department objects and 
        ' related Course objects, ordered by name.
        Dim departmentQuery As ObjectQuery(Of Department) = _
            schoolContext.Departments.Include("Courses") _
            .OrderBy("it.Name")

        ' Bind the ComboBox control to the query, which is 
        ' executed during data binding.
        Me.departmentList.DataSource = departmentQuery _
  .Execute(MergeOption.OverwriteChanges)
        Me.departmentList.DisplayMember = "Name"
    End Sub

    Private Sub departmentList_SelectedIndexChanged(ByVal sender _
            As System.Object, ByVal e As System.EventArgs) Handles _
            departmentList.SelectedIndexChanged
        ' Get the object for the selected department
        Dim department As Department = CType(Me.departmentList _
                .SelectedItem, Department)

        ' Bind the ComboBox control Course properties of
        ' the selected Department.
        courseList.DataSource = department.Courses
        courseList.DisplayMember = "Title"
    End Sub

    Private Sub courseList_SelectedIndexChanged(ByVal sender As  _
            System.Object, ByVal e As System.EventArgs) Handles _
            courseList.SelectedIndexChanged
        Me.studentList.Items.Clear()

        ' Get the CourseID from the selected Course.
        Dim course As Course = CType(Me.courseList.SelectedItem,  _
             Course)
        Dim courseId As Integer = course.CourseID

        ' Get all StudentGrade objects for the supplied CourseID
        Dim studentQuery As Course = schoolContext.Courses.Where _
             ("it.CourseID = @courseID", New ObjectParameter _
              ("courseID", courseId)).Include("StudentGrades"). _
              FirstOrDefault()

        ' Get all students for each StudentGrade
        For Each cg As StudentGrade In studentQuery.StudentGrades
            cg.PersonReference.Load()
            studentList.Items.Add(cg.Person.LastName + ", " + _
                                cg.Person.FirstName)
        Next

        studentList.Items.Add(" ")

        ' Get all Instructor types for the supplied CourseID
        Dim instructorQuery As Course = schoolContext.Courses. _
             Where("it.CourseID = @courseID", New ObjectParameter _
                   ("courseID", courseId)).Include("People") _
                   .FirstOrDefault()

        ' Display each instructor for the specified Course
        For Each Instructor As Instructor In instructorQuery.People
            Me.studentList.Items.Add("Instructor: " + Instructor. _
                            LastName + ", " + Instructor.FirstName)
        Next
    End Sub
End Class
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.Objects;
using System.Data.Objects.DataClasses;

namespace CourseManager
{
    public partial class Enrollment : Form
    {
        // Create an ObjectContext instance based on SchoolEntities.
        private SchoolEntities schoolContext;

        public Enrollment()
        {
            InitializeComponent();
        }

        private void Enrollment_Load(object sender, EventArgs e)
        {
            // Initialize the ObjectContext.
            schoolContext = new SchoolEntities();

            // Define a query that returns all Department objects
            // and related Course objects, ordered by name.
            ObjectQuery<Department> departmentQuery =
                schoolContext.Departments.Include("Courses")
                                        .OrderBy("it.Name");

            // Bind the ComboBox control to the query.
            this.departmentList.DataSource = departmentQuery
                .Execute(MergeOption.OverwriteChanges);
            this.departmentList.DisplayMember = "Name";
        }

        private void departmentList_SelectedIndexChanged(object sender,
            EventArgs e)
        {
            // Get the object for the selected department.
            Department department =
                    (Department)this.departmentList.SelectedItem;

            // Bind the ComboBox control to the Course  
            // properties of the selected Department.
            courseList.DataSource = department.Courses;
            courseList.DisplayMember = "Title";
        }

        private void courseList_SelectedIndexChanged(object sender,
            EventArgs e)
        {
            studentList.Items.Clear();

            // Get the CourseID from the selected Course.
            Course course = (Course)courseList.SelectedItem;
            int courseId = course.CourseID;

            // Get all StudentGrade types for the supplied CourseID
            Course studentQuery = schoolContext.Courses.Where(
                "it.CourseID = @courseID", new ObjectParameter
                    ("courseID", courseId)).Include("StudentGrades").
                    FirstOrDefault();

            // Get all students for each StudentGrade
            foreach (StudentGrade sg in studentQuery.StudentGrades)
            {
                sg.PersonReference.Load();
                studentList.Items.Add(sg.Person.LastName + ", " +
                    sg.Person.FirstName);
            }

            studentList.Items.Add(" ");

            // Get all Instructor types for the supplied CourseID
            Course instructorQuery = schoolContext.Courses.Where(
                "it.CourseID = @courseID", new ObjectParameter
                    ("courseID", courseId)).Include("People").
                    FirstOrDefault();

            // Display each instructor for the specified course.
            foreach (Instructor instructor in instructorQuery.People.
                OfType<Instructor>())
            {
                studentList.Items.Add("Instructor: " + instructor.
                    LastName + ", " + instructor.FirstName);
            }
        }
    }
}

Следующие шаги

Наследование типа «одна таблица на иерархию» в концептуальной модели реализовано успешно. Дополнительные сведения о способах определения концептуальной модели с наследованием типа «одна таблица на иерархию» см. в разделе How to: Define a Model with Table-per-Hierarchy Inheritance. Дополнительные сведения о привязке приложений при помощи платформы Entity Framework см. в разделе ADO.NET Entity Framework.

См. также

Другие ресурсы

Сценарии средств работы с моделью EDM
Задачи средств модели EDM