Udostępnij za pośrednictwem


Wprowadzenie ASP.NET stron sieci Web — aktualizowanie danych bazy danych

– autor Tom FitzMacken

W tym samouczku pokazano, jak zaktualizować (zmienić) istniejący wpis bazy danych podczas korzystania z ASP.NET Web Pages (Razor). Założono, że seria została ukończona za pomocą wprowadzania danych przy użyciu formularzy using ASP.NET Web Pages.

Zawartość:

  • Jak wybrać pojedynczy rekord w pomocniku WebGrid .
  • Jak odczytać pojedynczy rekord z bazy danych.
  • Jak wstępnie załadować formularz z wartościami z rekordu bazy danych.
  • Jak zaktualizować istniejący rekord w bazie danych.
  • Sposób przechowywania informacji na stronie bez wyświetlania ich.
  • Jak używać ukrytego pola do przechowywania informacji.

Omówione funkcje/technologie:

  • Pomocnik WebGrid .
  • Polecenie SQL Update .
  • Metoda Database.Execute .
  • Ukryte pola (<input type="hidden">).

Co utworzysz

W poprzednim samouczku przedstawiono sposób dodawania rekordu do bazy danych. Tutaj dowiesz się, jak wyświetlić rekord do edycji. Na stronie Filmy zaktualizujesz WebGrid pomocnika tak, aby obok każdego filmu był wyświetlany link Edytuj :

Wyświetlanie usługi WebGrid, w tym link

Po kliknięciu linku Edytuj następuje przejście do innej strony, na której informacje o filmie są już w formularzu:

Edytuj stronę Film pokazującą film do edycji

Możesz zmienić dowolną z wartości. Po przesłaniu zmian kod na stronie aktualizuje bazę danych i wraca do listy filmów.

Ta część procesu działa niemal dokładnie tak samo jak strona AddWięcej.cshtml utworzona w poprzednim samouczku, więc większość tego samouczka będzie znana.

Istnieje kilka sposobów implementacji sposobu edytowania pojedynczego filmu. Pokazano podejście zostało wybrane, ponieważ jest łatwe do zaimplementowania i łatwe do zrozumienia.

Aby rozpocząć, zaktualizujesz stronę Filmy , aby każda lista filmów zawierała również link Edytuj .

Otwórz plik Movies.cshtml .

W treści strony zmień znaczniki WebGrid , dodając kolumnę. Oto zmodyfikowany znacznik:

@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")
    )
)

Nowa kolumna to ta:

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

Punktem tej kolumny jest wyświetlenie linku (<a> elementu), którego tekst to "Edit" (Edytuj). Po wykonaniu tej czynności utworzymy link podobny do poniższego po uruchomieniu strony z wartością id inną dla każdego filmu:

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

Ten link wywoła stronę o nazwie EditHub i przekaże ciąg ?id=7 zapytania do tej strony.

Składnia nowej kolumny może wydawać się nieco złożona, ale jest to tylko dlatego, że łączy kilka elementów. Każdy pojedynczy element jest prosty. Jeśli skoncentrujesz się tylko na elemecie <a> , zobaczysz ten znacznik:

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

Niektóre tło dotyczące działania siatki: siatka wyświetla wiersze, jeden dla każdego rekordu bazy danych i wyświetla kolumny dla każdego pola w rekordzie bazy danych. Podczas konstruowania item każdego wiersza siatki obiekt zawiera rekord bazy danych (element) dla tego wiersza. Takie rozmieszczenie umożliwia pobranie danych w kodzie dla tego wiersza. Oto, co widzisz: wyrażenie item.ID otrzymuje wartość IDENTYFIKATORa bieżącego elementu bazy danych. Możesz uzyskać dowolną z wartości bazy danych (tytuł, gatunek lub rok) w taki sam sposób, używając item.Titlewartości , item.Genrelub item.Year.

"~/EditMovie?id=@item.ID Wyrażenie łączy zakodowaną część docelowego adresu URL (~/EditMovie?id=) z tym dynamicznie pochodnym identyfikatorem. (Operator został ~ wyświetlony w poprzednim samouczku; jest to operator ASP.NET reprezentujący bieżący katalog główny witryny internetowej).

Wynikiem jest to, że ta część znaczników w kolumnie po prostu generuje coś podobnego do następującego znacznika w czasie wykonywania:

href="/EditMovie?id=2"

Oczywiście rzeczywista wartość id będzie inna dla każdego wiersza.

Tworzenie niestandardowego wyświetlania dla kolumny siatki

Teraz wróć do kolumny siatki. Trzy kolumny pierwotnie w siatce zawierały tylko wartości danych (tytuł, gatunek i rok). Określono ten ekran, przekazując nazwę kolumny bazy danych — na przykład grid.Column("Title").

Ta nowa kolumna linku Edytuj jest inna. Zamiast określać nazwę kolumny, przekazujesz format parametr. Ten parametr pozwala zdefiniować znaczniki, które WebGrid pomocnik będzie renderowany wraz z wartością item , aby wyświetlić dane kolumny jako pogrubione lub zielone lub w żądanym formacie. Jeśli na przykład chcesz, aby tytuł był wyświetlany pogrubioną, możesz utworzyć kolumnę podobną do poniższego przykładu:

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

(Różne @ znaki widoczne we format właściwości oznaczają przejście między adiustacjami a wartością kodu).

Po zapoznaniu się z format właściwością łatwiej jest zrozumieć, jak nowa kolumna linku Edytuj jest ułożona:

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

Kolumna składa się tylko z znaczników renderujących link oraz niektóre informacje (identyfikator) wyodrębnione z rekordu bazy danych dla wiersza.

Porada

Nazwane parametry i parametry pozycyjne dla metody

Wiele razy, gdy wywołano metodę i przekazano do niej parametry, po prostu wymieniono wartości parametrów rozdzielone przecinkami. Oto kilka przykładów:

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

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

Nie wspomnieliśmy o problemie, gdy po raz pierwszy został wyświetlony ten kod, ale w każdym przypadku przekazujesz parametry do metod w określonej kolejności — czyli kolejności, w jakiej parametry są zdefiniowane w tej metodzie. W przypadku db.Execute elementów i Validation.RequireFields, jeśli pomieszasz kolejność przekazywanych wartości, podczas uruchamiania strony zostanie wyświetlony komunikat o błędzie lub co najmniej kilka dziwnych wyników. Oczywiście musisz znać kolejność przekazywania parametrów. (W programie WebMatrix funkcja IntelliSense może ułatwić poznanie nazwy, typu i kolejności parametrów).

Alternatywą dla przekazywania wartości w kolejności jest użycie nazwanych parametrów. (Przekazywanie parametrów w kolejności jest nazywane używaniem parametrów pozycyjnych). W przypadku nazwanych parametrów jawnie dołączasz nazwę parametru podczas przekazywania jego wartości. W tych samouczkach użyto już nazwanych parametrów. Na przykład:

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

oraz

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

Nazwane parametry są przydatne w kilku sytuacjach, zwłaszcza gdy metoda przyjmuje wiele parametrów. Jednym z nich jest przekazanie tylko jednego lub dwóch parametrów, ale wartości, które chcesz przekazać, nie należą do pierwszych pozycji na liście parametrów. Inną sytuacją jest to, że chcesz, aby kod był bardziej czytelny, przekazując parametry w kolejności, która jest dla Ciebie najbardziej zrozumiała.

Oczywiście, aby użyć nazwanych parametrów, musisz znać nazwy parametrów. Funkcja IntelliSense programu WebMatrix może wyświetlać nazwy, ale obecnie nie może ich wypełnić.

Tworzenie strony edycji

Teraz możesz utworzyć stronę Edit EdytowanieModuł . Gdy użytkownicy klikną link Edytuj , trafią na tę stronę.

Utwórz stronę o nazwie Edit Zamienić pliki w pliku na następujące znaczniki:

<!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>

Ten kod i adiustacja są podobne do tego, co znajduje się na stronie AddKodzie . Istnieje niewielka różnica w tekście przycisku przesyłania. Podobnie jak na stronieAdda , istnieje Html.ValidationSummary wywołanie, które spowoduje wyświetlenie błędów walidacji, jeśli istnieją. Tym razem pomijamy wywołania funkcji Validation.Message, ponieważ błędy będą wyświetlane w podsumowaniu weryfikacji. Jak wspomniano w poprzednim samouczku, możesz użyć podsumowania weryfikacji i poszczególnych komunikatów o błędach w różnych kombinacjach.

Zwróć uwagę, że method atrybut <form> elementu jest ustawiony na postwartość . Podobnie jak na stronie AddRabia.cshtml , ta strona wprowadza zmiany w bazie danych. W związku z tym ten formularz powinien wykonać operację POST . (Aby uzyskać więcej informacji na temat różnic między operacjami GET i POST , zobacz pasek boczny GET, POST i HTTP Verb Safety w samouczku dotyczącym formularzy HTML).

Jak pokazano we wcześniejszym samouczku, value atrybuty pól tekstowych są ustawiane przy użyciu kodu Razor w celu ich wstępnego załadowania. Tym razem jednak używasz zmiennych takich jak title i genre dla tego zadania zamiast Request.Form["title"]:

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

Tak jak wcześniej ta adiustacja spowoduje wstępne załadowanie wartości pól tekstowych z wartościami filmu. Zobaczysz w chwili, dlaczego warto używać zmiennych tym razem zamiast używać Request obiektu .

Na tej stronie znajduje się również <input type="hidden"> element. Ten element przechowuje identyfikator filmu bez uwidaczniania go na stronie. Identyfikator jest początkowo przekazywany do strony przy użyciu wartości ciągu zapytania (?id=7 lub podobnego w adresie URL). Umieszczając wartość identyfikatora w polu ukrytym, możesz upewnić się, że jest ona dostępna po przesłaniu formularza, nawet jeśli nie masz już dostępu do oryginalnego adresu URL wywoływanego przez stronę.

W przeciwieństwie do strony Add Moduł , kod strony Edit Page Ma dwie odrębne funkcje. Pierwsza funkcja polega na tym, że gdy strona jest wyświetlana po raz pierwszy (a dopiero wtedy), kod pobiera identyfikator filmu z ciągu zapytania. Następnie kod używa identyfikatora do odczytywania odpowiedniego filmu z bazy danych i wyświetlania go (wstępnego ładowania) w polach tekstowych.

Druga funkcja polega na tym, że gdy użytkownik kliknie przycisk Prześlij zmiany , kod musi odczytać wartości pól tekstowych i zweryfikować je. Kod musi również zaktualizować element bazy danych przy użyciu nowych wartości. Ta technika jest podobna do dodawania rekordu, jak pokazano w elem.

Dodawanie kodu do odczytywania pojedynczego filmu

Aby wykonać pierwszą funkcję, dodaj ten kod w górnej części strony:

@{
    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.");
        }
    }
}

Większość tego kodu znajduje się wewnątrz bloku, który uruchamia element if(!IsPost). Operator ! oznacza "nie", więc wyrażenie oznacza, że jeśli to żądanie nie jest przesyłaniem pośrednim, czyli pośrednim sposobem powiedzenia , czy to żądanie jest pierwszym uruchomieniem tej strony. Jak wspomniano wcześniej, ten kod powinien być uruchamiany tylko przy pierwszym uruchomieniu strony. Jeśli kod nie został ujęta w if(!IsPost)element , będzie uruchamiany za każdym razem, gdy strona jest wywoływana, czy to po raz pierwszy, czy w odpowiedzi na kliknięcie przycisku.

Zwróć uwagę, że kod zawiera else blok tym razem. Jak mówiliśmy podczas wprowadzania if bloków, czasami chcesz uruchomić alternatywny kod, jeśli testowy warunek nie jest spełniony. Tak jest tutaj. Jeśli warunek przebiegnie (oznacza to, że jeśli identyfikator przekazany do strony jest ok), odczytasz wiersz z bazy danych. Jeśli jednak warunek nie zostanie przekazany, blok zostanie uruchomiony, else a kod ustawi komunikat o błędzie.

Weryfikowanie wartości przekazanej do strony

Kod używa Request.QueryString["id"] metody w celu pobrania identyfikatora przekazanego do strony. Kod zapewnia, że wartość została rzeczywiście przekazana dla identyfikatora. Jeśli żadna wartość nie została przekazana, kod ustawia błąd weryfikacji.

Ten kod przedstawia inny sposób weryfikacji informacji. W poprzednim samouczku współpracowaliśmy z pomocnikiem Validation . Zarejestrowano pola w celu zweryfikowania, a ASP.NET automatycznie wykonać walidację i wyświetlić błędy przy użyciu narzędzi Html.ValidationMessage i Html.ValidationSummary. W takim przypadku jednak nie walidujesz danych wejściowych użytkownika. Zamiast tego walidujesz wartość, która została przekazana do strony z innego miejsca. Pomocnik Validation nie robi tego za Ciebie.

W związku z tym sprawdzasz wartość samodzielnie, testując ją przy użyciu polecenia if(!Request.QueryString["ID"].IsEmpty()). Jeśli wystąpi problem, możesz wyświetlić błąd przy użyciu polecenia Html.ValidationSummary, tak jak w przypadku Validation pomocnika. Aby to zrobić, należy wywołać Validation.AddFormError polecenie i przekazać komunikat do wyświetlenia. Validation.AddFormError to wbudowana metoda, która umożliwia definiowanie niestandardowych komunikatów, które wiążą się z systemem weryfikacji, który już znasz. (W dalszej części tego samouczka omówimy, jak sprawić, aby ten proces weryfikacji był nieco bardziej niezawodny).

Po upewnieniu się, że istnieje identyfikator filmu, kod odczytuje bazę danych, szukając tylko jednego elementu bazy danych. (Prawdopodobnie zauważono ogólny wzorzec operacji bazy danych: otwórz bazę danych, zdefiniuj instrukcję SQL i uruchom instrukcję ). Tym razem instrukcja SQL Select zawiera element WHERE ID = @0. Ponieważ identyfikator jest unikatowy, można zwrócić tylko jeden rekord.

Zapytanie jest wykonywane przy użyciu metody db.QuerySingle (nie db.Query, jak użyto na potrzeby listy filmów), a kod umieszcza wynik w zmiennej row . Nazwa row jest dowolna. Możesz nadać zmienne dowolną nazwę. Zmienne zainicjowane u góry są następnie wypełniane szczegółami filmu, dzięki czemu te wartości mogą być wyświetlane w polach tekstowych.

Testowanie strony edycji (do tej pory)

Jeśli chcesz przetestować stronę, uruchom teraz stronę Filmy i kliknij link Edytuj obok dowolnego filmu. Zostanie wyświetlona stronaEdita editzna z wypełnionymi szczegółami dla wybranego filmu:

Zrzut ekranu przedstawiający stronę Edytowanie filmu z filmem do edycji.

Zwróć uwagę, że adres URL strony zawiera coś takiego jak ?id=10 (lub inny numer). Do tej pory przetestowano, że funkcja Edytuj łącza w obszarze Strona filmowa działa, że strona odczytuje identyfikator z ciągu zapytania i że zapytanie bazy danych w celu pobrania pojedynczego rekordu filmu działa.

Możesz zmienić informacje o filmie, ale nic się nie dzieje po kliknięciu przycisku Prześlij zmiany.

Dodawanie kodu w celu zaktualizowania filmu za pomocą zmian użytkownika

W pliku EditProduct.cshtml , aby zaimplementować drugą funkcję (zapisywanie zmian), dodaj następujący kod tuż wewnątrz zamykającego nawiasu klamrowego @ bloku. (Jeśli nie masz pewności, gdzie umieścić kod, możesz przyjrzeć się pełnej liście kodu dla strony Edytuj film , która zostanie wyświetlona na końcu tego samouczka).

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");
   }
}

Ponownie ten kod i adiustacja są podobne do kodu w addKodzie. Kod znajduje się w if(IsPost) bloku, ponieważ ten kod jest uruchamiany tylko wtedy, gdy użytkownik kliknie przycisk Prześlij zmiany , czyli wtedy (i tylko wtedy), gdy formularz został opublikowany. W takim przypadku nie używasz testu, takiego jak if(IsPost && Validation.IsValid())— oznacza to, że nie łączysz obu testów przy użyciu funkcji AND. Na tej stronie najpierw określisz, czy istnieje przesyłanie formularza (if(IsPost)), a następnie zarejestrujesz pola w celu weryfikacji. Następnie możesz przetestować wyniki weryfikacji (if(Validation.IsValid()). Przepływ jest nieco inny niż na stronie AddHtml.cshtml , ale efekt jest taki sam.

Wartości pól tekstowych są uzyskiwane przy użyciu kodu Request.Form["title"] i podobnego kodu dla innych <input> elementów. Zwróć uwagę, że tym razem kod pobiera identyfikator filmu z ukrytego pola (<input type="hidden">). Gdy strona została uruchomiona po raz pierwszy, kod dostał identyfikator z ciągu zapytania. Uzyskasz wartość z pola ukrytego, aby upewnić się, że otrzymujesz identyfikator filmu, który został pierwotnie wyświetlony, na wypadek, gdy ciąg zapytania został w jakiś sposób zmieniony od tego czasu.

Naprawdę ważną różnicą między kodem Add Dziękuję a tym kodem jest to, że w tym kodzie używasz instrukcji SQL Update zamiast instrukcji Insert Into . Poniższy przykład przedstawia składnię instrukcji SQL Update :

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

Można określić dowolne kolumny w dowolnej kolejności i niekoniecznie trzeba aktualizować każdą kolumnę Update podczas operacji. (Nie można zaktualizować samego identyfikatora, ponieważ spowodowałoby to zapisanie rekordu jako nowego rekordu i nie jest to dozwolone dla Update operacji).

Uwaga

Ważne Klauzula Where o identyfikatorze jest bardzo ważna, ponieważ w ten sposób baza danych wie, który rekord bazy danych chcesz zaktualizować. Jeśli klauzula Where została przerwana, baza danych będzie aktualizować każdy rekord w bazie danych. W większości przypadków byłoby to katastrofą.

W kodzie wartości do aktualizacji są przekazywane do instrukcji SQL przy użyciu symboli zastępczych. Aby powtórzyć to, co powiedzieliśmy wcześniej: ze względów bezpieczeństwa użyj tylko symboli zastępczych, aby przekazać wartości do instrukcji SQL.

Po użyciu db.Execute kodu do uruchomienia instrukcji Update nastąpi przekierowanie z powrotem do strony listy, gdzie można zobaczyć zmiany.

Porada

Różne instrukcje SQL, różne metody

Być może zauważyliśmy, że do uruchamiania różnych instrukcji SQL używasz nieco różnych metod. Aby uruchomić Select zapytanie, które potencjalnie zwraca wiele rekordów, należy użyć Query metody . Aby uruchomić Select zapytanie, które wiadomo, zwróci tylko jeden element bazy danych, należy użyć QuerySingle metody . Aby uruchomić polecenia, które wprowadzają zmiany, ale nie zwracają elementów bazy danych, należy użyć Execute metody .

Musisz mieć różne metody, ponieważ każda z nich zwraca różne wyniki, jak pokazano już w różnicy między Query i QuerySingle. (Metoda Execute rzeczywiście zwraca wartość również — a mianowicie liczbę wierszy bazy danych, których dotyczyło polecenie — ale do tej pory ignorowano to).

Oczywiście Query metoda może zwracać tylko jeden wiersz bazy danych. Jednak ASP.NET zawsze traktuje wyniki Query metody jako kolekcję. Nawet jeśli metoda zwraca tylko jeden wiersz, musisz wyodrębnić ten pojedynczy wiersz z kolekcji. W związku z tym w sytuacjach, w których wiesz, że wrócisz tylko jeden wiersz, jest to nieco wygodniejsze w użyciu .QuerySingle

Istnieje kilka innych metod, które wykonują określone typy operacji bazy danych. Listę metod bazy danych można znaleźć w skróconym dokumentacji interfejsu API stron internetowych ASP.NET.

Tworzenie walidacji dla identyfikatora bardziej niezawodne

Przy pierwszym uruchomieniu strony otrzymasz identyfikator filmu z ciągu zapytania, aby można było pobrać ten film z bazy danych. Upewniono się, że rzeczywiście istnieje wartość do wyszukania, którą wykonano przy użyciu tego kodu:

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

Użyto tego kodu, aby upewnić się, że jeśli użytkownik dostanie się do strony EditRobis bez uprzedniego wybrania filmu na stronie Filmy , na stronie będzie wyświetlany przyjazny dla użytkownika komunikat o błędzie. (W przeciwnym razie użytkownicy zobaczą błąd, który prawdopodobnie po prostu je pomyli).

Jednak ta walidacja nie jest bardzo niezawodna. Strona może być również wywoływana z następującymi błędami:

  • Identyfikator nie jest liczbą. Na przykład można wywołać stronę przy użyciu adresu URL, takiego jak http://localhost:nnnnn/EditMovie?id=abc.
  • Identyfikator jest liczbą, ale odwołuje się do filmu, który nie istnieje (na przykład http://localhost:nnnnn/EditMovie?id=100934).

Jeśli chcesz zobaczyć błędy wynikające z tych adresów URL, uruchom stronę Filmy . Wybierz film do edycji, a następnie zmień adres URL strony EditPrzedaży na adres URL zawierający identyfikator alfabetyczny lub identyfikator nieistniejącego filmu.

Więc co należy zrobić? Pierwszą poprawką jest upewnienie się, że nie tylko identyfikator został przekazany do strony, ale identyfikator jest liczbą całkowitą. Zmień kod !IsPost testu, aby wyglądał jak w tym przykładzie:

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

Dodano drugi warunek do IsEmpty testu połączony z elementem && (logiczny AND):

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

Możesz pamiętać z samouczka Wprowadzenie do ASP.NET programowania stron internetowych , który metody takie jak AsBoolAsInt konwertowanie ciągu znaków na inny typ danych. Metoda (i inne, takie jak IsBool i IsDateTime) jest podobnaIsInt. Jednak testują tylko, czy można przekonwertować ciąg bez faktycznego wykonania konwersji. W tym miejscu zasadniczo mówisz , że jeśli wartość ciągu zapytania może zostać przekonwertowana na liczbę całkowitą ....

Innym potencjalnym problemem jest szukanie filmu, który nie istnieje. Kod pobierania filmu wygląda następująco:

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

Jeśli przekażesz movieId wartość do QuerySingle metody, która nie odpowiada rzeczywistemu filmowi, nic nie zostanie zwrócone, a następujące instrukcje (na przykład title=row.Title) spowodują błędy.

Ponownie jest łatwa poprawka. db.QuerySingle Jeśli metoda nie zwraca żadnych wyników, zmienna row będzie mieć wartość null. Dzięki temu można sprawdzić, czy zmienna row ma wartość null, zanim spróbujesz pobrać z niej wartości. Poniższy kod dodaje if blok wokół instrukcji, które pobierają wartości z row obiektu:

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

Dzięki tym dwóm dodatkowym testom weryfikacyjnym strona staje się bardziej kuloodporna. Kompletny kod gałęzi !IsPost wygląda teraz następująco:

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.");
    }
}

Po raz kolejny zauważymy, że to zadanie jest dobrym rozwiązaniem w przypadku else bloku. Jeśli testy nie przejdą, else bloki ustawiają komunikaty o błędach.

Ostatnim i przydatnym szczegółem jest dodanie linku z powrotem do strony Filmy . W zwykłym przepływie zdarzeń użytkownicy będą uruchamiać się na stronie Filmy i kliknąć link Edytuj . Spowoduje to przeniesienie ich na stronę EditDziuki , na której można edytować film i kliknąć przycisk. Gdy kod przetworzy zmianę, nastąpi przekierowanie z powrotem do strony Filmy .

Jednak:

  • Użytkownik może zdecydować się nie zmieniać niczego.
  • Użytkownik mógł uzyskać dostęp do tej strony bez uprzedniego kliknięcia linku Edytuj na stronie Filmy .

Tak czy inaczej, chcesz ułatwić im powrót do głównej listy. Jest to łatwa poprawka — dodaj następujący znacznik tuż po tagu zamykającym </form> w znaczniku:

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

Ta adiustacja używa tej samej składni dla <a> elementu, który był widziany gdzie indziej. Adres URL zawiera ~ wartość "katalogu głównego witryny internetowej".

Testowanie procesu aktualizacji filmu

Teraz możesz przetestować. Uruchom stronę Filmy i kliknij przycisk Edytuj obok filmu. Po wyświetleniu strony EditRobienie wprowadź zmiany w filmie i kliknij pozycję Prześlij zmiany. Po wyświetleniu listy filmów upewnij się, że zmiany są wyświetlane.

Aby upewnić się, że walidacja działa, kliknij przycisk Edytuj dla innego filmu. Po wyświetleniu stronyEditeji wyczyść pole Gatunek (lub pole Year lub oba te elementy) i spróbuj przesłać zmiany. Zobaczysz błąd, jak można się spodziewać:

Edytowanie strony filmowej z błędami walidacji

Kliknij link Wróć do listy filmów , aby porzucić zmiany i wrócić do strony Filmy .

Najbliższych następnych

W następnym samouczku zobaczysz, jak usunąć rekord filmu.

@{
    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>

Ukończ listę stron edycji strony filmu

@{
    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>

Dodatkowe zasoby