다음을 통해 공유


자습서: ASP.NET MVC에서 Entity Framework를 사용하여 CRUD 기능 구현

이전 자습서에서는 EF(Entity Framework) 6 및 SQL Server LocalDB를 사용하여 데이터를 저장하고 표시하는 MVC 애플리케이션을 만들었습니다. 이 자습서에서는 MVC 스캐폴딩이 컨트롤러 및 뷰에서 자동으로 만드는 CRUD(만들기, 읽기, 업데이트, 삭제) 코드를 검토하고 사용자 지정합니다.

참고

컨트롤러와 데이터 액세스 계층 간에 추상화 계층을 만들기 위해 리포지토리 패턴을 구현하는 일반적인 사례입니다. 이러한 자습서를 간단하고 EF 6 자체를 사용하는 방법을 가르치는 데 집중하기 위해 리포지토리를 사용하지 않습니다. 리포지토리를 구현하는 방법에 대한 자세한 내용은 ASP.NET 데이터 액세스 콘텐츠 맵을 참조하세요.

만드는 웹 페이지의 예는 다음과 같습니다.

학생 세부 정보 페이지의 스크린샷

학생 만들기 페이지의 스크린샷

학생 삭제 페이지의 스크린샷

이 자습서에서는 다음을 수행합니다.

  • 세부 정보 페이지 만들기
  • 만들기 페이지 업데이트
  • HttpPost Edit 메서드 업데이트
  • 삭제 페이지 업데이트
  • 데이터베이스 연결 닫기
  • 트랜잭션 처리

사전 요구 사항

세부 정보 페이지 만들기

학생 Index 페이지에 대한 스캐폴드된 코드는 해당 속성이 Enrollments 컬렉션을 보유하기 때문에 속성을 제외했습니다. 페이지에서 Details HTML 테이블에 컬렉션의 내용을 표시합니다.

Controllers\StudentController.cs에서 뷰의 Details 작업 메서드는 Find 메서드를 사용하여 단일 Student 엔터티를 검색합니다.

public ActionResult Details(int? id)
{
    if (id == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }
    Student student = db.Students.Find(id);
    if (student == null)
    {
        return HttpNotFound();
    }
    return View(student);
}

키 값은 매개 변수로 id 메서드에 전달되며 인덱스 페이지의 세부 정보 하이퍼링크에 있는 경로 데이터에서 가져옵니다.

팁: 데이터 라우팅

경로 데이터는 모델 바인더가 라우팅 테이블에 지정된 URL 세그먼트에서 찾은 데이터입니다. 예를 들어 기본 경로는 , actionid 세그먼트를 지정controller합니다.

routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

다음 URL에서 기본 경로는 로 actionIndex 매핑 Instructorcontroller되고, 1id은 로 매핑됩니다. 이러한 경로는 경로 데이터 값입니다.

http://localhost:1230/Instructor/Index/1?courseID=2021

?courseID=2021 는 쿼리 문자열 값입니다. 를 쿼리 문자열 값으로 전달하는 id 경우에도 모델 바인더가 작동합니다.

http://localhost:1230/Instructor/Index?id=1&CourseID=2021

URL은 Razor 뷰의 문에 의해 ActionLink 만들어집니다. 다음 코드에서 매개 변수는 id 기본 경로와 일치하므로 id 경로 데이터에 추가됩니다.

@Html.ActionLink("Select", "Index", new { id = item.PersonID  })

다음 코드에서 는 courseID 기본 경로의 매개 변수와 일치하지 않으므로 쿼리 문자열로 추가됩니다.

@Html.ActionLink("Select", "Index", new { courseID = item.CourseID })

세부 정보 페이지를 만들려면

  1. Views\Student\Details.cshtml을 엽니다.

    다음 예제와 같이 각 필드는 도우미를 DisplayFor 사용하여 표시됩니다.

    <dt>
        @Html.DisplayNameFor(model => model.LastName)
    </dt>
    <dd>
        @Html.DisplayFor(model => model.LastName)
    </dd>
    
  2. EnrollmentDate 다음 예제와 같이 필드 뒤와 닫는 </dl> 태그 바로 앞에 강조 표시된 코드를 추가하여 등록 목록을 표시합니다.

    <dt>
                @Html.DisplayNameFor(model => model.EnrollmentDate)
            </dt>
    
            <dd>
                @Html.DisplayFor(model => model.EnrollmentDate)
            </dd>
            <dt>
                @Html.DisplayNameFor(model => model.Enrollments)
            </dt>
            <dd>
                <table class="table">
                    <tr>
                        <th>Course Title</th>
                        <th>Grade</th>
                    </tr>
                    @foreach (var item in Model.Enrollments)
                    {
                        <tr>
                            <td>
                                @Html.DisplayFor(modelItem => item.Course.Title)
                            </td>
                            <td>
                                @Html.DisplayFor(modelItem => item.Grade)
                            </td>
                        </tr>
                    }
                </table>
            </dd>
        </dl>
    </div>
    <p>
        @Html.ActionLink("Edit", "Edit", new { id = Model.ID }) |
        @Html.ActionLink("Back to List", "Index")
    </p>
    

    코드를 붙여넣은 후 코드 들여쓰기를 잘못한 경우 CtrlK, Ctrl++D를 눌러 서식을 지정합니다.

    이 코드는 Enrollments 탐색 속성의 엔터티를 통해 반복됩니다. 속성의 각 Enrollment 엔터티에 대해 과정 제목과 성적을 표시합니다. 과정 제목은 엔터티의 Course 탐색 속성 EnrollmentsCourse 저장된 엔터티에서 검색됩니다. 이 모든 데이터는 필요할 때 데이터베이스에서 자동으로 검색됩니다. 즉, 여기에서 지연 로드를 사용하고 있습니다. 탐색 속성에 대한 Courses즉시 로드를 지정하지 않았으므로 등록이 학생을 가져온 동일한 쿼리에서 검색되지 않았습니다. 대신 탐색 속성에 처음으로 액세스 Enrollments 하려고 하면 새 쿼리가 데이터베이스로 전송되어 데이터를 검색합니다. 지연 로드 및 즉시 로드에 대한 자세한 내용은 이 시리즈의 뒷부분에 있는 관련 데이터 읽기 자습서에서 확인할 수 있습니다.

  3. 프로그램(Ctrl+F5)을 시작하고 학생 탭을 선택한 다음 Alexander Carson에 대한 세부 정보 링크를 클릭하여 세부 정보 페이지를 엽니다. (Ctrl 키를 누를+ 경우Details.cshtml 파일이 열려 있는 동안 F5 HTTP 400 오류가 발생합니다. Visual Studio가 세부 정보 페이지를 실행하려고 하지만 표시할 학생을 지정하는 링크에서 연결되지 않았기 때문입니다. 이 경우 URL에서 "Student/Details"를 제거하고 다시 시도하거나 브라우저를 닫고 프로젝트를 마우스 오른쪽 단추로 클릭하고브라우저에서 보기보기를> 클릭합니다.

    선택한 학생의 과정 및 성적 목록이 표시됩니다.

  4. 브라우저를 닫습니다.

만들기 페이지 업데이트

  1. Controllers\StudentController.cs에서 작업 메서드를 HttpPostAttributeCreate 다음 코드로 바꿉니다. 이 코드는 try-catch 블록을 추가하고 스캐폴드된 메서드의 BindAttribute 특성에서 제거합니다ID.

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create([Bind(Include = "LastName, FirstMidName, EnrollmentDate")]Student student)
    {
        try
        {
            if (ModelState.IsValid)
            {
                db.Students.Add(student);
                db.SaveChanges();
                return RedirectToAction("Index");
            }
        }
        catch (DataException /* dex */)
        {
            //Log the error (uncomment dex variable name 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.");
        }
        return View(student);
    }
    

    이 코드는 Student ASP.NET MVC 모델 바인더에서 만든 엔터티를 Students 엔터티 집합에 추가한 다음 변경 내용을 데이터베이스에 저장합니다. 모델 바인더는 양식에서 제출한 데이터를 더 쉽게 사용할 수 있도록 하는 ASP.NET MVC 기능을 나타냅니다. 모델 바인더는 게시된 양식 값을 CLR 형식으로 변환하고 매개 변수의 작업 메서드에 전달합니다. 이 경우 모델 바인더는 컬렉션의 속성 값을 사용하여 엔터티를 Form 인스턴스화 Student 합니다.

    행이 삽입될 ID 때 SQL Server 자동으로 설정되는 기본 키 값이므로 Bind 특성 ID 에서 제거했습니다. 사용자의 입력이 값을 설정 ID 하지 않습니다.

    보안 경고 - 특성은 ValidateAntiForgeryToken사이트 간 요청 위조 공격을 방지하는 데 도움이 됩니다. 나중에 볼 수 있는 해당 Html.AntiForgeryToken() 문이 보기에 필요합니다.

    특성은 Bind 만들기 시나리오에서 과도하게 게시 되지 않도록 보호하는 한 가지 방법입니다. 예를 들어 엔터티에 Student 이 웹 페이지를 설정하지 않으려는 속성이 포함되어 Secret 있다고 가정합니다.

    public class Student
    {
        public int ID { get; set; }
        public string LastName { get; set; }
        public string FirstMidName { get; set; }
        public DateTime EnrollmentDate { get; set; }
        public string Secret { get; set; }
    
        public virtual ICollection<Enrollment> Enrollments { get; set; }
    }
    

    웹 페이지에 필드가 Secret 없더라도 해커는 fiddler와 같은 도구를 사용하거나 일부 JavaScript를 작성하여 양식 값을 게시 Secret 할 수 있습니다. 모델 바인더가 instance 만들 때 사용하는 필드를 제한하는 특성이 없으면 모델 바인더는 해당 Secret 양식 값을 선택하고 이를 사용하여 엔터티 instance 만듭니 Student 다.StudentBindAttribute 그런 다음, 해커가 Secret 양식 필드에 대해 지정한 모든 값은 데이터베이스에서 업데이트됩니다. 다음 이미지는 게시된 양식 값에 Secret 필드("OverPost" 값 포함)를 추가하는 fiddler 도구를 보여 줍니다.

    작성기 탭을 보여 주는 스크린샷 오른쪽 위 모서리에서 실행은 빨간색 원으로 표시됩니다. 오른쪽 아래 모서리에서 비밀은 포스트 위에 같으며 빨간색으로 동그라미를 친다.

    값 "OverPost"는 웹 페이지가 속성을 설정할 수 있도록 의도하지 않았지만 삽입된 행의 Secret 속성에 성공적으로 추가됩니다.

    매개 변수를 Include 특성과 함께 Bind 사용하여 필드를 명시적으로 나열하는 것이 가장 좋습니다. 매개 변수를 사용하여 Exclude 제외하려는 필드를 차단할 수도 있습니다. 더 안전한 이유는 Include 엔터티에 새 속성을 추가할 때 새 필드가 목록으로 자동으로 보호되지 않기 때문 Exclude 입니다.

    먼저 데이터베이스에서 엔터티를 읽은 다음 를 호출 TryUpdateModel하여 명시적으로 허용된 속성 목록을 전달하여 편집 시나리오에서 오버포스트를 방지할 수 있습니다. 이 자습서에서 사용되는 방법입니다.

    많은 개발자가 선호하는 오버포스트를 방지하는 또 다른 방법은 모델 바인딩이 있는 엔터티 클래스 대신 보기 모델을 사용하는 것입니다. 보기 모델에서 업데이트하려는 속성만 포함합니다. MVC 모델 바인더가 완료되면 선택적으로 AutoMapper와 같은 도구를 사용하여 뷰 모델 속성을 엔터티 instance 복사합니다. db를 사용합니다. 엔터티 instance 항목을 입력하여 상태를 변경되지 않음으로 설정한 다음 Property("PropertyName")를 설정합니다. 보기 모델에 포함된 각 엔터티 속성에 대해 IsModified를 true로 설정합니다. 이 방법은 편집 및 만들기 시나리오에서 모두 작동합니다.

    특성 try-catch 이외에 Bind 블록은 스캐폴드된 코드에 대한 유일한 변경 내용입니다. DataException에서 파생되는 예외가 변경 내용이 저장되는 동안 발견되는 경우 일반 오류 메시지가 표시됩니다. DataException 예외는 경우에 따라 프로그래밍 오류가 아니라 애플리케이션에 대한 외부적인 문제로 발생하므로 사용자는 다시 시도하는 것이 좋습니다. 이 샘플에서 구현되지 않지만 프로덕션 품질 애플리케이션은 예외를 기록합니다. 자세한 내용은 모니터링 및 원격 분석(Azure로 실제 클라우드 앱 빌드)에서 정보에 대한 로그 섹션을 참조하세요.

    Views\Student\Create.cshtml의 코드는 및 도우미가 대신 DisplayFor각 필드에 사용된다는 점을 제외하고 EditorForDetails.cshtml에서 본 코드와 ValidationMessageFor 유사합니다. 관련 코드는 다음과 같습니다.

    <div class="form-group">
        @Html.LabelFor(model => model.LastName, new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.LastName)
            @Html.ValidationMessageFor(model => model.LastName)
        </div>
    </div>
    

    Create.cshtml에는 교차 사이트 요청 위조 공격을 방지하기 위해 컨트롤러의 ValidateAntiForgeryToken 특성과 함께 작동하는 도 포함@Html.AntiForgeryToken()됩니다.

    Create.cshtml에는 변경이 필요하지 않습니다.

  2. 프로그램을 시작하고 학생 탭을 선택한 다음 새로 만들기를 클릭하여 페이지를 실행 합니다.

  3. 이름과 잘못된 날짜를 입력하고 만들기 를 클릭하여 오류 메시지를 확인합니다.

    기본적으로 가져오는 서버 쪽 유효성 검사입니다. 이후 자습서에서는 클라이언트 쪽 유효성 검사를 위한 코드를 생성하는 특성을 추가하는 방법을 알아보세요. 다음 강조 표시된 코드는 Create 메서드의 모델 유효성 검사 검사 보여줍니다.

    if (ModelState.IsValid)
    {
        db.Students.Add(student);
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    
  4. 유효한 값으로 날짜를 변경하고 만들기를 클릭하여 인덱스 페이지에 표시되는 새 학생을 봅니다.

  5. 브라우저를 닫습니다.

HttpPost Edit 메서드 업데이트

  1. 작업 메서드를 HttpPostAttributeEdit 다음 코드로 바꿉다.

    [HttpPost, ActionName("Edit")]
    [ValidateAntiForgeryToken]
    public ActionResult EditPost(int? id)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        var studentToUpdate = db.Students.Find(id);
        if (TryUpdateModel(studentToUpdate, "",
           new string[] { "LastName", "FirstMidName", "EnrollmentDate" }))
        {
            try
            {
                db.SaveChanges();
    
                return RedirectToAction("Index");
            }
            catch (DataException /* dex */)
            {
                //Log the error (uncomment dex variable name 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.");
            }
        }
        return View(studentToUpdate);
    }
    

    참고

    Controllers\StudentController.csHttpGet Edit에서 메서드(특성이 없는 HttpPost 메서드)는 메서드에서 확인한 것처럼 메서드를 사용하여 Find 선택한 Student 엔터티를 Details 검색합니다. 이 메서드를 변경할 필요가 없습니다.

    이러한 변경은 오버포스트를 방지하기 위한 보안 모범 사례를 구현합니다. 스캐폴더는 특성을 생성 Bind 하고 모델 바인더에서 만든 엔터티를 수정된 플래그가 있는 엔터티 집합에 추가했습니다. 특성이 매개 변수에 나열되지 않은 필드의 Bind 기존 데이터를 지우므로 해당 코드는 Include 더 이상 권장되지 않습니다. 나중에 MVC 컨트롤러 스캐폴더가 업데이트되어 편집 메서드에 대한 특성을 생성 Bind 하지 않습니다.

    새 코드는 기존 엔터티를 읽고 를 호출 TryUpdateModel 하여 게시된 양식 데이터의 사용자 입력에서 필드를 업데이트합니다. Entity Framework의 자동 변경 내용 추적은 엔터티에서 EntityState.Modified 플래그를 설정합니다. SaveChanges 메서드가 호출되면 플래그로 Modified 인해 Entity Framework에서 데이터베이스 행을 업데이트하는 SQL 문을 만듭니다. 동시성 충돌 은 무시되고 사용자가 변경하지 않은 열을 포함하여 데이터베이스 행의 모든 열이 업데이트됩니다. (이후 자습서에서는 동시성 충돌을 처리하는 방법을 보여 줍니다. 데이터베이스에서 개별 필드만 업데이트하려면 엔터티를 EntityState.Unchanged 로 설정하고 개별 필드를 EntityState.Modified로 설정할 수 있습니다.)

    초과 게시를 방지하기 위해 편집 페이지에서 업데이트할 수 있도록 하려는 필드가 매개 변수에 TryUpdateModel 나열됩니다. 현재 보호하는 추가 필드가 없지만 모델 바인더에서 바인딩하길 원하는 필드를 나열하는 것은 향후에 데이터 모델에 필드를 추가하는지 확인하며, 여기에서 명시적으로 추가할 때까지 자동으로 보호됩니다.

    이러한 변경으로 인해 HttpPost Edit 메서드의 메서드 서명은 HttpGet 편집 메서드와 동일합니다. 따라서 메서드의 이름을 EditPost로 변경했습니다.

    엔터티 상태 및 Attach 및 SaveChanges 메서드

    데이터베이스 컨텍스트는 메모리의 엔터티가 데이터베이스의 해당 열과 동기화 상태인지 여부의 추적을 유지하고 이 정보는 SaveChanges 메서드를 호출할 때 발생하는 작업을 결정합니다. 예를 들어 새 엔터티를 Add 메서드에 전달하면 해당 엔터티의 상태가 로 Added설정됩니다. 그런 다음 SaveChanges 메서드를 호출하면 데이터베이스 컨텍스트에서 SQL INSERT 명령을 실행합니다.

    엔터티는 다음 상태 중 하나일 수 있습니다.

    • Added. 엔터티가 데이터베이스에 아직 존재하지 않습니다. 메서드는 SaveChanges 문을 실행 INSERT 해야 합니다.
    • Unchanged. SaveChanges 메서드에서 이 엔터티로 아무 작업도 수행할 필요가 없습니다. 데이터베이스에서 엔터티를 읽을 때 엔터티는 이 상태로 시작합니다.
    • Modified. 일부 또는 모든 엔터티의 속성 값이 수정되었습니다. 메서드는 SaveChanges 문을 실행 UPDATE 해야 합니다.
    • Deleted. 엔터티가 삭제되도록 표시되었습니다. 메서드는 SaveChanges 문을 실행 DELETE 해야 합니다.
    • Detached. 엔터티가 데이터베이스 컨텍스트에 의해 추적되지 않습니다.

    데스크톱 애플리케이션에서는 일반적으로 상태 변경 내용이 자동으로 설정됩니다. 데스크톱 유형의 애플리케이션에서는 엔터티를 읽고 일부 속성 값을 변경합니다. 이렇게 하면 해당 엔터티 상태가 자동으로 Modified로 변경됩니다. 그런 다음, 를 호출 SaveChanges하면 Entity Framework는 변경한 실제 속성만 업데이트하는 SQL UPDATE 문을 생성합니다.

    웹앱의 연결이 끊긴 특성은 이 연속 시퀀스를 허용하지 않습니다. 엔터티를 읽는 DbContext 는 페이지가 렌더링된 후 삭제됩니다. HttpPostEdit 작업 메서드가 호출되면 새 요청이 수행되고 DbContext의 새 instance 있으므로 엔터티 상태를 Modified. 수동으로 로 설정해야 합니다. 를 호출SaveChanges할 때 Entity Framework는 변경한 속성을 알 수 없기 때문에 데이터베이스 행의 모든 열을 업데이트합니다.

    SQL Update 문에서 사용자가 실제로 변경한 필드만 업데이트하려면 메서드를 호출할 때 사용할 수 있도록 원래 값(예: 숨겨진 필드)을 HttpPostEdit 저장할 수 있습니다. 그런 다음 원래 값을 사용하여 엔터티를 Student 만들고, 엔터티의 원래 버전으로 메서드를 호출 Attach 하고, 엔터티의 값을 새 값으로 업데이트한 다음, 자세한 SaveChanges. 내용은 엔터티 상태 및 SaveChanges 및로컬 데이터를 참조하세요.

    Views\Student\Edit.cshtml의 HTML 및 Razor 코드는 Create.cshtml에서 본 것과 유사하며 변경이 필요하지 않습니다.

  2. 프로그램을 시작하고 학생 탭을 선택한 다음 , 하이퍼링크 편집 을 클릭하여 페이지를 실행합니다.

  3. 데이터의 일부를 변경하고 저장을 클릭합니다. 인덱스 페이지에 변경된 데이터가 표시됩니다.

  4. 브라우저를 닫습니다.

삭제 페이지 업데이트

Controllers\StudentController.cs에서 메서드의 HttpGetAttributeDelete 템플릿 코드는 및 Edit 메서드에서 확인한 것처럼 메서드를 사용하여 Find 선택한 Student 엔터티를 Details 검색합니다. 그러나 SaveChanges에 대한 호출이 실패하는 경우 사용자 지정 오류 메시지를 구현하려면 이 메서드 및 해당 보기에 일부 기능을 추가합니다.

업데이트 및 만들기 작업에 대해 본 것과 같이 삭제 작업에는 두 개의 작업 메서드가 필요합니다. GET 요청에 대한 응답으로 호출되는 메서드는 사용자에게 삭제 작업을 승인하거나 취소할 수 있는 보기를 표시합니다. 사용자가 승인하는 경우 POST 요청이 생성됩니다. 이 경우 메서드가 HttpPostDelete 호출되고 해당 메서드가 실제로 삭제 작업을 수행합니다.

데이터베이스가 try-catch 업데이트될 때 발생할 수 있는 오류를 처리하기 위해 메서드에 블록을 HttpPostAttributeDelete 추가합니다. 오류가 발생하면 메서드는 HttpPostAttributeDelete 메서드를 HttpGetAttributeDelete 호출하여 오류가 발생했음을 나타내는 매개 변수를 전달합니다. 그런 다음 메서드는 HttpGetAttributeDelete 오류 메시지와 함께 확인 페이지를 다시 표시하여 사용자에게 취소하거나 다시 시도할 수 있는 기회를 제공합니다.

  1. 작업 메서드를 HttpGetAttributeDelete 오류 보고를 관리하는 다음 코드로 바꿉니다.

    public ActionResult Delete(int? id, bool? saveChangesError=false)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        if (saveChangesError.GetValueOrDefault())
        {
            ViewBag.ErrorMessage = "Delete failed. Try again, and if the problem persists see your system administrator.";
        }
        Student student = db.Students.Find(id);
        if (student == null)
        {
            return HttpNotFound();
        }
        return View(student);
    }
    

    이 코드는 변경 내용을 저장하지 못한 후 메서드가 호출되었는지 여부를 나타내는 선택적 매개 변수 를 허용합니다. 이 매개 변수는 false 메서드가 HttpGetDelete 이전 오류 없이 호출되는 경우입니다. 데이터베이스 업데이트 오류에 대한 응답으로 메서드에 의해 HttpPostDelete 호출되면 매개 변수가 이 true 고 오류 메시지가 보기에 전달됩니다.

  2. HttpPostAttributeDelete 작업 메서드(명명됨)를 DeleteConfirmed실제 삭제 작업을 수행하고 데이터베이스 업데이트 오류를 catch하는 다음 코드로 바꿉니다.

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Delete(int id)
    {
        try
        {
            Student student = db.Students.Find(id);
            db.Students.Remove(student);
            db.SaveChanges();
        }
        catch (DataException/* dex */)
        {
            //Log the error (uncomment dex variable name and add a line here to write a log.
            return RedirectToAction("Delete", new { id = id, saveChangesError = true });
        }
        return RedirectToAction("Index");
    }
    

    이 코드는 선택한 엔터티를 검색한 다음 Remove 메서드를 호출하여 엔터티의 상태 로 Deleted설정합니다. SaveChanges가 호출되면 SQL DELETE 명령이 생성됩니다. 또한 DeleteConfirmed에서 Delete로 작업 메서드 이름을 변경했습니다. 메서드라는 스캐폴드된 코드는 HttpPostDelete 메서드 DeleteConfirmedHttpPost 고유한 서명을 제공합니다. (CLR에는 오버로드된 메서드에 다른 메서드 매개 변수가 있어야 합니다.) 이제 서명이 고유하므로 MVC 규칙을 고수하고 및 HttpGet 삭제 메서드에 대해 HttpPost 동일한 이름을 사용할 수 있습니다.

    대용량 애플리케이션의 성능 향상이 우선 순위인 경우 및 Remove 메서드를 호출 Find 하는 코드 줄을 다음 코드로 바꿔서 행을 검색하는 불필요한 SQL 쿼리를 방지할 수 있습니다.

    Student studentToDelete = new Student() { ID = id };
    db.Entry(studentToDelete).State = EntityState.Deleted;
    

    이 코드는 Student 기본 키 값만 사용하여 엔터티를 인스턴스화한 다음 엔터티 상태를 로 Deleted설정합니다. Entity Framework에서 엔터티를 삭제하기 위해 필요한 모든 것입니다.

    설명한 대로 메서드는 HttpGetDelete 데이터를 삭제하지 않습니다. GET 요청에 대한 응답으로 삭제 작업을 수행하거나 편집 작업, 만들기 작업 또는 데이터를 변경하는 기타 작업을 수행하면 보안 위험이 발생합니다. 자세한 내용은 ASP.NET MVC 팁 #46 - Stephen Walther의 블로그에 보안 허점을 만들기 때문에 링크 삭제를 사용하지 않음 을 참조하세요.

  3. Views\Student\Delete.cshtml에서 다음 예제와 같이 제목과 h3 제목 사이에 h2 오류 메시지를 추가합니다.

    <h2>Delete</h2>
    <p class="error">@ViewBag.ErrorMessage</p>
    <h3>Are you sure you want to delete this?</h3>
    
  4. 프로그램을 시작하고 학생 탭을 선택한 다음 삭제 하이퍼링크를 클릭하여 페이지를 실행합니다.

  5. 삭제하시겠습니까?라는 페이지에서 삭제를 선택합니다.

    인덱스 페이지는 삭제된 학생 없이 표시됩니다. ( 동시성 자습서에서 작동 중인 오류 처리 코드의 예제가 표시됩니다.)

데이터베이스 연결 닫기

데이터베이스 연결 닫고 가능한 한 빨리 보유한 리소스를 확보하려면 작업을 완료하면 컨텍스트 instance 삭제합니다. 따라서 스캐폴드된 코드는 다음 예제와 같이 StudentController.csStudentController 클래스 끝에 Dispose 메서드를 제공합니다.

protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        db.Dispose();
    }
    base.Dispose(disposing);
}

기본 Controller 클래스는 이미 인터페이스를 IDisposable 구현하므로 이 코드는 메서드에 재정의 Dispose(bool) 를 추가하여 컨텍스트 instance 명시적으로 삭제합니다.

트랜잭션 처리

기본적으로 Entity Framework는 트랜잭션을 암시적으로 구현합니다. 여러 행 또는 테이블을 변경한 다음 를 호출 SaveChanges하는 시나리오에서 Entity Framework는 자동으로 모든 변경 내용이 성공하거나 모두 실패하도록 합니다. 일부 변경 내용이 먼저 완료된 다음, 오류가 발생하는 경우 해당 변경 내용이 자동으로 롤백됩니다. 더 많은 제어가 필요한 시나리오(예: 트랜잭션에 Entity Framework 외부에서 수행된 작업을 포함하려는 경우)는 트랜잭션 작업을 참조하세요.

코드 가져오기

완료된 프로젝트 다운로드

추가 리소스

이제 엔터티에 대해 Student 간단한 CRUD 작업을 수행하는 전체 페이지 집합이 있습니다. MVC 도우미를 사용하여 데이터 필드에 대한 UI 요소를 생성했습니다. MVC 도우미에 대한 자세한 내용은 HTML 도우미를 사용하여 양식 렌더링을 참조하세요(이 문서는 MVC 3용이지만 MVC 5와 여전히 관련이 있음).

다른 EF 6 리소스에 대한 링크는 ASP.NET 데이터 액세스 - 권장 리소스에서 찾을 수 있습니다.

다음 단계

이 자습서에서는 다음을 수행합니다.

  • 세부 정보 페이지 만들기
  • 만들기 페이지 업데이트
  • HttpPost Edit 메서드가 업데이트됨
  • 삭제 페이지 업데이트
  • 데이터베이스 연결 닫기
  • 처리된 트랜잭션

다음 문서로 이동하여 프로젝트에 정렬, 필터링 및 페이징을 추가하는 방법을 알아봅니다.