ASP.NET MVC 애플리케이션에서 Entity Framework를 사용하여 관련 데이터 업데이트(10개 중 6개)
작성자 : Tom Dykstra
Contoso University 샘플 웹 애플리케이션은 Entity Framework 5 Code First 및 Visual Studio 2012를 사용하여 ASP.NET MVC 4 애플리케이션을 만드는 방법을 보여 줍니다. 자습서 시리즈에 대한 정보는 시리즈의 첫 번째 자습서를 참조하세요.
참고
resolve 수 없는 문제가 발생하면 완료된 장을 다운로드하고 문제를 재현해 보세요. 일반적으로 코드를 완료된 코드와 비교하여 문제에 대한 해결 방법을 찾을 수 있습니다. 몇 가지 일반적인 오류 및 해결 방법은 오류 및 해결 방법을 참조하세요.
이전 자습서에서는 관련 데이터를 표시했습니다. 이 자습서에서는 관련 데이터를 업데이트합니다. 대부분의 관계에서는 적절한 외래 키 필드를 업데이트하여 이 작업을 수행할 수 있습니다. 다 대 다 관계의 경우 Entity Framework는 조인 테이블을 직접 노출하지 않으므로 적절한 탐색 속성에서 엔터티를 명시적으로 추가 및 제거해야 합니다.
다음 그림에서는 사용할 페이지를 보여 줍니다.
강좌에 대한 만들기 및 편집 페이지 사용자 지정
새 강좌 엔터티가 만들어질 때 기존 부서에 대한 관계가 있어야 합니다. 이를 수행하기 위해 스캐폴드 코드는 컨트롤러 메서드 및 부서를 선택하기 위한 드롭다운 목록을 포함하는 만들기 및 편집 보기를 포함합니다. 드롭다운 목록은 Course.DepartmentID
외래 키 속성을 설정하고, 이는 적절한 Department
엔터티로 Department
탐색 속성을 로드하기 위해 필요한 모든 Entity Framework입니다. 스캐폴드 코드를 사용하지만 오류 처리를 추가하고 드롭다운 목록을 정렬하도록 약간 변경합니다.
CourseController.cs에서 네 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);
}
및 Edit
에 Create
대한 메서드에는 HttpPost
오류 발생 후 페이지를 다시 표시할 때 선택한 항목을 설정하는 코드도 포함됩니다.
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
있는 Courses 필드를 추가합니다.
@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 제목 바로 다음에 Courses 제목을 추가합니다.
<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 리소스에 대한 링크는 이 시리즈의 마지막 자습서 끝에 있습니다.
피드백
https://aka.ms/ContentUserFeedback
출시 예정: 2024년 내내 콘텐츠에 대한 피드백 메커니즘으로 GitHub 문제를 단계적으로 폐지하고 이를 새로운 피드백 시스템으로 바꿀 예정입니다. 자세한 내용은 다음을 참조하세요.다음에 대한 사용자 의견 제출 및 보기