ASP.NET 웹 페이지 소개 - 데이터베이스 데이터 업데이트

Tom FitzMacken

이 자습서에서는 ASP.NET 웹 페이지(Razor)를 사용할 때 기존 데이터베이스 항목을 업데이트(변경)하는 방법을 보여 줍니다. ASP.NET 웹 페이지 사용하여 폼을 사용하여 데이터 입력을 통해 시리즈를 완료한 것으로 가정합니다.

학습할 내용:

  • 도우미에서 개별 레코드를 WebGrid 선택하는 방법입니다.
  • 데이터베이스에서 단일 레코드를 읽는 방법입니다.
  • 데이터베이스 레코드의 값을 사용하여 양식을 미리 로드하는 방법입니다.
  • 데이터베이스에서 기존 레코드를 업데이트하는 방법입니다.
  • 페이지를 표시하지 않고 페이지에 정보를 저장하는 방법입니다.
  • 숨겨진 필드를 사용하여 정보를 저장하는 방법입니다.

설명된 기능/기술:

  • 도우미입니다 WebGrid .
  • SQL Update 명령입니다.
  • Database.Execute 메서드
  • 숨겨진 필드(<input type="hidden">).

만들 내용

이전 자습서에서는 데이터베이스에 레코드를 추가하는 방법을 알아보았습니다. 여기서는 편집을 위해 레코드를 표시하는 방법을 알아봅니다. 영화 페이지에서 도우미를 WebGrid 업데이트하여 각 동영상 옆에 편집 링크를 표시합니다.

각 동영상에 대한 '편집' 링크를 포함하는 WebGrid 디스플레이

편집 링크를 클릭하면 영화 정보가 이미 양식에 있는 다른 페이지로 이동합니다.

편집할 동영상을 보여 주는 동영상 편집 페이지

값을 변경할 수 있습니다. 변경 내용을 제출하면 페이지의 코드가 데이터베이스를 업데이트하고 동영상 목록으로 돌아갑니다.

프로세스의 이 부분은 이전 자습서에서 만든 AddMovie.cshtml 페이지와 거의 동일하게 작동하므로 이 자습서의 많은 부분이 익숙할 것입니다.

개별 영화를 편집하는 방법을 구현하는 방법에는 여러 가지가 있습니다. 표시된 접근 방식은 구현하기 쉽고 이해하기 쉽기 때문에 선택되었습니다.

시작하려면 각 영화 목록에 편집 링크도 포함되도록 영화 페이지를 업데이트합니다.

Movies.cshtml 파일을 엽니다.

페이지 본문에서 열을 추가하여 태그를 변경 WebGrid 합니다. 수정된 태그는 다음과 같습니다.

@grid.GetHtml(
    tableStyle: "grid",
    headerStyle: "head",
    alternatingRowStyle: "alt",
    columns: grid.Columns(
        grid.Column(format: @<a href="~/EditMovie?id=@item.ID">Edit</a>),
        grid.Column("Title"),
        grid.Column("Genre"),
        grid.Column("Year")
    )
)

새 열은 다음과 같습니다.

grid.Column(format: @<a href="~/EditMovie?id=@item.ID)">Edit</a>)

이 열의 요점은 텍스트가 "편집"이라는 링크(<a> 요소)를 표시하는 것입니다. 이후 각 영화에 대해 값이 다른 페이지가 실행 id 되면 다음과 같은 링크를 만듭니다.

http://localhost:43097/EditMovie?id=7

이 링크는 EditMovie라는 페이지를 호출하고 쿼리 문자열 ?id=7 을 해당 페이지에 전달합니다.

새 열의 구문은 약간 복잡해 보일 수 있지만 여러 요소를 함께 배치하기 때문입니다. 각 개별 요소는 간단합니다. 요소에만 <a> 집중하면 다음 태그가 표시됩니다.

<a href="~/EditMovie?id=@item.ID)">Edit</a>

그리드 작동 방식에 대한 몇 가지 배경: 그리드는 각 데이터베이스 레코드에 대해 하나씩 행을 표시하고 데이터베이스 레코드의 각 필드에 대한 열을 표시합니다. 각 그리드 행이 생성되는 동안 개체에는 item 해당 행에 대한 데이터베이스 레코드(항목)가 포함됩니다. 이 정렬은 코드에서 해당 행의 데이터를 가져오는 방법을 제공합니다. item.ID 식은 현재 데이터베이스 항목의 ID 값을 가져옵니다. , item.Genre또는 를 사용하여 item.Title동일한 방식으로 데이터베이스 값(제목, 장르 또는 item.Year연도)을 가져올 수 있습니다.

"~/EditMovie?id=@item.ID 은 대상 URL(~/EditMovie?id=)의 하드 코딩된 부분을 동적으로 파생된 ID와 결합합니다. (이전 자습서에서 연산자를 ~ 확인했습니다. 현재 웹 사이트 루트를 나타내는 ASP.NET 연산자입니다.)

결과적으로 열에 있는 태그의 이 부분은 런타임에 다음과 같은 태그를 생성합니다.

href="/EditMovie?id=2"

당연히 의 실제 값 id 은 각 행마다 다릅니다.

그리드 열에 대한 사용자 지정 디스플레이 만들기

이제 그리드 열로 돌아갑니다. 원래 그리드에 있던 세 개의 열에는 데이터 값(제목, 장르 및 연도)만 표시되었습니다. 데이터베이스 열의 이름(예 grid.Column("Title"): )을 전달하여 이 표시를 지정했습니다.

이 새 링크 편집 열은 다릅니다. 열 이름을 지정하는 대신 매개 변수를 전달합니다 format . 이 매개 변수를 사용하면 도우미가 WebGrid 값과 item 함께 렌더링할 태그를 정의하여 열 데이터를 굵게 또는 녹색 또는 원하는 형식으로 표시할 수 있습니다. 예를 들어 제목이 굵게 표시되도록 하려면 다음 예제와 같은 열을 만들 수 있습니다.

grid.Column(format:@<strong>@item.Title</strong>)

속성에 format 표시되는 다양한 @ 문자는 태그와 코드 값 간의 전환을 표시합니다.

속성에 format 대해 알게 되면 새 편집 링크 열이 어떻게 결합되는지 더 쉽게 이해할 수 있습니다.

grid.Column(format: @<a href="~/EditMovie?id=@item.ID">Edit</a>),

열은 링크를 렌더링하는 태그와 행의 데이터베이스 레코드에서 추출된 일부 정보(ID) 로만 구성됩니다.

메서드의 명명된 매개 변수 및 위치 매개 변수

메서드를 호출하고 매개 변수를 전달한 경우 매개 변수 값을 쉼표로 구분하여 나열한 경우가 많습니다. 다음은 몇 가지 예입니다.

db.Execute(insertCommand, title, genre, year)

Validation.RequireField("title", "You must enter a title")

이 코드를 처음 보았을 때 문제를 멘션 않았지만, 각각의 경우 매개 변수를 특정 순서로 메서드에 전달합니다. 즉, 매개 변수가 해당 메서드에 정의된 순서입니다. db.ExecuteValidation.RequireFields의 경우 전달한 값의 순서를 혼합하면 페이지가 실행되거나 적어도 이상한 결과가 나타날 때 오류 메시지가 표시됩니다. 분명히 매개 변수를 전달하는 순서를 알아야 합니다. (WebMatrix에서 IntelliSense는 매개 변수의 이름, 형식 및 순서를 파악하는 데 도움이 될 수 있습니다.)

값을 순서대로 전달하는 대신 명명된 매개 변수를 사용할 수 있습니다. (순서대로 매개 변수를 전달하는 것은 위치 매개 변수를 사용하는 것으로 알려져 있습니다.) 명명된 매개 변수의 경우 해당 값을 전달할 때 매개 변수의 이름을 명시적으로 포함합니다. 이 자습서에서는 명명된 매개 변수를 이미 여러 번 사용했습니다. 예:

var grid = new WebGrid(source: selectedData, defaultSort: "Genre", rowsPerPage:3)

@grid.GetHtml(
    tableStyle: "grid",
    headerStyle: "head",
    alternatingRowStyle: "alt",
    columns: grid.Columns(
       grid.Column("Title"),
       grid.Column("Genre"),
       grid.Column("Year")
    )
)

명명된 매개 변수는 특히 메서드가 많은 매개 변수를 사용하는 경우 몇 가지 경우에 유용합니다. 하나는 하나 또는 두 개의 매개 변수만 전달하려는 경우이지만 전달하려는 값이 매개 변수 목록의 첫 번째 위치에 속하지 않는 경우입니다. 또 다른 상황은 가장 적합한 순서로 매개 변수를 전달하여 코드를 더 읽기 쉽게 만들려는 경우입니다.

명명된 매개 변수를 사용하려면 매개 변수의 이름을 알아야 합니다. WebMatrix IntelliSense는 이름을 표시 할 수 있지만 현재 이름을 입력할 수는 없습니다.

편집 페이지 만들기

이제 EditMovie 페이지를 만들 수 있습니다. 사용자가 편집 링크를 클릭하면 이 페이지에서 종료됩니다.

EditMovie.cshtml이라는 페이지를 만들고 파일에 있는 항목을 다음 태그로 바꿉니다.

<!DOCTYPE html>
<html>
  <head>
   <meta charset="utf-8" />
   <title>Edit a Movie</title>
    <style>
      .validation-summary-errors{
        border:2px dashed red;
        color:red;
        font-weight:bold;
        margin:12px;
      }
    </style>
  </head>
  <body>
    <h1>Edit a Movie</h1>
    @Html.ValidationSummary()
    <form method="post">
      <fieldset>
        <legend>Movie Information</legend>

        <p><label for="title">Title:</label>
           <input type="text" name="title" value="@title" /></p>

        <p><label for="genre">Genre:</label>
           <input type="text" name="genre" value="@genre" /></p>

        <p><label for="year">Year:</label>
           <input type="text" name="year" value="@year" /></p>

        <input type="hidden" name="movieid" value="@movieId" />

        <p><input type="submit" name="buttonSubmit" value="Submit Changes" /></p>
      </fieldset>
    </form>
  </body>
</html>

이 태그 및 코드는 AddMovie 페이지에 있는 것과 비슷합니다. 제출 단추의 텍스트에는 약간의 차이가 있습니다. AddMovie 페이지 Html.ValidationSummary 와 마찬가지로 유효성 검사 오류가 있는 경우 이를 표시하는 호출이 있습니다. 이번에는 유효성 검사 요약에 Validation.Message오류가 표시되므로 에 대한 호출을 제외합니다. 이전 자습서에서 설명한 대로 유효성 검사 요약 및 개별 오류 메시지를 다양한 조합으로 사용할 수 있습니다.

요소의 <form> 특성이 method 로 설정되어 있는지 다시 확인합니다post. AddMovie.cshtml 페이지와 마찬가지로 이 페이지는 데이터베이스를 변경합니다. 따라서 이 양식은 작업을 수행해야 POST 합니다. (및 작업의 차이점 GET 에 대한 자세한 내용은 HTML 양식에 대한 자습서의 GET, POST 및 HTTP 동사 안전 사이드바를 참조하세요.)POST

이전 자습서 value 에서 보았듯이 텍스트 상자의 특성은 미리 로드하기 위해 Razor 코드로 설정됩니다. 하지만 이번에는 대신 및 genre 와 같은 title 변수를 해당 작업에 Request.Form["title"]사용합니다.

<input type="text" name="title" value="@title" />

이전과 마찬가지로 이 태그는 텍스트 상자 값을 동영상 값으로 미리 로드합니다. 이번에는 개체를 사용하는 Request 대신 변수를 사용하는 것이 편리한 이유를 잠시 알 수 있습니다.

이 페이지에는 <input type="hidden"> 요소도 있습니다. 이 요소는 페이지에 동영상 ID를 표시하지 않고 저장합니다. ID는 처음에 쿼리 문자열 값(?id=7 또는 URL에서 유사)을 사용하여 페이지로 전달됩니다. ID 값을 숨겨진 필드에 배치하면 페이지가 호출된 원래 URL에 더 이상 액세스할 수 없더라도 양식이 제출될 때 사용할 수 있는지 확인할 수 있습니다.

AddMovie 페이지와 달리 EditMovie 페이지의 코드에는 두 가지 고유한 함수가 있습니다. 첫 번째 함수는 페이지가 처음으로 표시될 때(그리고 그 다음에 ) 코드가 쿼리 문자열에서 동영상 ID를 가져오는 것입니다. 그런 다음 코드는 ID를 사용하여 데이터베이스에서 해당 동영상을 읽고 텍스트 상자에 표시(미리 로드)합니다.

두 번째 함수는 사용자가 변경 내용 제출 단추를 클릭하면 코드가 텍스트 상자의 값을 읽고 유효성을 검사해야 한다는 것입니다. 또한 코드는 데이터베이스 항목을 새 값으로 업데이트해야 합니다. 이 기술은 AddMovie에서 보았듯이 레코드를 추가하는 것과 비슷합니다.

단일 동영상을 읽는 코드 추가

첫 번째 함수를 수행하려면 페이지 맨 위에 다음 코드를 추가합니다.

@{
    var title = "";
    var genre = "";
    var year = "";
    var movieId = "";

    if(!IsPost){
        if(!Request.QueryString["ID"].IsEmpty()){
            movieId = Request.QueryString["ID"];
            var db = Database.Open("WebPagesMovies");
            var dbCommand = "SELECT * FROM Movies WHERE ID = @0";
            var row = db.QuerySingle(dbCommand, movieId);
            title = row.Title;
            genre = row.Genre;
            year = row.Year;
        }
        else{
            Validation.AddFormError("No movie was selected.");
        }
    }
}

이 코드의 대부분은 를 시작하는 블록 내에 있습니다 if(!IsPost). 연산자는 ! "not"을 의미하므로 식은 이 요청이 게시 제출이 아닌 경우를 의미하며, 이는 이 요청이 이 페이지가 처음 실행된 경우를 간접적으로 말하는 방법입니다. 앞에서 설명한 대로 이 코드는 페이지를 처음 실행할 때만 실행되어야 합니다. 에 if(!IsPost)코드를 묶지 않은 경우 처음 또는 단추 클릭에 대한 응답으로 페이지가 호출될 때마다 실행됩니다.

이번에는 코드에 블록이 else 포함되어 있습니다. 블록을 도입했을 if 때 말했듯이 테스트 중인 조건이 true가 아닌 경우 대체 코드를 실행하려는 경우가 있습니다. 여기에도 해당합니다. 조건이 전달되면(즉, 페이지에 전달된 ID가 정상인 경우) 데이터베이스에서 행을 읽습니다. 그러나 조건이 통과되지 않으면 블록이 else 실행되고 코드가 오류 메시지를 설정합니다.

페이지에 전달된 값의 유효성 검사

코드는 를 사용하여 Request.QueryString["id"] 페이지에 전달된 ID를 가져옵니다. 이 코드는 ID에 대한 값이 실제로 전달되었는지 확인합니다. 값이 전달되지 않은 경우 코드는 유효성 검사 오류를 설정합니다.

이 코드는 정보의 유효성을 검사하는 다른 방법을 보여줍니다. 이전 자습서에서는 도우미와 함께 작업했습니다 Validation . 유효성을 검사하기 위해 필드를 등록했고, ASP.NET 자동으로 유효성 검사를 수행하고 및 Html.ValidationSummary을 사용하여 Html.ValidationMessage 오류를 표시했습니다. 그러나 이 경우 사용자 입력의 유효성을 실제로 검사하지는 않습니다. 대신 다른 위치에서 페이지로 전달된 값의 유효성을 검사합니다. 도우미는 Validation 이 작업을 수행하지 않습니다.

따라서 를 사용하여 테스트if(!Request.QueryString["ID"].IsEmpty()하여 값을 직접 검사. 문제가 있는 경우 도우미와 마찬가지로 를 사용하여 Html.ValidationSummary오류를 표시할 Validation 수 있습니다. 이렇게 하려면 를 호출 Validation.AddFormError 하고 표시할 메시지를 전달합니다. Validation.AddFormError 는 이미 익숙한 유효성 검사 시스템과 연결된 사용자 지정 메시지를 정의할 수 있는 기본 제공 메서드입니다. (이 자습서의 뒷부분에서는 이 유효성 검사 프로세스를 좀 더 강력하게 만드는 방법에 대해 설명합니다.)

동영상의 ID가 있는지 확인한 후 코드는 데이터베이스를 읽고 단일 데이터베이스 항목만 찾습니다. 데이터베이스를 열고 SQL 문을 정의한 다음 문을 실행하는 데이터베이스 작업의 일반적인 패턴을 알아차렸을 것입니다. 이번에는 SQL Select 문에 가 포함됩니다 WHERE ID = @0. ID는 고유하므로 하나의 레코드만 반환할 수 있습니다.

쿼리는 (동영상 목록에 사용한 것처럼 이 아닌db.Query)을 사용하여 db.QuerySingle 수행되며, 코드는 결과를 변수에 row 넣습니다. 이름은 row 임의적입니다. 원하는 변수의 이름을 지정할 수 있습니다. 그런 다음 맨 위에서 초기화된 변수는 이러한 값을 텍스트 상자에 표시할 수 있도록 동영상 세부 정보로 채워집니다.

편집 페이지 테스트(지금까지)

페이지를 테스트하려면 지금 영화 페이지를 실행하고 동영상 옆에 있는 편집 링크를 클릭합니다. 선택한 영화에 대한 세부 정보가 입력된 EditMovie 페이지가 표시됩니다.

스크린샷은 편집할 동영상을 보여 주는 동영상 편집 페이지를 보여줍니다.

페이지의 URL에는 (또는 다른 숫자)와 같은 ?id=10 항목이 포함되어 있습니다. 지금까지 동영상 페이지의 링크 편집이 작동하고, 페이지가 쿼리 문자열에서 ID를 읽고 있으며, 단일 영화 레코드를 가져오기 위한 데이터베이스 쿼리가 작동하는지 테스트했습니다.

영화 정보를 변경할 수 있지만 변경 내용 제출을 클릭하면 아무 일도 발생하지 않습니다.

사용자의 변경 내용으로 동영상을 업데이트하는 코드 추가

EditMovie.cshtml 파일에서 두 번째 함수(변경 내용 저장)를 구현하려면 블록의 @ 닫는 중괄호 안에 다음 코드를 추가합니다. (코드를 어디에 배치해야 할지 정확히 모르는 경우 이 자습서의 끝에 표시되는 동영상 편집 페이지의 전체 코드 목록을 확인할 수 있습니다.)

if(IsPost){
    Validation.RequireField("title", "You must enter a title");
    Validation.RequireField("genre", "Genre is required");
    Validation.RequireField("year", "You haven't entered a year");
    Validation.RequireField("movieid", "No movie ID was submitted!");

    title = Request.Form["title"];
    genre = Request.Form["genre"];
    year = Request.Form["year"];
    movieId = Request.Form["movieId"];

    if(Validation.IsValid()){
        var db = Database.Open("WebPagesMovies");
        var updateCommand = "UPDATE Movies SET Title=@0, Genre=@1, Year=@2 WHERE Id=@3";
        db.Execute(updateCommand, title, genre, year, movieId);
        Response.Redirect("~/Movies");
   }
}

이 태그와 코드는 AddMovie의 코드와 비슷합니다. 이 코드는 if(IsPost) 사용자가 변경 내용 제출 단추를 클릭할 때만 실행되기 때문에 블록에 있습니다. 즉, 양식이 게시된 경우(그리고 있을 때만)입니다. 이 경우 와 같은 if(IsPost && Validation.IsValid())테스트를 사용하지 않습니다. 즉, AND를 사용하여 두 테스트를 결합하지는 않습니다. 이 페이지에서는 먼저 양식 제출()if(IsPost)이 있는지 확인한 다음 유효성 검사를 위해 필드를 등록합니다. 그런 다음 유효성 검사 결과(if(Validation.IsValid())를 테스트할 수 있습니다. 흐름은 AddMovie.cshtml 페이지와 약간 다르지만 효과는 동일합니다.

다른 <input> 요소에 대해 및 유사한 코드를 사용하여 Request.Form["title"] 텍스트 상자의 값을 가져옵니다. 이번에는 코드가 숨겨진 필드(<input type="hidden">)에서 영화 ID를 가져옵니다. 페이지가 처음 실행되면 코드가 쿼리 문자열에서 ID를 가져옵니다. 숨겨진 필드에서 값을 가져와 쿼리 문자열이 그 이후로 어떻게든 변경된 경우를 대비하여 원래 표시된 동영상의 ID를 가져오도록 합니다.

AddMovie 코드와 이 코드 간의 매우 중요한 차이점은 이 코드에서 문 대신 Insert Into SQL Update 문을 사용한다는 것입니다. 다음 예제에서는 SQL Update 문의 구문을 보여 줍니다.

UPDATE table SET col1="value", col2="value", col3="value" ... WHERE ID = value

임의의 순서로 열을 지정할 수 있으며 작업 중에 Update 모든 열을 업데이트할 필요는 없습니다. (실제로 레코드를 새 레코드로 저장하므로 ID 자체를 업데이트할 수 없으며 작업에는 허용되지 Update 않습니다.)

참고

중요 ID가 있는 절은 Where 데이터베이스가 업데이트하려는 데이터베이스 레코드를 알고 있기 때문에 매우 중요합니다. 절을 Where 중단한 경우 데이터베이스는 데이터베이스의 모든 레코드를 업데이트합니다. 대부분의 경우, 그것은 재앙이 될 것입니다.

코드에서 업데이트할 값은 자리 표시자를 사용하여 SQL 문에 전달됩니다. 앞에서 설명한 내용을 반복하려면: 보안상의 이유로 자리 표시자 사용하여 SQL 문에 값을 전달합니다.

코드는 를 사용하여 db.Execute 문을 실행한 Update 후 목록 페이지로 다시 리디렉션됩니다. 여기서 변경 내용을 볼 수 있습니다.

다른 SQL 문, 다른 메서드

약간 다른 메서드를 사용하여 다른 SQL 문을 실행하는 것을 확인할 수 있습니다. 잠재적으로 여러 레코드를 Select 반환하는 쿼리를 실행하려면 메서드를 Query 사용합니다. 하나의 데이터베이스 항목만 반환할 것으로 알고 있는 쿼리를 실행 Select 하려면 메서드를 QuerySingle 사용합니다. 변경하지만 데이터베이스 항목을 반환하지 않는 명령을 실행하려면 메서드를 Execute 사용합니다.

QuerySingleQuery 차이점에서 이미 확인한 것처럼 각 메서드는 서로 다른 결과를 반환하기 때문에 서로 다른 메서드가 있어야 합니다. 메서드는 Execute 실제로 명령의 영향을 받은 데이터베이스 행 수와 같은 값도 반환하지만 지금까지 무시해 왔습니다.

물론 메서드는 Query 하나의 데이터베이스 행만 반환할 수 있습니다. 그러나 ASP.NET 항상 메서드의 Query 결과를 컬렉션으로 처리합니다. 메서드가 하나의 행만 반환하더라도 컬렉션에서 해당 단일 행을 추출해야 합니다. 따라서 한 행만 다시 가져올 것으로 알고 있는 상황에서는 를 사용하는 QuerySingle것이 좀 더 편리합니다.

특정 유형의 데이터베이스 작업을 수행하는 몇 가지 다른 방법이 있습니다. ASP.NET 웹 페이지 API 빠른 참조에서 데이터베이스 메서드 목록을 찾을 수 있습니다.

ID에 대한 유효성 검사를 보다 강력하게 만들기

페이지가 처음 실행되면 데이터베이스에서 해당 동영상을 가져올 수 있도록 쿼리 문자열에서 영화 ID를 가져옵니다. 이 코드를 사용하여 실제로 찾을 값이 있는지 확인했습니다.

if(!IsPost){
    if(!Request.QueryString["ID"].IsEmpty()){
        // Etc.
    }
}

이 코드를 사용하여 사용자가 영화 페이지에서 영화를 먼저 선택하지 않고 EditMovies 페이지로 이동하면 페이지에 사용자에게 친숙한 오류 메시지가 표시되도록 했습니다. (그렇지 않으면 사용자에게 혼동을 줄 수 있는 오류가 표시됩니다.)

그러나 이 유효성 검사는 매우 강력하지 않습니다. 다음과 같은 오류로 페이지가 호출될 수도 있습니다.

  • ID는 숫자가 아닙니다. 예를 들어 와 같은 http://localhost:nnnnn/EditMovie?id=abcURL을 사용하여 페이지를 호출할 수 있습니다.
  • ID는 숫자이지만 존재하지 않는 영화를 참조합니다(예: http://localhost:nnnnn/EditMovie?id=100934).

이러한 URL로 인해 발생하는 오류를 확인하려면 영화 페이지를 실행 합니다 . 편집할 동영상을 선택한 다음 EditMovie 페이지의 URL을 영문자 ID 또는 존재하지 않는 동영상의 ID가 포함된 URL로 변경합니다.

그렇다면 어떻게 해야 할까요? 첫 번째 수정 사항은 페이지에 전달된 ID일 뿐만 아니라 ID가 정수인지 확인하는 것입니다. 테스트의 코드를 !IsPost 다음 예제와 같이 변경합니다.

if(!IsPost){
    if(!Request.QueryString["ID"].IsEmpty() && Request.QueryString["ID"].IsInt()) {
       // Etc.

(논리적 AND)와 연결된 && 두 번째 조건을 IsEmpty 테스트에 추가했습니다.

Request.QueryString["ID"].IsInt()

ASP.NET 웹 페이지 프로그래밍 소개 자습서에서 문자 문자열을 다른 데이터 형식으로 변환하는 등의 AsBoolAsInt 메서드를 기억할 수 있습니다. IsInt 메서드(및 와 같은 IsBoolIsDateTime다른 메서드)는 비슷합니다. 그러나 실제로 변환을 수행하지 않고 문자열을 변환할 있는지 여부만 테스트합니다. 따라서 여기서는 기본적으로 쿼리 문자열 값을 정수로 변환할 수 있는 경우를 말합니다.

다른 잠재적인 문제는 존재하지 않는 영화를 찾는 것입니다. 동영상을 가져오는 코드는 다음 코드와 같습니다.

var row = db.QuerySingle(dbCommand, movieId);

실제 동영상에 movieId 해당하지 않는 메서드에 QuerySingle 값을 전달하면 아무 것도 반환되지 않으며 다음 문(예: title=row.Title)으로 인해 오류가 발생합니다.

다시 쉽게 수정할 수 있습니다. 메서드가 db.QuerySingle 결과를 반환하지 않으면 변수는 row null이 됩니다. 따라서 변수에서 값을 가져오기 전에 변수가 row null인지 여부를 검사 수 있습니다. 다음 코드는 개체에서 값을 row 가져오는 문 주위에 블록을 추가 if 합니다.

if(row != null) {
    title = row.Title;
    genre = row.Genre;
    year = row.Year;
}
else{
    Validation.AddFormError("No movie was found for that ID.");
}

이러한 두 가지 추가 유효성 검사 테스트를 사용하면 페이지가 더 방탄 상태가 됩니다. 이제 분기의 전체 코드는 !IsPost 다음 예제와 같습니다.

if(!IsPost){
    if(!Request.QueryString["ID"].IsEmpty() && Request.QueryString["ID"].IsInt()) {
        movieId = Request.QueryString["ID"];
        var db = Database.Open("WebPagesMovies");
        var dbCommand = "SELECT * FROM Movies WHERE ID = @0";
        var row = db.QuerySingle(dbCommand, movieId);

        if(row != null) {
            title = row.Title;
            genre = row.Genre;
            year = row.Year;
        }
        else {
            Validation.AddFormError("No movie was found for that ID.");
        }
    }
    else {
        Validation.AddFormError("No movie was selected.");
    }
}

이 작업은 블록에 적합 else 하다는 점에 다시 한 번 유의합니다. 테스트가 통과되지 않으면 블록은 else 오류 메시지를 설정합니다.

최종적이고 유용한 세부 정보는 영화 페이지에 링크를 다시 추가하는 것입니다. 이벤트의 일반적인 흐름에서 사용자는 영화 페이지에서 시작하여 편집 링크를 클릭합니다. 그러면 편집모비 페이지로 이동하여 영화를 편집하고 단추를 클릭할 수 있습니다. 코드가 변경 사항을 처리한 후 영화 페이지로 다시 리디렉션됩니다.

단,

  • 사용자는 아무것도 변경하지 않기로 결정할 수 있습니다.
  • 사용자가 영화 페이지에서 편집 링크를 먼저 클릭하지 않고 이 페이지로 이동했을 수 있습니다.

어느 쪽이든 기본 목록으로 쉽게 돌아갈 수 있도록 하고자 합니다. 쉽게 수정할 수 있습니다. 태그의 닫는 </form> 태그 바로 다음에 다음 태그를 추가합니다.

<p><a href="~/Movies">Return to movie listing</a></p>

이 태그는 다른 곳에서 본 요소에 <a> 대해 동일한 구문을 사용합니다. URL에는 "웹 사이트의 루트"를 의미하는 가 포함됩니다 ~ .

영화 업데이트 프로세스 테스트

이제 테스트할 수 있습니다. 영화 페이지를 실행하고 영화 옆에 있는 편집을 클릭합니다. EditMovie 페이지가 나타나면 동영상을 변경하고 변경 내용 제출을 클릭합니다. 동영상 목록이 표시되면 변경 내용이 표시되는지 확인합니다.

유효성 검사가 작동하는지 확인하려면 다른 동영상 에 대해 편집 을 클릭합니다. EditMovie 페이지로 이동하면 장르 필드(또는 연도 필드 또는 둘 다)를 지우고 변경 내용을 제출합니다. 다음과 같은 오류가 표시됩니다.

유효성 검사 오류를 보여 주는 동영상 편집 페이지

동영상 목록으로 돌아가기 링크를 클릭하여 변경 내용을 중단하고 영화 페이지로 돌아갑니다.

다음 출시 예정

다음 자습서에서는 영화 레코드를 삭제하는 방법을 알아보세요.

@{
    var db = Database.Open("WebPagesMovies") ;
    var selectCommand = "SELECT * FROM Movies";
    var searchTerm = "";

    if(!Request.QueryString["searchGenre"].IsEmpty() ) {
        selectCommand = "SELECT * FROM Movies WHERE Genre = @0";
        searchTerm = Request.QueryString["searchGenre"];
    }

    if(!Request.QueryString["searchTitle"].IsEmpty() ) {
        selectCommand = "SELECT * FROM Movies WHERE Title LIKE @0";
        searchTerm = "%" + Request.QueryString["searchTitle"] + "%";
    }

    var selectedData = db.Query(selectCommand, searchTerm);
    var grid = new WebGrid(source: selectedData, defaultSort: "Genre", rowsPerPage:3);
}

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <title>Movies</title>
        <style type="text/css">
          .grid { margin: 4px; border-collapse: collapse; width: 600px; }
          .grid th, .grid td { border: 1px solid #C0C0C0; padding: 5px; }
          .head { background-color: #E8E8E8; font-weight: bold; color: #FFF; }
          .alt { background-color: #E8E8E8; color: #000; }
        </style>
    </head>
    <body>
        <h1>Movies</h1>
          <form method="get">
              <div>
                <label for="searchGenre">Genre to look for:</label>
                <input type="text" name="searchGenre" value="@Request.QueryString["searchGenre"]" />
                <input type="Submit" value="Search Genre" /><br/>
                (Leave blank to list all movies.)<br/>
                </div>

              <div>
                  <label for="SearchTitle">Movie title contains the following:</label>
                  <input type="text" name="searchTitle" value="@Request.QueryString["searchTitle"]" />
                  <input type="Submit" value="Search Title" /><br/>
                </div>
            </form>

        <div>
             @grid.GetHtml(
                tableStyle: "grid",
                headerStyle: "head",
                alternatingRowStyle: "alt",
                columns: grid.Columns(
                    grid.Column(format: @<a href="~/EditMovie?id=@item.ID">Edit</a>),
                    grid.Column("Title"),
                    grid.Column("Genre"),
                    grid.Column("Year")
                )
            )
        </div>
    <p>
        <a href="~/AddMovie">Add a movie</a>
    </p>
    </body>
</html>

동영상 편집 페이지의 전체 페이지 목록

@{
    var title = "";
    var genre = "";
    var year = "";
    var movieId = "";

    if(!IsPost){
        if(!Request.QueryString["ID"].IsEmpty() && Request.QueryString["ID"].IsInt()) {
            movieId = Request.QueryString["ID"];
            var db = Database.Open("WebPagesMovies");
            var dbCommand = "SELECT * FROM Movies WHERE ID = @0";
            var row = db.QuerySingle(dbCommand, movieId);

            if(row != null) {
                title = row.Title;
                genre = row.Genre;
                year = row.Year;
            }
            else{
                Validation.AddFormError("No movie was selected.");
            }
        }
        else{
            Validation.AddFormError("No movie was selected.");
        }
    }

    if(IsPost){
        Validation.RequireField("title", "You must enter a title");
        Validation.RequireField("genre", "Genre is required");
        Validation.RequireField("year", "You haven't entered a year");
        Validation.RequireField("movieid", "No movie ID was submitted!");

        title = Request.Form["title"];
        genre = Request.Form["genre"];
        year = Request.Form["year"];
        movieId = Request.Form["movieId"];

        if(Validation.IsValid()){
            var db = Database.Open("WebPagesMovies");
            var updateCommand = "UPDATE Movies SET Title=@0, Genre=@1, Year=@2 WHERE Id=@3";
            db.Execute(updateCommand, title, genre, year, movieId);
            Response.Redirect("~/Movies");
        }
    }
}

<!DOCTYPE html>
<html>
  <head>
   <meta charset="utf-8" />
   <title>Edit a Movie</title>
    <style>
      .validation-summary-errors{
        border:2px dashed red;
        color:red;
        font-weight:bold;
        margin:12px;
      }
    </style>
  </head>
  <body>
    <h1>Edit a Movie</h1>
      @Html.ValidationSummary()
      <form method="post">
      <fieldset>
        <legend>Movie Information</legend>

        <p><label for="title">Title:</label>
           <input type="text" name="title" value="@title" /></p>

        <p><label for="genre">Genre:</label>
           <input type="text" name="genre" value="@genre" /></p>

        <p><label for="year">Year:</label>
           <input type="text" name="year" value="@year" /></p>

        <input type="hidden" name="movieid" value="@movieId" />

        <p><input type="submit" name="buttonSubmit" value="Submit Changes" /></p>
      </fieldset>
    </form>
    <p><a href="~/Movies">Return to movie listing</a></p>
  </body>
</html>

추가 리소스