ASP.NET MVC 애플리케이션에서 Entity Framework를 사용하여 관련 데이터 업데이트(10개 중 6개)
작성자: Tom Dykstra
Contoso University 샘플 웹 애플리케이션은 Entity Framework 5 Code First 및 Visual Studio 2012를 사용하여 ASP.NET MVC 4 애플리케이션을 만드는 방법을 보여 줍니다. 자습서 시리즈에 대한 정보는 시리즈의 첫 번째 자습서를 참조하세요.
참고 항목
해결할 수 없는 문제가 발생하면 완료된 장을 다운로드하고 문제를 재현해 보세요. 일반적으로 코드를 완료된 코드와 비교하여 문제에 대한 솔루션을 찾을 수 있습니다. 몇 가지 일반적인 오류 및 해결 방법은 오류 및 해결 방법을 참조 하세요.
이전 자습서에서는 관련 데이터를 표시했습니다. 이 자습서에서는 관련 데이터를 업데이트합니다. 대부분의 관계에서는 적절한 외래 키 필드를 업데이트하여 이 작업을 수행할 수 있습니다. 다 대 다 관계의 경우 Entity Framework는 조인 테이블을 직접 노출하지 않으므로 적절한 탐색 속성에서 엔터티를 명시적으로 추가 및 제거해야 합니다.
다음 그림에서는 사용할 페이지를 보여 줍니다.
강좌에 대한 만들기 및 편집 페이지 사용자 지정
새 강좌 엔터티가 만들어질 때 기존 부서에 대한 관계가 있어야 합니다. 이를 수행하기 위해 스캐폴드 코드는 컨트롤러 메서드 및 부서를 선택하기 위한 드롭다운 목록을 포함하는 만들기 및 편집 보기를 포함합니다. 드롭다운 목록은 Course.DepartmentID
외래 키 속성을 설정하고, 이는 적절한 Department
엔터티로 Department
탐색 속성을 로드하기 위해 필요한 모든 Entity Framework입니다. 스캐폴드 코드를 사용하지만 오류 처리를 추가하고 드롭다운 목록을 정렬하도록 약간 변경합니다.
CourseController.cs 4 Edit
개와 Create
메서드를 삭제하고 다음 코드로 바꿉다.
public ActionResult Create()
{
PopulateDepartmentsDropDownList();
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(
[Bind(Include = "CourseID,Title,Credits,DepartmentID")]
Course course)
{
try
{
if (ModelState.IsValid)
{
db.Courses.Add(course);
db.SaveChanges();
return RedirectToAction("Index");
}
}
catch (DataException /* dex */)
{
//Log the error (uncomment dex variable name after DataException and add a line here to write a log.)
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
}
PopulateDepartmentsDropDownList(course.DepartmentID);
return View(course);
}
public ActionResult Edit(int id)
{
Course course = db.Courses.Find(id);
PopulateDepartmentsDropDownList(course.DepartmentID);
return View(course);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(
[Bind(Include = "CourseID,Title,Credits,DepartmentID")]
Course course)
{
try
{
if (ModelState.IsValid)
{
db.Entry(course).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
}
catch (DataException /* dex */)
{
//Log the error (uncomment dex variable name after DataException and add a line here to write a log.)
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
}
PopulateDepartmentsDropDownList(course.DepartmentID);
return View(course);
}
private void PopulateDepartmentsDropDownList(object selectedDepartment = null)
{
var departmentsQuery = from d in db.Departments
orderby d.Name
select d;
ViewBag.DepartmentID = new SelectList(departmentsQuery, "DepartmentID", "Name", selectedDepartment);
}
메서드는 PopulateDepartmentsDropDownList
이름으로 정렬된 모든 부서의 목록을 가져오고, 드롭다운 목록에 대한 컬렉션을 만들고 SelectList
, 컬렉션을 속성의 보기에 ViewBag
전달합니다. 메서드는 호출 코드가 드롭다운 목록이 렌더링될 때 선택될 항목을 지정하도록 허용하는 선택적 selectedDepartment
매개 변수를 허용합니다. 보기는 도우미에게 DropDownList
이름을 DepartmentID
전달하고 도우미는 명명DepartmentID
된 개체 SelectList
를 ViewBag
찾는 것을 알고 있습니다.
이 메서드는 HttpGet
Create
선택한 항목을 설정하지 않고 메서드를 호출 PopulateDepartmentsDropDownList
합니다. 새 과정의 경우 부서가 아직 설정되지 않았기 때문입니다.
public ActionResult Create()
{
PopulateDepartmentsDropDownList();
return View();
}
이 메서드는 HttpGet
Edit
편집 중인 과정에 이미 할당된 부서의 ID에 따라 선택한 항목을 설정합니다.
public ActionResult Edit(int id)
{
Course course = db.Courses.Find(id);
PopulateDepartmentsDropDownList(course.DepartmentID);
return View(course);
}
HttpPost
둘 다 Create
에 대한 메서드와 Edit
선택한 항목이 오류 발생 후 페이지를 다시 표시할 때 설정하는 코드도 포함됩니다.
catch (DataException /* dex */)
{
//Log the error (uncomment dex variable name after DataException and add a line here to write a log.)
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
}
PopulateDepartmentsDropDownList(course.DepartmentID);
return View(course);
이 코드는 페이지가 다시 표시되어 오류 메시지를 표시할 때 선택한 부서가 선택된 상태로 유지되도록 합니다.
Views\Course\Create.cshtml에서 강조 표시된 코드를 추가하여 제목 필드 앞에 새 과정 번호 필드를 만듭니다. 이전 자습서에서 설명한 것처럼 기본 키 필드는 기본적으로 스캐폴드되지 않지만 이 기본 키는 의미가 있으므로 사용자가 키 값을 입력할 수 있도록 합니다.
@model ContosoUniversity.Models.Course
@{
ViewBag.Title = "Create";
}
<h2>Create</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
<fieldset>
<legend>Course</legend>
<div class="editor-label">
@Html.LabelFor(model => model.CourseID)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.CourseID)
@Html.ValidationMessageFor(model => model.CourseID)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Title)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Title)
@Html.ValidationMessageFor(model => model.Title)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Credits)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Credits)
@Html.ValidationMessageFor(model => model.Credits)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.DepartmentID, "Department")
</div>
<div class="editor-field">
@Html.DropDownList("DepartmentID", String.Empty)
@Html.ValidationMessageFor(model => model.DepartmentID)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
Views\Course\Edit.cshtml, Views\Course\Delete.cshtml 및 Views\Course\Details.cshtml에서 제목 필드 앞에 강좌 번호 필드를 추가합니다. 기본 키이므로 표시되지만 변경할 수는 없습니다.
<div class="editor-label">
@Html.LabelFor(model => model.CourseID)
</div>
<div class="editor-field">
@Html.DisplayFor(model => model.CourseID)
</div>
만들기 페이지(강좌 인덱스 페이지 표시 및 새로 만들기 클릭)를 실행하고 새 과정에 대한 데이터를 입력합니다.
만들기를 클릭합니다. 강좌 인덱스 페이지가 목록에 추가된 새 과정과 함께 표시됩니다. 인덱스 페이지 목록의 부서 이름은 관계가 올바르게 설정되었음을 표시하는 탐색 속성에서 제공됩니다.
편집 페이지를 실행합니다(강좌 인덱스 페이지를 표시하고 강좌에서 편집 클릭).
페이지에서 데이터를 변경하고 저장을 클릭합니다. 강좌 인덱스 페이지는 업데이트된 과정 데이터와 함께 표시됩니다.
강사용 편집 페이지 추가
강사 레코드를 편집할 때 강사의 사무실 할당을 업데이트할 수 있습니다. Instructor
엔터티는 엔터티와 일대일 관계를 맺 OfficeAssignment
습니다. 즉, 다음과 같은 상황을 처리해야 합니다.
- 사용자가 사무실 할당을 지우고 원래 값이 있는 경우 엔터티를
OfficeAssignment
제거하고 삭제해야 합니다. - 사용자가 사무실 할당 값을 입력하고 원래 비어 있는 경우 새
OfficeAssignment
엔터티를 만들어야 합니다. - 사용자가 사무실 할당 값을 변경하는 경우 기존
OfficeAssignment
엔터티의 값을 변경해야 합니다.
InstructorController.cs 열고 메서드를 확인합니다 HttpGet
Edit
.
public ActionResult Edit(int id = 0)
{
Instructor instructor = db.Instructors.Find(id);
if (instructor == null)
{
return HttpNotFound();
}
ViewBag.InstructorID = new SelectList(db.OfficeAssignments, "InstructorID", "Location", instructor.InstructorID);
return View(instructor);
}
여기서 스캐폴드된 코드는 원하는 코드가 아닙니다. 드롭다운 목록에 대한 데이터를 설정하지만 텍스트 상자가 필요합니다. 이 메서드를 다음 코드로 바꿉다.
public ActionResult Edit(int id)
{
Instructor instructor = db.Instructors
.Include(i => i.OfficeAssignment)
.Where(i => i.InstructorID == id)
.Single();
return View(instructor);
}
이 코드는 ViewBag
문을 삭제하고 연결된 OfficeAssignment
엔터티에 대한 즉시 로드를 추가합니다. 메서드를 Find
사용하여 즉시 로드를 수행할 수 없으므로 강사를 Where
선택하는 대신 메서드와 Single
메서드를 사용합니다.
메서드를 HttpPost
Edit
다음 코드로 바꿉다. Office 할당 업데이트를 처리하는 다음을 수행합니다.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(int id, FormCollection formCollection)
{
var instructorToUpdate = db.Instructors
.Include(i => i.OfficeAssignment)
.Where(i => i.InstructorID == id)
.Single();
if (TryUpdateModel(instructorToUpdate, "",
new string[] { "LastName", "FirstMidName", "HireDate", "OfficeAssignment" }))
{
try
{
if (String.IsNullOrWhiteSpace(instructorToUpdate.OfficeAssignment.Location))
{
instructorToUpdate.OfficeAssignment = null;
}
db.Entry(instructorToUpdate).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
catch (DataException /* dex */)
{
//Log the error (uncomment dex variable name after DataException and add a line here to write a log.
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
}
}
ViewBag.InstructorID = new SelectList(db.OfficeAssignments, "InstructorID", "Location", id);
return View(instructorToUpdate);
}
코드는 다음을 수행합니다.
OfficeAssignment
탐색 속성에 대한 즉시 로드를 사용하여 데이터베이스에서 현재Instructor
엔터티를 가져옵니다. 이는 메서드에서 수행된 작업과HttpGet
Edit
동일합니다.모델 바인더의 값으로 검색된
Instructor
엔터티를 업데이트합니다. 사용된 TryUpdateModel 오버로드를 사용하면 포함하려는 속성을 허용 목록에 추가할 수 있습니다. 이렇게 하면 두 번째 자습서에 설명된 대로 초과 게시를 방지합니다.if (TryUpdateModel(instructorToUpdate, "", new string[] { "LastName", "FirstMidName", "HireDate", "OfficeAssignment" }))
사무실 위치가 비어 있는 경우
OfficeAssignment
테이블의 관련된 행이 삭제되도록Instructor.OfficeAssignment
속성을 Null로 설정합니다.if (String.IsNullOrWhiteSpace(instructorToUpdate.OfficeAssignment.Location)) { instructorToUpdate.OfficeAssignment = null; }
변경 내용을 데이터베이스에 저장합니다.
Views\Instructor\Edit.cshtml에서 고용 날짜 필드의 div
요소 뒤의 사무실 위치를 편집하기 위한 새 필드를 추가합니다.
<div class="editor-label">
@Html.LabelFor(model => model.OfficeAssignment.Location)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.OfficeAssignment.Location)
@Html.ValidationMessageFor(model => model.OfficeAssignment.Location)
</div>
페이지를 실행합니다(강사 탭을 선택한 다음 강사에서 편집 클릭). 사무실 위치를 변경하고 저장을 클릭합니다.
강사 편집 페이지에 과정 과제 추가
강사는 강좌 수에 관계 없이 가르칠 수 있습니다. 이제 다음 스크린샷에 표시된 것처럼 확인란 그룹을 사용하여 강좌 할당을 변경하는 기능을 추가하여 강사 편집 페이지를 향상시킵니다.
엔터티와 Instructor
엔터티 간의 Course
관계는 다대다 관계이므로 조인 테이블에 직접 액세스할 수 없습니다. 대신 탐색 속성에서 엔터티를 Instructor.Courses
추가하고 제거합니다.
강사에게 할당된 강좌를 변경할 수 있도록 하는 UI는 확인란의 그룹입니다. 데이터베이스의 모든 강좌에 대한 확인란이 표시되고 강사에게 현재 할당되어 있는 것이 선택됩니다. 사용자는 확인란을 선택하거나 선택 취소하여 강좌 할당을 변경할 수 있습니다. 과정 수가 훨씬 많은 경우 뷰에서 데이터를 표시하는 다른 방법을 사용하려고 하지만 관계를 만들거나 삭제하기 위해 탐색 속성을 조작하는 동일한 방법을 사용합니다.
확인란의 목록에 대한 보기에 데이터를 제공하려면 보기 모델 클래스를 사용합니다. ViewModels 폴더에서 AssignedCourseData.cs 만들고 기존 코드를 다음 코드로 바꿉니다.
namespace ContosoUniversity.ViewModels
{
public class AssignedCourseData
{
public int CourseID { get; set; }
public string Title { get; set; }
public bool Assigned { get; set; }
}
}
InstructorController.cs 메서드를 HttpGet
Edit
다음 코드로 바꿉다. 변경 내용은 강조 표시되어 있습니다.
public ActionResult Edit(int id)
{
Instructor instructor = db.Instructors
.Include(i => i.OfficeAssignment)
.Include(i => i.Courses)
.Where(i => i.InstructorID == id)
.Single();
PopulateAssignedCourseData(instructor);
return View(instructor);
}
private void PopulateAssignedCourseData(Instructor instructor)
{
var allCourses = db.Courses;
var instructorCourses = new HashSet<int>(instructor.Courses.Select(c => c.CourseID));
var viewModel = new List<AssignedCourseData>();
foreach (var course in allCourses)
{
viewModel.Add(new AssignedCourseData
{
CourseID = course.CourseID,
Title = course.Title,
Assigned = instructorCourses.Contains(course.CourseID)
});
}
ViewBag.Courses = viewModel;
}
코드는 Courses
탐색 속성에 대해 즉시 로드를 추가하고 새 PopulateAssignedCourseData
메서드를 호출하여 AssignedCourseData
보기 모델 클래스를 사용하여 확인란 배열에 대한 정보를 제공합니다.
PopulateAssignedCourseData
메서드의 코드는 보기 모델 클래스를 사용하는 강좌의 목록을 로드하기 위해 모든 Course
엔터티를 통해 읽습니다. 각 강좌의 경우 코드는 강좌가 강사의 Courses
탐색 속성에 있는지 여부를 확인합니다. 강사에게 강좌가 할당되었는지 여부를 확인할 때 효율적인 조회를 만들기 위해 강사에게 할당된 과정은 HashSet 컬렉션에 배치됩니다. 이 Assigned
속성은 강사가 true
할당된 과정에 대해 설정됩니다. 보기는 이 속성을 사용하여 선택된 것으로 표시되어야 하는 확인란을 결정합니다. 마지막으로 목록이 속성의 뷰에 ViewBag
전달됩니다.
다음으로 사용자가 저장을 클릭할 때 실행되는 코드를 추가합니다. 엔터티의 HttpPost
Edit
탐색 속성을 업데이트하는 새 메서드를 호출하는 다음 코드로 메서드를 Instructor
바꿉니다Courses
. 변경 내용은 강조 표시되어 있습니다.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(int id, FormCollection formCollection, string[] selectedCourses)
{
var instructorToUpdate = db.Instructors
.Include(i => i.OfficeAssignment)
.Include(i => i.Courses)
.Where(i => i.InstructorID == id)
.Single();
if (TryUpdateModel(instructorToUpdate, "",
new string[] { "LastName", "FirstMidName", "HireDate", "OfficeAssignment" }))
{
try
{
if (String.IsNullOrWhiteSpace(instructorToUpdate.OfficeAssignment.Location))
{
instructorToUpdate.OfficeAssignment = null;
}
UpdateInstructorCourses(selectedCourses, instructorToUpdate);
db.Entry(instructorToUpdate).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
catch (DataException /* dex */)
{
//Log the error (uncomment dex variable name after DataException and add a line here to write a log.
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
}
}
PopulateAssignedCourseData(instructorToUpdate);
return View(instructorToUpdate);
}
private void UpdateInstructorCourses(string[] selectedCourses, Instructor instructorToUpdate)
{
if (selectedCourses == null)
{
instructorToUpdate.Courses = new List<Course>();
return;
}
var selectedCoursesHS = new HashSet<string>(selectedCourses);
var instructorCourses = new HashSet<int>
(instructorToUpdate.Courses.Select(c => c.CourseID));
foreach (var course in db.Courses)
{
if (selectedCoursesHS.Contains(course.CourseID.ToString()))
{
if (!instructorCourses.Contains(course.CourseID))
{
instructorToUpdate.Courses.Add(course);
}
}
else
{
if (instructorCourses.Contains(course.CourseID))
{
instructorToUpdate.Courses.Remove(course);
}
}
}
}
뷰에 엔터티 컬렉션 Course
이 없으므로 모델 바인더는 탐색 속성을 자동으로 업데이트할 Courses
수 없습니다. 모델 바인더를 사용하여 Courses 탐색 속성을 업데이트하는 대신 새 UpdateInstructorCourses
메서드에서 이 작업을 수행합니다. 따라서 모델 바인딩에서 Courses
속성을 제외해야 합니다. 허용 목록 오버로드 Courses
를 사용하고 포함 목록에 없기 때문에 TryUpdateModel을 호출하는 코드를 변경할 필요가 없습니다.
확인란을 선택하지 않은 경우 코드는 UpdateInstructorCourses
빈 컬렉션을 사용하여 Courses
탐색 속성을 초기화합니다.
if (selectedCourses == null)
{
instructorToUpdate.Courses = new List<Course>();
return;
}
그런 다음, 코드는 데이터베이스의 모든 강좌를 반복하고 현재 강사에게 할당된 것과 보기에서 선택되었던 것에 대해 각 강좌를 확인합니다. 효율적인 조회를 수행하기 위해 후자의 두 컬렉션은 HashSet
개체에 저장됩니다.
강좌에 대한 확인란이 선택됐지만 강좌가 Instructor.Courses
탐색 속성에 없는 경우 강좌는 탐색 속성의 컬렉션에 추가됩니다.
if (selectedCoursesHS.Contains(course.CourseID.ToString()))
{
if (!instructorCourses.Contains(course.CourseID))
{
instructorToUpdate.Courses.Add(course);
}
}
강좌에 대한 확인란이 선택되지 않았지만 강좌가 Instructor.Courses
탐색 속성에 있는 경우 강좌는 탐색 속성에서 제거됩니다.
else
{
if (instructorCourses.Contains(course.CourseID))
{
instructorToUpdate.Courses.Remove(course);
}
}
Views\Instructor\Edit.cshtml에서 필드의 요소 OfficeAssignment
바로 다음에 div
다음 강조 표시된 코드를 추가하여 확인란 배열이 있는 강좌 필드를 추가합니다.
@model ContosoUniversity.Models.Instructor
@{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
<fieldset>
<legend>Instructor</legend>
@Html.HiddenFor(model => model.InstructorID)
<div class="editor-label">
@Html.LabelFor(model => model.LastName)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.LastName)
@Html.ValidationMessageFor(model => model.LastName)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.FirstMidName)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.FirstMidName)
@Html.ValidationMessageFor(model => model.FirstMidName)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.HireDate)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.HireDate)
@Html.ValidationMessageFor(model => model.HireDate)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.OfficeAssignment.Location)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.OfficeAssignment.Location)
@Html.ValidationMessageFor(model => model.OfficeAssignment.Location)
</div>
<div class="editor-field">
<table>
<tr>
@{
int cnt = 0;
List<ContosoUniversity.ViewModels.AssignedCourseData> courses = ViewBag.Courses;
foreach (var course in courses) {
if (cnt++ % 3 == 0) {
@: </tr> <tr>
}
@: <td>
<input type="checkbox"
name="selectedCourses"
value="@course.CourseID"
@(Html.Raw(course.Assigned ? "checked=\"checked\"" : "")) />
@course.CourseID @: @course.Title
@:</td>
}
@: </tr>
}
</table>
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
이 코드는 세 개의 열이 있는 HTML 테이블을 만듭니다. 각 열은 강좌 번호 및 제목으로 구성된 캡션이 뒤에 오는 확인란입니다. 확인란은 모두 동일한 이름("selectedCourses")을 가지며, 이는 모델 바인더가 그룹으로 처리되어야 함을 알려줍니다. 각 확인란의 특성은 value
페이지가 게시될 때의 CourseID.
값으로 설정되며, 모델 바인더는 선택한 확인란에 CourseID
대한 값으로 구성된 컨트롤러에 배열을 전달합니다.
확인란이 처음 렌더링될 때 강사에게 할당된 과정에 대한 확인란에는 checked
해당 확인란을 선택하는 특성이 있습니다(선택된 것으로 표시됨).
과정 과제를 변경한 후에는 사이트가 페이지로 돌아올 Index
때 변경 내용을 확인할 수 있습니다. 따라서 해당 페이지의 테이블에 열을 추가해야 합니다. 이 경우 표시하려는 정보가 모델로 페이지에 전달하는 엔터티의 Instructor
탐색 속성에 Courses
이미 있으므로 개체를 사용할 ViewBag
필요가 없습니다.
Views\Instructor\Index.cshtml에서 다음 예제와 같이 Office 제목 바로 다음에 강좌 제목을 추가합니다.
<tr>
<th></th>
<th>Last Name</th>
<th>First Name</th>
<th>Hire Date</th>
<th>Office</th>
<th>Courses</th>
</tr>
그런 다음 사무실 위치 세부 정보 셀 바로 다음에 새 세부 정보 셀을 추가합니다.
@model ContosoUniversity.ViewModels.InstructorIndexData
@{
ViewBag.Title = "Instructors";
}
<h2>Instructors</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th></th>
<th>Last Name</th>
<th>First Name</th>
<th>Hire Date</th>
<th>Office</th>
<th>Courses</th>
</tr>
@foreach (var item in Model.Instructors)
{
string selectedRow = "";
if (item.InstructorID == ViewBag.InstructorID)
{
selectedRow = "selectedrow";
}
<tr class="@selectedRow" valign="top">
<td>
@Html.ActionLink("Select", "Index", new { id = item.InstructorID }) |
@Html.ActionLink("Edit", "Edit", new { id = item.InstructorID }) |
@Html.ActionLink("Details", "Details", new { id = item.InstructorID }) |
@Html.ActionLink("Delete", "Delete", new { id = item.InstructorID })
</td>
<td>
@item.LastName
</td>
<td>
@item.FirstMidName
</td>
<td>
@String.Format("{0:d}", item.HireDate)
</td>
<td>
@if (item.OfficeAssignment != null)
{
@item.OfficeAssignment.Location
}
</td>
<td>
@{
foreach (var course in item.Courses)
{
@course.CourseID @: @course.Title <br />
}
}
</td>
</tr>
}
</table>
@if (Model.Courses != null)
{
<h3>Courses Taught by Selected Instructor</h3>
<table>
<tr>
<th></th>
<th>ID</th>
<th>Title</th>
<th>Department</th>
</tr>
@foreach (var item in Model.Courses)
{
string selectedRow = "";
if (item.CourseID == ViewBag.CourseID)
{
selectedRow = "selectedrow";
}
<tr class="@selectedRow">
<td>
@Html.ActionLink("Select", "Index", new { courseID = item.CourseID })
</td>
<td>
@item.CourseID
</td>
<td>
@item.Title
</td>
<td>
@item.Department.Name
</td>
</tr>
}
</table>
}
@if (Model.Enrollments != null)
{
<h3>Students Enrolled in Selected Course</h3>
<table>
<tr>
<th>Name</th>
<th>Grade</th>
</tr>
@foreach (var item in Model.Enrollments)
{
<tr>
<td>
@item.Student.FullName
</td>
<td>
@Html.DisplayFor(modelItem => item.Grade)
</td>
</tr>
}
</table>
}
강사 인 덱스 페이지를 실행하여 각 강사에게 할당된 과정을 확인합니다.
강사에서 편집을 클릭하여 편집 페이지를 확인합니다.
일부 과정 과제를 변경하고 저장을 클릭합니다. 변경 내용은 인덱스 페이지에 반영됩니다.
참고: 제한된 수의 강좌가 있는 경우 강사 과정 데이터를 편집하기 위해 수행되는 접근 방식이 잘 작동합니다. 훨씬 큰 컬렉션의 경우 다른 UI 및 다른 업데이트 메서드가 필요합니다.
Delete 메서드 업데이트
강사가 삭제될 때 사무실 할당 레코드(있는 경우)가 삭제되도록 HttpPost Delete 메서드의 코드를 변경합니다.
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
Instructor instructor = db.Instructors
.Include(i => i.OfficeAssignment)
.Where(i => i.InstructorID == id)
.Single();
instructor.OfficeAssignment = null;
db.Instructors.Remove(instructor);
db.SaveChanges();
return RedirectToAction("Index");
}
관리자 권한으로 부서에 할당된 강사를 삭제하려고 하면 참조 무결성 오류가 발생합니다. 강사가 관리자로 할당된 모든 부서에서 강사를 자동으로 제거하는 추가 코드는 이 자습서의 현재 버전을 참조하세요.
요약
이제 관련 데이터 작업에 대한 이 소개를 완료했습니다. 지금까지 이러한 자습서에서는 전체 CRUD 작업을 수행했지만 동시성 문제는 처리하지 않았습니다. 다음 자습서에서는 동시성 항목을 소개하고, 처리 옵션을 설명하고, 한 엔터티 형식에 대해 이미 작성한 CRUD 코드에 동시성 처리를 추가합니다.
다른 Entity Framework 리소스에 대한 링크는 이 시리즈의 마지막 자습서 끝에 있습니다.