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
사용하여 관련 데이터를 사용하기 시작했습니다. 탐색 속성에 여러 수준의 계층 구조와 편집된 데이터를 표시했습니다. 이 자습서에서는 관계를 추가하고 삭제하고 기존 엔터티와 관계가 있는 새 엔터티를 추가하여 관련 데이터를 계속 작업합니다.
부서에 할당된 과정을 추가하는 페이지를 만듭니다. 부서가 이미 있으며 새 과정을 만들 때 동시에 해당 부서와 기존 부서 간에 관계를 설정합니다.
또한 강좌에 강사를 할당하거나(선택한 두 엔터티 간의 관계 추가) 강좌에서 강사를 제거(선택한 두 엔터티 간의 관계 제거)하여 다대다 관계와 함께 작동하는 페이지를 만듭니다. 데이터베이스에서 강사와 과정 간의 관계를 추가하면 연결 테이블에 새 행이 추가 CourseInstructor
됩니다. 관계를 제거하려면 연결 테이블에서 행 CourseInstructor
을 삭제해야 합니다. 그러나 테이블을 명시적으로 참조하지 않고 탐색 속성을 설정하여 Entity Framework에서 CourseInstructor
이 작업을 수행합니다.
기존 엔터티에 관계가 있는 엔터티 추가
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
삽입되기 전에 이벤트가 발생합니다. 처리기의 코드는 컨트롤에서 를 DepartmentID
DropDownList
가져오고 이를 사용하여 엔터티의 Course
속성에 DepartmentID
사용할 값을 설정합니다.
Entity Framework는 연결된 Department
엔터티의 탐색 속성에 Courses
이 과정을 추가하는 작업을 수행합니다. 또한 엔터티의 탐색 속성에 Department
부서를 Course
추가합니다.
페이지를 실행합니다.
ID, 제목, 여러 크레딧을 입력하고 부서를 선택한 다음 삽입을 클릭합니다.
Courses.aspx 페이지를 실행하고 동일한 부서를 선택하여 새 과정을 확인합니다.
다대다 관계 작업
엔터티 집합과 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
강사의 엔터티 이름과 PersonID
Person
를 검색하는 컨트롤을 만듭니다. 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();
}
페이지를 실행합니다.
강사를 선택합니다. 과정 할당 드롭다운 목록에는 강사가 가르치지 않는 과정이 표시되고 과정 제거 드롭다운 목록에는 강사가 이미 할당된 과정이 표시됩니다. 과정 할당 섹션에서 강좌를 선택한 다음 할당을 클릭합니다. 코스는 과정 제거 드롭다운 목록으로 이동합니다. 과정 제거 섹션에서 과정을 선택하고 제거를 클릭합니다. 과정은 과정 할당 드롭다운 목록으로 이동합니다.
이제 관련 데이터로 작업하는 몇 가지 방법을 더 보았습니다. 다음 자습서에서는 데이터 모델에서 상속을 사용하여 애플리케이션의 유지 관리를 개선하는 방법을 알아봅니다.