ASP.NET 웹 페이지 소개 - 데이터베이스 데이터 삭제

Tom FitzMacken

이 자습서에서는 개별 데이터베이스 항목을 삭제하는 방법을 보여줍니다. ASP.NET 웹 페이지 데이터베이스 데이터 업데이트를 통해 시리즈를 완료한 것으로 가정합니다.

학습할 내용:

  • 레코드 목록에서 개별 레코드를 선택하는 방법입니다.
  • 데이터베이스에서 단일 레코드를 삭제하는 방법입니다.
  • 양식에서 특정 단추를 클릭했는지 검사 방법입니다.

설명된 기능/기술:

  • 도우미입니다 WebGrid .
  • SQL Delete 명령입니다.
  • Database.Execute SQL Delete 명령을 실행하는 메서드입니다.

만들 내용

이전 자습서에서는 기존 데이터베이스 레코드를 업데이트하는 방법을 알아보았습니다. 이 자습서는 레코드를 업데이트하는 대신 삭제한다는 점을 제외하고 비슷합니다. 삭제가 더 간단하다는 점을 제외하고 프로세스는 거의 동일하므로 이 자습서는 짧습니다.

영화 페이지에서 도우미를 WebGrid 업데이트하여 이전에 추가한 편집 링크와 함께 각 동영상 옆에 삭제 링크를 표시합니다.

각 동영상에 대한 삭제 링크를 보여 주는 영화 페이지

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

동영상이 표시된 영화 페이지 삭제

그런 다음 단추를 클릭하여 레코드를 영구적으로 삭제할 수 있습니다.

먼저 도우미에 삭제 링크를 추가합니다 WebGrid . 이 링크는 이전 자습서에서 추가한 편집 링크와 유사합니다.

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="~/DeleteMovie?id=@item.ID">Delete</a>)
    )
)

새 열은 다음과 같습니다.

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

그리드가 구성된 방식에서 편집 열은 표에서 맨 왼쪽에 있고 Delete 열은 맨 오른쪽에 있습니다. 열 다음에는 쉼표 Year 가 있습니다.) 이러한 링크 열이 어디로 가는지 에 대한 특별한 것은 없으며 쉽게 나란히 배치할 수 있습니다. 이 경우, 그들은 혼합하기 어렵게 만들기 위해 분리되어 있습니다.

편집 및 세부 정보 링크가 표시된 영화 페이지는 서로 옆에 있지 않음을 표시합니다.

새 열에는 텍스트가 "Delete"라고 표시된 링크(<a> 요소)가 표시됩니다. 링크의 대상(해당 href 특성)은 궁극적으로 각 동영상에 대해 값이 다른 이 URL과 id 같이 확인되는 코드입니다.

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

이 링크는 DeleteMovie 라는 페이지를 호출하고 선택한 영화의 ID를 전달합니다.

이 자습서는 이전 자습서(ASP.NET 웹 페이지 데이터베이스 데이터 업데이트)의 편집 링크와 거의 동일하기 때문에 이 링크가 생성되는 방법에 대해 자세히 설명하지 않습니다.

삭제 페이지 만들기

이제 표에서 삭제 링크의 대상이 될 페이지를 만들 수 있습니다.

참고

중요 먼저 삭제할 레코드를 선택한 다음 별도의 페이지와 단추를 사용하여 프로세스를 확인하는 기술은 보안에 매우 중요합니다. 이전 자습서에서 읽은 것처럼 웹 사이트를 변경하는 작업은항상 HTTP POST 작업을 사용하여 양식을 사용하여 수행해야 합니다. 링크를 클릭하는 것만으로 사이트를 변경할 수 있는 경우(즉, GET 작업을 사용하여) 사용자가 사이트에 대한 간단한 요청을 수행하고 데이터를 삭제할 수 있습니다. 사이트를 인덱싱하는 검색 엔진 크롤러조차도 링크를 따라 실수로 데이터를 삭제할 수 있습니다.

앱에서 사용자가 레코드를 변경할 수 있는 경우 편집을 위해 레코드를 사용자에게 표시해야 합니다. 그러나 레코드를 삭제하기 위해 이 단계를 건너뛰려는 유혹이 있을 수 있습니다. 하지만 해당 단계를 건너뛰지 마세요. (사용자가 레코드를 보고 의도한 레코드를 삭제하고 있는지 확인하는 것도 유용합니다.)

후속 자습서 집합에서는 사용자가 레코드를 삭제하기 전에 로그인해야 하므로 로그인 기능을 추가하는 방법을 확인할 수 있습니다.

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

<html>
<head>
  <title>Delete a Movie</title>
</head>
<body>
      <h1>Delete a Movie</h1>
        @Html.ValidationSummary()
      <p><a href="~/Movies">Return to movie listing</a></p>

      <form method="post">
        <fieldset>
        <legend>Movie Information</legend>

        <p><span>Title:</span>
         <span>@title</span></p>

        <p><span>Genre:</span>
         <span>@genre</span></p>

        <p><span>Year:</span>
          <span>@year</span></p>

        <input type="hidden" name="movieid" value="@movieId" />
        <p><input type="submit" name="buttonDelete" value="Delete Movie" /></p>
        </fieldset>
      </form>
    </body>
</html>

이 태그는 텍스트 상자()<input type="text">를 사용하는 대신 태그에 요소가 포함되어 <span> 있다는 점을 제외하고 EditMovie 페이지와 같습니다. 편집할 항목은 없습니다. 사용자가 올바른 동영상을 삭제하고 있는지 확인할 수 있도록 영화 세부 정보를 표시하기만 하면 됩니다.

태그에는 사용자가 영화 목록 페이지로 돌아갈 수 있는 링크가 이미 포함되어 있습니다.

EditMovie 페이지에서와 같이 선택한 동영상의 ID는 숨겨진 필드에 저장됩니다. (처음에 쿼리 문자열 값으로 페이지에 전달됩니다.) Html.ValidationSummary 유효성 검사 오류를 표시하는 호출이 있습니다. 이 경우 페이지에 영화 ID가 전달되지 않거나 영화 ID가 잘못되었을 수 있습니다. 이 상황은 누군가가 영화 페이지에서 영화를 먼저 선택하지 않고 이 페이지를 실행한 경우에 발생할 수 있습니다.

캡션 단추는 영화 삭제이고 이름 특성은 로 buttonDelete설정됩니다. 특성은 name 코드에서 양식을 제출한 단추를 식별하는 데 사용됩니다.

1에 코드를 작성해야 합니다. 페이지가 처음 표시될 때 동영상 세부 정보를 읽고 2) 사용자가 단추를 클릭할 때 실제로 동영상을 삭제합니다.

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

DeleteMovie.cshtml 페이지의 맨 위에 다음 코드 블록을 추가합니다.

@{
    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 found for that ID.");
            }
        }
        else{
            Validation.AddFormError("No movie was found for that ID.");
        }
    }
}

이 태그는 EditMovie 페이지의 해당 코드와 동일합니다. 쿼리 문자열에서 동영상 ID를 가져오고 ID를 사용하여 데이터베이스에서 레코드를 읽습니다. 이 코드에는 페이지에 전달되는 영화 ID가 유효한지 확인하기 위한 유효성 검사 테스트(IsInt()row != null)가 포함되어 있습니다.

이 코드는 페이지를 처음 실행할 때만 실행해야 합니다. 사용자가 영화 삭제 단추를 클릭할 때 데이터베이스에서 영화 레코드를 다시 읽지 않으려는 경우 따라서 영화를 읽는 코드는 테스트 내에 있습니다. 즉, 요청이 if(!IsPost)사후 작업(양식 제출)이 아닌 경우 입니다.

선택한 동영상을 삭제하는 코드 추가

사용자가 단추를 클릭할 때 동영상을 삭제하려면 블록의 @ 닫는 중괄호 안에 다음 코드를 추가합니다.

if(IsPost && !Request["buttonDelete"].IsEmpty()){
    movieId = Request.Form["movieId"];
    var db = Database.Open("WebPagesMovies");
    var deleteCommand = "DELETE FROM Movies WHERE ID = @0";
    db.Execute(deleteCommand, movieId);
    Response.Redirect("~/Movies");
}

이 코드는 기존 레코드를 업데이트하기 위한 코드와 비슷하지만 더 간단합니다. 코드는 기본적으로 SQL Delete 문을 실행합니다.

EditMovie 페이지에서와 같이 코드는 블록에 있습니다if(IsPost). 이번에는 if() 조건이 좀 더 복잡합니다.

if(IsPost && !Request["buttonDelete"].IsEmpty())

여기에는 두 가지 조건이 있습니다. 첫 번째는 이전에 if(IsPost)보았듯이 페이지가 제출되고 있다는 것입니다.

두 번째 조건은 입니다. !Request["buttonDelete"].IsEmpty()즉, 요청에 라는 buttonDelete개체가 있습니다. 단, 양식을 제출한 단추를 테스트하는 간접적인 방법입니다. 양식에 여러 제출 단추가 포함된 경우 클릭한 단추의 이름만 요청에 표시됩니다. 따라서 논리적으로 특정 단추의 이름이 요청에 표시되거나 코드에 설명된 대로 해당 단추가 비어 있지 않은 경우 폼을 제출한 단추입니다.

연산자는 && "and"(논리적 AND)를 의미합니다. 따라서 전체 if 조건은 ...

이 요청은 게시물입니다(처음 요청이 아님).

AND

TthebuttonDelete단추는 양식을 제출한 단추였습니다.

이 양식(사실 이 페이지)에는 단추가 하나만 포함되어 있으므로 에 대한 buttonDelete 추가 테스트는 기술적으로 필요하지 않습니다. 그래도 데이터를 영구적으로 제거하는 작업을 수행하려고 합니다. 따라서 사용자가 명시적으로 요청한 경우에만 작업을 수행하는지 최대한 확신하려고 합니다. 예를 들어 나중에 이 페이지를 확장하고 다른 단추를 추가했다고 가정해 보겠습니다. 그럼에도 불구하고 동영상을 삭제하는 코드는 단추를 클릭한 경우에만 buttonDelete 실행됩니다.

EditMovie 페이지에서와 같이 숨겨진 필드에서 ID를 가져오고 SQL 명령을 실행합니다. 문의 구문 Delete 은 다음과 같습니다.

DELETE FROM table WHERE ID = value

절과 ID를 WHERE 포함해야 합니다. WHERE 절을 제외하면 테이블의 모든 레코드가 삭제됩니다. 본 것처럼 자리 표시자를 사용하여 SQL 명령에 ID 값을 전달합니다.

동영상 삭제 프로세스 테스트

이제 테스트할 수 있습니다. 영화 페이지를 실행하고 영화 옆에 있는 삭제를 클릭합니다. DeleteMovie 페이지가 나타나면 영화 삭제를 클릭합니다.

동영상 삭제 단추가 강조 표시된 영화 삭제 페이지

단추를 클릭하면 코드가 영화를 삭제하고 영화 목록으로 돌아갑니다. 삭제된 동영상을 검색하여 삭제되었는지 확인할 수 있습니다.

다음 출시 예정

다음 자습서에서는 사이트의 모든 페이지에 일반적인 모양과 레이아웃을 제공하는 방법을 보여 줍니다.

@{
    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"),
                grid.Column(format: @<a href="~/DeleteMovie?id=@item.ID">Delete</a>)
            )
        )
      </div>
      <p>
        <a href="~/AddMovie">Add a movie</a>
      </p>
    </body>
</html>

DeleteMovie 페이지에 대한 전체 목록

@{
    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 found for that ID.");
            }
        }
        else{
            Validation.AddFormError("No movie was found for that ID.");
        }
    }

    if(IsPost && !Request["buttonDelete"].IsEmpty()){
        movieId = Request.Form["movieId"];
        var db = Database.Open("WebPagesMovies");
        var deleteCommand = "DELETE FROM Movies WHERE ID = @0";
        db.Execute(deleteCommand, movieId);
        Response.Redirect("~/Movies");
    }
}
<html>
<head>
  <title>Delete a Movie</title>
</head>
<body>
      <h1>Delete a Movie</h1>
        @Html.ValidationSummary()
      <p><a href="~/Movies">Return to movie listing</a></p>

      <form method="post">
        <fieldset>
        <legend>Movie Information</legend>

        <p><span>Title:</span>
         <span>@title</span></p>

        <p><span>Genre:</span>
         <span>@genre</span></p>

        <p><span>Year:</span>
          <span>@year</span></p>

        <input type="hidden" name="movieid" value="@movieId" />
        <p><input type="submit" name="buttonDelete" value="Delete Movie" /></p>
        </fieldset>
        <p><a href="~/Movies">Return to movie listing</a></p>
      </form>
    </body>
</html>

추가 리소스