다음을 통해 공유


Entity Framework 4.0 Database First 및 ASP.NET 4 Web Forms 시작 - 5부

작성자: Tom Dykstra

Contoso University 샘플 웹 애플리케이션은 Entity Framework 4.0 및 Visual Studio 2010을 사용하여 ASP.NET Web Forms 애플리케이션을 만드는 방법을 보여 줍니다. 자습서 시리즈에 대한 자세한 내용은 시리즈의 첫 번째 자습서를 참조하세요.

이전 자습서에서는 컨트롤을 EntityDataSource 사용하여 관련 데이터를 사용하기 시작했습니다. 탐색 속성에 여러 수준의 계층 구조와 편집된 데이터를 표시했습니다. 이 자습서에서는 관계를 추가하고 삭제하고 기존 엔터티와 관계가 있는 새 엔터티를 추가하여 관련 데이터를 계속 작업합니다.

부서에 할당된 과정을 추가하는 페이지를 만듭니다. 부서가 이미 있으며 새 과정을 만들 때 동시에 해당 부서와 기존 부서 간에 관계를 설정합니다.

ID, 제목 및 크레딧 텍스트 필드가 있는 과정 추가 보기와 부서 드롭다운을 보여 주는 인터넷 Explorer 창의 스크린샷

또한 강좌에 강사를 할당하거나(선택한 두 엔터티 간의 관계 추가) 강좌에서 강사를 제거(선택한 두 엔터티 간의 관계 제거)하여 다대다 관계와 함께 작동하는 페이지를 만듭니다. 데이터베이스에서 강사와 과정 간의 관계를 추가하면 연결 테이블에 새 행이 추가 CourseInstructor 됩니다. 관계를 제거하려면 연결 테이블에서 행 CourseInstructor 을 삭제해야 합니다. 그러나 테이블을 명시적으로 참조하지 않고 탐색 속성을 설정하여 Entity Framework에서 CourseInstructor 이 작업을 수행합니다.

강좌에 강사 할당 또는 강좌에서 제거 보기를 보여 주는 인터넷 Explorer 창의 스크린샷

기존 엔터티에 관계가 있는 엔터티 추가

Site.Master master 페이지를 사용하는 CoursesAdd.aspx라는 새 웹 페이지를 만들고 라는 컨트롤Content2에 다음 태그를 Content 추가합니다.

<h2>Add Courses</h2>
    <asp:EntityDataSource ID="CoursesEntityDataSource" runat="server" 
        ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False"
        EntitySetName="Courses" 
        EnableInsert="True" EnableDelete="True" >
    </asp:EntityDataSource>
    <asp:DetailsView ID="CoursesDetailsView" runat="server" AutoGenerateRows="False"
        DataSourceID="CoursesEntityDataSource" DataKeyNames="CourseID"
        DefaultMode="Insert" oniteminserting="CoursesDetailsView_ItemInserting">
        <Fields>
            <asp:BoundField DataField="CourseID" HeaderText="ID" />
            <asp:BoundField DataField="Title" HeaderText="Title" />
            <asp:BoundField DataField="Credits" HeaderText="Credits" />
            <asp:TemplateField HeaderText="Department">
                <InsertItemTemplate>
                    <asp:EntityDataSource ID="DepartmentsEntityDataSource" runat="server" ConnectionString="name=SchoolEntities"
                        DefaultContainerName="SchoolEntities" EnableDelete="True" EnableFlattening="False"
                        EntitySetName="Departments" EntityTypeFilter="Department">
                    </asp:EntityDataSource>
                    <asp:DropDownList ID="DepartmentsDropDownList" runat="server" DataSourceID="DepartmentsEntityDataSource"
                        DataTextField="Name" DataValueField="DepartmentID"
                        oninit="DepartmentsDropDownList_Init">
                    </asp:DropDownList>
                </InsertItemTemplate>
            </asp:TemplateField>
            <asp:CommandField ShowInsertButton="True" />
        </Fields>
    </asp:DetailsView>

이 태그는 EntityDataSource 과정을 선택하고, 삽입을 사용하도록 설정하고, 이벤트에 대한 처리기를 지정하는 컨트롤을 Inserting 만듭니다. 새 엔터티를 만들 때 Course 처리기를 사용하여 탐색 속성을 업데이트 Department 합니다.

태그는 새 Course 엔터티를 DetailsView 추가하는 데 사용할 컨트롤도 만듭니다. 태그는 엔터티 속성에 바인딩 Course 된 필드를 사용합니다. 시스템에서 생성된 ID 필드가 CourseID 아니므로 값을 입력해야 합니다. 대신 강좌를 만들 때 수동으로 지정해야 하는 과정 번호입니다.

탐색 속성은 컨트롤과 Department 함께 BoundField 사용할 수 없으므로 탐색 속성에 템플릿 필드를 사용합니다. 템플릿 필드는 부서를 선택하는 드롭다운 목록을 제공합니다. 드롭다운 목록은 를 업데이트하기 위해 탐색 속성을 직접 바인딩할 Departments 수 없으므로 가 아닌 Bind을 사용하여 Eval 설정된 엔터티에 바인딩됩니다. 외래 키를 업데이트하는 코드에서 DropDownList 사용할 컨트롤에 대한 참조를 저장할 수 있도록 컨트롤 Init 이벤트에 대한 처리기를 지정합니다 DepartmentID .

Partial 클래스 선언 바로 뒤의 CoursesAdd.aspx.cs 에서 클래스 필드를 추가하여 컨트롤에 대한 참조 DepartmentsDropDownList 를 보유합니다.

private DropDownList departmentDropDownList;

컨트롤에 대한 참조를 DepartmentsDropDownList 저장할 수 있도록 컨트롤의 Init 이벤트에 대한 처리기를 추가합니다. 이렇게 하면 사용자가 입력한 값을 가져와서 엔터티 값을 Course 업데이트 DepartmentID 하는 데 사용할 수 있습니다.

protected void DepartmentsDropDownList_Init(object sender, EventArgs e)
{
    departmentDropDownList = sender as DropDownList;
}

컨트롤의 Inserting 이벤트에 대한 DetailsView 처리기를 추가합니다.

protected void CoursesDetailsView_ItemInserting(object sender, DetailsViewInsertEventArgs e)
{
    var departmentID = Convert.ToInt32(departmentDropDownList.SelectedValue);
    e.Values["DepartmentID"] = departmentID;
}

사용자가 를 클릭하면 Insert새 레코드가 Inserting 삽입되기 전에 이벤트가 발생합니다. 처리기의 코드는 컨트롤에서 를 DepartmentIDDropDownList 가져오고 이를 사용하여 엔터티의 Course 속성에 DepartmentID 사용할 값을 설정합니다.

Entity Framework는 연결된 Department 엔터티의 탐색 속성에 Courses 이 과정을 추가하는 작업을 수행합니다. 또한 엔터티의 탐색 속성에 Department 부서를 Course 추가합니다.

페이지를 실행합니다.

ID, 제목 및 크레딧 텍스트 필드가 있는 과정 추가 보기와 부서 드롭다운을 보여 주는 인터넷 Explorer 창의 스크린샷

ID, 제목, 여러 크레딧을 입력하고 부서를 선택한 다음 삽입을 클릭합니다.

Courses.aspx 페이지를 실행하고 동일한 부서를 선택하여 새 과정을 확인합니다.

Image03

다대다 관계 작업

엔터티 집합과 People 엔터티 집합 간의 Courses 관계는 다대다 관계입니다. Course 엔터티에는 0개, 1개 이상의 관련 Person 엔터티(해당 과정을 가르치기 위해 할당된 강사를 나타내기)를 포함할 수 있는 라는 People 탐색 속성이 있습니다. 엔터티에는 Person 0개, 하나 이상의 관련 Course 엔터티(강사가 교육하도록 할당된 과정을 나타낸)를 포함할 수 있는 라는 Courses 탐색 속성이 있습니다. 한 강사는 여러 과정을 가르칠 수 있으며, 한 과정은 여러 강사가 가르칠 수 있습니다. 연습의 이 섹션에서는 관련 엔터티의 탐색 속성을 업데이트하여 및 Course 엔터티 간의 Person 관계를 추가하고 제거합니다.

Site.Master master 페이지를 사용하는 InstructorsCourses.aspx라는 Content2새 웹 페이지를 만들고 라는 컨트롤에 다음 태그를 Content 추가합니다.

<h2>Assign Instructors to Courses or Remove from Courses</h2>
    <br />
    <asp:EntityDataSource ID="InstructorsEntityDataSource" runat="server" 
        ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False" 
        EntitySetName="People"
        Where="it.HireDate is not null" Select="it.LastName + ', ' + it.FirstMidName AS Name, it.PersonID">
    </asp:EntityDataSource>
    Select an Instructor:
    <asp:DropDownList ID="InstructorsDropDownList" runat="server" DataSourceID="InstructorsEntityDataSource"
        AutoPostBack="true" DataTextField="Name" DataValueField="PersonID"
        OnSelectedIndexChanged="InstructorsDropDownList_SelectedIndexChanged" 
        OnDataBound="InstructorsDropDownList_DataBound">
    </asp:DropDownList>
    <h3>
        Assign a Course</h3>
    <br />
    Select a Course:
    <asp:DropDownList ID="UnassignedCoursesDropDownList" runat="server"
        DataTextField="Title" DataValueField="CourseID">
    </asp:DropDownList>
    <br />
    <asp:Button ID="AssignCourseButton" runat="server" Text="Assign" OnClick="AssignCourseButton_Click" />
    <br />
    <asp:Label ID="CourseAssignedLabel" runat="server" Visible="false" Text="Assignment successful"></asp:Label>
    <br />
    <h3>
        Remove a Course</h3>
    <br />
    Select a Course:
    <asp:DropDownList ID="AssignedCoursesDropDownList" runat="server"
        DataTextField="title" DataValueField="courseiD">
    </asp:DropDownList>
    <br />
    <asp:Button ID="RemoveCourseButton" runat="server" Text="Remove" OnClick="RemoveCourseButton_Click" />
    <br />
    <asp:Label ID="CourseRemovedLabel" runat="server" Visible="false" Text="Removal successful"></asp:Label>

이 태그는 EntityDataSource 강사의 엔터티 이름과 PersonIDPerson 를 검색하는 컨트롤을 만듭니다. DropDrownList 컨트롤은 컨트롤에 바인딩됩니다EntityDataSource. 컨트롤은 DropDownList 이벤트에 대한 처리기를 지정합니다 DataBound . 이 처리기를 사용하여 과정을 표시하는 두 개의 드롭다운 목록을 데이터 바인딩합니다.

태그는 선택한 강사에게 과정을 할당하는 데 사용할 다음 컨트롤 그룹도 만듭니다.

  • DropDownList 할당할 과정을 선택하기 위한 컨트롤입니다. 이 컨트롤은 현재 선택한 강사에게 할당되지 않은 과정으로 채워집니다.
  • Button 할당을 시작할 컨트롤입니다.
  • Label 할당이 실패할 경우 오류 메시지를 표시하는 컨트롤입니다.

마지막으로 태그는 선택한 강사에서 과정을 제거하는 데 사용할 컨트롤 그룹도 만듭니다.

InstructorsCourses.aspx.cs에서 using 문을 추가합니다.

using ContosoUniversity.DAL;

과정을 표시하는 두 개의 드롭다운 목록을 채우는 메서드를 추가합니다.

private void PopulateDropDownLists()
{
    using (var context = new SchoolEntities())
    {
        var allCourses = (from c in context.Courses
                          select c).ToList();

        var instructorID = Convert.ToInt32(InstructorsDropDownList.SelectedValue);
        var instructor = (from p in context.People.Include("Courses")
                          where p.PersonID == instructorID
                          select p).First();

        var assignedCourses = instructor.Courses.ToList();
        var unassignedCourses = allCourses.Except(assignedCourses.AsEnumerable()).ToList();

        UnassignedCoursesDropDownList.DataSource = unassignedCourses;
        UnassignedCoursesDropDownList.DataBind();
        UnassignedCoursesDropDownList.Visible = true;

        AssignedCoursesDropDownList.DataSource = assignedCourses;
        AssignedCoursesDropDownList.DataBind();
        AssignedCoursesDropDownList.Visible = true;
    }
}

이 코드는 엔터티 집합에서 Courses 모든 과정을 가져오고 선택한 강사에 Courses 대한 엔터티의 Person 탐색 속성에서 과정을 가져옵니다. 그런 다음 해당 강사에게 할당된 과정을 결정하고 그에 따라 드롭다운 목록을 채웁니다.

단추 이벤트에 Click 대한 Assign 처리기를 추가합니다.

protected void AssignCourseButton_Click(object sender, EventArgs e)
{
    using (var context = new SchoolEntities())
    {
        var instructorID = Convert.ToInt32(InstructorsDropDownList.SelectedValue);
        var instructor = (from p in context.People
                          where p.PersonID == instructorID
                          select p).First();
        var courseID = Convert.ToInt32(UnassignedCoursesDropDownList.SelectedValue);
        var course = (from c in context.Courses
                      where c.CourseID == courseID
                      select c).First();
        instructor.Courses.Add(course);
        try
        {
            context.SaveChanges();
            PopulateDropDownLists();
            CourseAssignedLabel.Text = "Assignment successful.";
        }
        catch (Exception)
        {
            CourseAssignedLabel.Text = "Assignment unsuccessful.";
            //Add code to log the error.
        }
        CourseAssignedLabel.Visible = true;
    }
}

이 코드는 선택한 강사의 Person 엔터티를 가져오고, 선택한 과정의 엔터티를 가져오 Course 고, 선택한 과정을 Courses 강사 엔터티의 Person 탐색 속성에 추가합니다. 그런 다음 변경 내용을 데이터베이스에 저장하고 드롭다운 목록을 다시 채워 결과를 즉시 확인할 수 있습니다.

단추 이벤트에 Click 대한 Remove 처리기를 추가합니다.

protected void RemoveCourseButton_Click(object sender, EventArgs e)
{
    using (var context = new SchoolEntities())
    {
        var instructorID = Convert.ToInt32(InstructorsDropDownList.SelectedValue);
        var instructor = (from p in context.People
                          where p.PersonID == instructorID
                          select p).First();
        var courseID = Convert.ToInt32(AssignedCoursesDropDownList.SelectedValue);
        var courses = instructor.Courses;
        var courseToRemove = new Course();
        foreach (Course c in courses)
        {
            if (c.CourseID == courseID)
            {
                courseToRemove = c;
                break;
            }
        }
        try
        {
            courses.Remove(courseToRemove);
            context.SaveChanges();
            PopulateDropDownLists();
            CourseRemovedLabel.Text = "Removal successful.";
        }
        catch (Exception)
        {
            CourseRemovedLabel.Text = "Removal unsuccessful.";
            //Add code to log the error.
        }
        CourseRemovedLabel.Visible = true;
    }
}

이 코드는 선택한 강사의 Person 엔터티를 가져오고, 선택한 과정의 엔터티를 가져오 Course 고, 엔터티의 Courses 탐색 속성에서 Person 선택한 과정을 제거합니다. 그런 다음 변경 내용을 데이터베이스에 저장하고 드롭다운 목록을 다시 채워 결과를 즉시 확인할 수 있습니다.

보고할 Page_Load 오류가 없을 때 오류 메시지가 표시되지 않도록 하는 코드를 메서드에 추가하고 강사 드롭다운 목록의 및 SelectedIndexChanged 이벤트에 대한 DataBound 처리기를 추가하여 과정 드롭다운 목록을 채웁니다.

protected void Page_Load(object sender, EventArgs e)
{
    CourseAssignedLabel.Visible = false;
    CourseRemovedLabel.Visible = false;
}

protected void InstructorsDropDownList_DataBound(object sender, EventArgs e)
{
    PopulateDropDownLists();
}

protected void InstructorsDropDownList_SelectedIndexChanged(object sender, EventArgs e)
{
    PopulateDropDownLists();
}

페이지를 실행합니다.

해당 드롭다운이 있는 강좌에 강사 할당 또는 강좌에서 제거 보기를 보여주는 인터넷 Explorer 창의 스크린샷

강사를 선택합니다. 과정 할당 드롭다운 목록에는 강사가 가르치지 않는 과정이 표시되고 과정 제거 드롭다운 목록에는 강사가 이미 할당된 과정이 표시됩니다. 과정 할당 섹션에서 강좌를 선택한 다음 할당을 클릭합니다. 코스는 과정 제거 드롭다운 목록으로 이동합니다. 과정 제거 섹션에서 과정을 선택하고 제거를 클릭합니다. 과정은 과정 할당 드롭다운 목록으로 이동합니다.

이제 관련 데이터로 작업하는 몇 가지 방법을 더 보았습니다. 다음 자습서에서는 데이터 모델에서 상속을 사용하여 애플리케이션의 유지 관리를 개선하는 방법을 알아봅니다.