Share via


연습: 매핑 상속 - 계층당 하나의 테이블

이 항목에서는 EDM(엔터티 데이터 모델)에서 개념적 모델을 변경하여 계층당 하나의 테이블 상속을 구현하는 방법을 보여 줍니다. 계층당 하나의 테이블 상속에서는 하나의 데이터베이스 테이블을 사용하여 상속 계층 구조에 있는 모든 엔터티 형식의 데이터를 유지합니다. EDM으로 상속을 구현하는 방법에 대한 자세한 내용은 Inheritance (EDM)을 참조하십시오.

이 연습에서는 CourseManager 응용 프로그램에서 사용된 EDM을 수정하여 계층당 하나의 테이블 상속을 구현합니다. 자세한 내용은 이 항목의 뒷부분에 있는 필수 구성 요소 단원을 참조하십시오.

CourseManager EDM에서 Person 엔터티 형식에는 HireDateEnrollmentDate라는 두 개의 속성이 있습니다. 두 속성은 Person에서 상속된 새 엔터티 형식(각각 InstructorStudent)에 속할 수 있습니다. 다음 단계에서는 이 경우 계층당 하나의 테이블 상속을 구현하는 방법을 요약해서 보여 줍니다. 이 연습의 절차에서 자세히 설명합니다.

  1. InstructorStudent라는 두 개의 새 엔터티 형식을 만듭니다.

  2. 새 엔터티 형식의 기본 형식을 각각 Person으로 설정합니다.

  3. PersonHireDate 속성을 Instructor로 이동하고, PersonEnrollmentDate 속성을 Student로 이동합니다.

  4. Person 엔터티 형식을 추상 형식으로 설정합니다.

  5. 두 개의 조건 HireDate Is Not NullEnrollmentDate Is Null을 사용하여 Instructor 엔터티 형식을 Person 테이블에 매핑합니다.

  6. 두 개의 조건 EnrollmentDate Is Not NullHireDate Is Null을 사용하여 Student 엔터티 형식을 Person 테이블에 매핑합니다.

필수 구성 요소

이 연습을 수행하려면 CourseManager 응용 프로그램을 빌드해야 합니다. 자세한 내용과 지침은 Entity Framework 퀵 스타트를 참조하십시오. 이 응용 프로그램을 빌드한 후 계층당 하나의 테이블 상속을 구현하여 해당 EDM을 수정합니다. 그런 다음 응용 프로그램의 기능을 확장하여 선택한 과정의 등록을 표시합니다.

Cc716683.note(ko-kr,VS.100).gif참고:
이 설명서에 있는 대부분의 연습 항목에서는 CourseManager 응용 프로그램을 시작 지점으로 사용하므로 원래 CourseManager 코드를 편집하지 않고 연습용으로 CourseManager 응용 프로그램을 복사하여 사용하는 것이 좋습니다.

이 연습에서는 독자가 Visual Studio, .NET Framework 및 Visual C# 또는 Visual Basic 프로그래밍에 대한 기본적인 지식을 가지고 있다고 가정합니다.

계층당 하나의 테이블 상속 구현

이 절차에서는 SchoolModel EDM의 개념적 부분을 변경하여 계층당 하나의 테이블 상속을 구현합니다.

계층당 하나의 테이블 상속을 구현하려면

  1. Visual Studio에서 CourseManager 솔루션을 엽니다.

  2. 솔루션 탐색기에서 School.edmx 파일을 두 번 클릭합니다.

    School.edmx 파일이 ADO.NET 엔터티 데이터 모델 디자이너(Entity Designer)에서 열립니다.

  3. Entity Designer 디자인 화면의 빈 영역을 마우스 오른쪽 단추로 클릭하고 추가를 가리킨 다음 엔터티를 클릭합니다.

    새 엔터티 대화 상자가 나타납니다.

  4. 엔터티 이름으로 Instructor를 입력하고 기본 형식 드롭다운 목록에서 Person을 선택합니다.

  5. 확인을 클릭합니다.

    새 엔터티 형식이 만들어져 디자인 화면에 표시됩니다.

  6. 3-5단계를 반복하고, 두 번째 단계에서 엔터티 이름으로 Student를 입력합니다.

    이제 두 개의 새 엔터티 형식인 InstructorStudent가 디자인 화면에 표시됩니다. 화살표가 새 엔터티 형식에서 Person 엔터티 형식을 가리킵니다. 이는 Person이 새 엔터티 형식의 기본 형식임을 나타냅니다.

  7. Person 엔터티 형식의 HireDate 속성(스칼라 속성 아래에 있음)을 마우스 오른쪽 단추로 클릭하고 잘라내기를 선택합니다.

  8. Instructor 엔터티 형식의 스칼라 속성을 마우스 오른쪽 단추로 클릭하고 붙여넣기를 선택합니다.

  9. HireDate 속성을 마우스 오른쪽 단추로 클릭하고 속성을 선택합니다.

  10. 속성 창에서 Nullable 속성을 false로 설정합니다.

  11. 7-10단계를 반복하고, Person 엔터티 형식의 EnrollmentDate 속성을 잘라내어 Student 엔터티 형식에 붙여 넣습니다.

  12. Person 엔터티 형식을 선택합니다. 속성 창에서 해당 Abstract 속성을 true로 설정합니다.

    엔터티 형식을 추상으로 정의하면 해당 형식에 대한 기존 함수 매핑이 모두 제거된다고 알리는 메시지 상자가 나타납니다. 확인을 클릭합니다.

    Cc716683.note(ko-kr,VS.100).gif참고:
    일반적인 계층당 하나의 테이블 시나리오를 모델링하기 위해 추상 형식을 사용할 필요는 없습니다. 이 예제에서 추상 형식이 사용된 것은 EDM의 추상 형식 사용을 보여 주기 위해서입니다.

    Cc716683.note(ko-kr,VS.100).gif참고:
    이 절차의 나머지 단계를 수행하려면 매핑 정보 창이 필요합니다. 이 창이 표시되지 않으면 디자인 화면을 마우스 오른쪽 단추로 클릭하고 매핑 정보를 선택합니다.

  13. Instructor 엔터티 형식을 선택하고 매핑 정보 창에서 **<테이블 또는 뷰 추가>**를 클릭합니다.

    <테이블 또는 뷰 추가> 필드는 선택한 엔터티를 매핑할 수 있는 테이블 또는 뷰의 드롭다운 목록이 됩니다.

  14. 드롭다운 목록에서 Person을 선택합니다.

    매핑 정보 창이 기본 열 매핑과 조건 추가 옵션으로 업데이트됩니다.

  15. **<조건 추가>**를 클릭합니다.

    <조건 추가> 필드는 조건이 설정될 수 있는 열의 드롭다운 목록이 됩니다.

  16. 드롭다운 목록에서 HireDate를 선택합니다.

    다른 <조건 추가> 필드가 나타납니다.

  17. 매핑 정보 창의 연산자 열에 있는 드롭다운 목록에서 Is를 선택합니다.

  18. 속성/값 열에서 Not Null을 선택합니다.

  19. **<조건 추가>**를 클릭합니다.

  20. 드롭다운 목록에서 EnrollmentDate를 선택합니다.

  21. 연산자 열의 드롭다운 목록에서 Is를 선택합니다.

  22. 속성/값 열에서 Null을 선택합니다.

    Cc716683.note(ko-kr,VS.100).gif참고:
    값/속성이 조건에 사용되면 조건에서 Is Null 또는 Is Not Null 비교를 사용하지 않을 경우 해당 값/속성은 엔터티 속성이 될 수 없습니다.

  23. Student 엔터티 형식에 대해 13-22단계를 반복하고, 조건 HireDate Is NullEnrollmentDate Is Not Null을 만듭니다.

이제 계층당 하나의 테이블 상속이 구현되었습니다.

사용자 인터페이스 생성

다음에는 Enrollment 폼을 로드 및 표시하는 단추를 CourseViewer 폼에 추가합니다. 그런 후에 ComboBox 컨트롤 두 개와 ListBox 컨트롤 한 개를 Enrollment 폼에 추가합니다. 첫 번째 ComboBox를 사용하여 부서를 선택할 수 있습니다. 두 번째 ComboBox에서는 첫 번째 ComboBox에서 선택한 부서를 기반으로 과정을 선택할 수 있습니다. 선택한 과정의 학생 및 강사 목록이 ListBox 컨트롤에 표시됩니다.

사용자 인터페이스를 생성하려면

  1. 솔루션 탐색기에서 CourseManager 프로젝트를 마우스 오른쪽 단추로 클릭하고 추가를 가리킨 다음 새 항목을 선택합니다.

    새 항목 추가 대화 상자가 나타납니다.

  2. Windows Form을 선택하고 폼의 이름을 사용하는 언어에 따라 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;
    

이제 사용자 인터페이스가 완료되었습니다.

EDM 쿼리

이 절차에서는 EDM을 쿼리하고 그 결과를 Windows Forms 컨트롤에 바인딩합니다. 개체를 컨트롤에 바인딩하는 방법에 대한 자세한 내용은 Binding Objects to Controls (Entity Framework)을 참조하십시오.

EDM을 쿼리하려면

  1. 폼 디자이너에 Enrollment 폼이 열려 있는 상태로 Enrollment 폼을 두 번 클릭합니다.

    Enrollment 폼의 코드 숨김 파일이 열립니다.

  2. EDM 네임스페이스를 참조하는 다음 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 폼의 디자인 뷰로 돌아가서 departmentListComboBox 컨트롤을 두 번 클릭합니다.

    departmentList_SelectedIndexChanged 이벤트 처리기가 코드 숨김 파일에 만들어집니다.

  6. 선택한 DepartmentCourse 속성에 courseListComboBox 컨트롤을 바인딩하는 코드를 이벤트 처리기에 추가합니다.

    ' 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 폼의 디자인 뷰로 돌아가서 courseListComboBox 컨트롤을 두 번 클릭합니다.

    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를 누릅니다. Enrollment 폼을 로드하려면 View 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);
            }
        }
    }
}

다음 단계

EDM에서 계층당 하나의 테이블 상속을 성공적으로 구현했습니다. 계층당 하나의 테이블 상속을 사용하여 EDM을 정의하는 방법에 대한 자세한 내용은 How to: Define a Model with Table-per-Hierarchy Inheritance를 참조하십시오. Entity Framework를 사용하는 응용 프로그램을 빌드하는 방법에 대한 자세한 내용은 Programming Guide (Entity Framework)를 참조하십시오.

참고 항목

기타 리소스

ADO.NET 엔터티 데이터 모델 디자이너 시나리오
엔터티 데이터 모델 도구 작업