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 :
Po kliknięciu linku Edytuj następuje przejście do innej strony, na której informacje o filmie są już w formularzu:
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.
Dodawanie linku edycji do listy filmów
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.Title
wartości , item.Genre
lub 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 post
wartość . 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:
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 AsBool
AsInt
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.
Dodawanie linku w celu powrotu do strony filmów
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ć:
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.
Kompletna lista dla strony filmu (zaktualizowana przy użyciu linków edycji)
@{
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>