Introducción a la actualización de datos de base de datos de ASP.NET Web Pages

por Tom FitzMacken

En este tutorial se muestra cómo actualizar (cambiar) una entrada de base de datos existente cuando se usa ASP.NET Web Pages (Razor). Se supone que ha completado la serie a través de la especificación de datos mediante el uso de formularios ASP.NET Web pages.

Temas que se abordarán:

  • Cómo seleccionar un registro individual en la aplicación auxiliar de WebGrid.
  • Cómo leer un solo registro de una base de datos.
  • Cómo cargar previamente un formulario con valores del registro de base de datos.
  • Cómo actualizar un registro existente en una base de datos.
  • Cómo almacenar información en la página sin mostrarla.
  • Cómo usar un campo oculto para almacenar información.

Características y tecnologías descritas:

  • Aplicación auxiliar de WebGrid.
  • Comando de SQL Update.
  • El método Database.Execute .
  • Campos ocultos (<input type="hidden">).

Lo que creará

En el tutorial anterior, aprendió a agregar un registro a una base de datos. Aquí aprenderá a mostrar un registro para editarlo. En la página películas , actualizará la aplicación auxiliar de WebGrid para que muestre un vínculo de edición junto a cada película:

Presentación de WebGrid que incluye un vínculo de edición para cada película

Al hacer clic en el vínculo Editar , se le remite a una página diferente, donde la información de la película ya está en un formulario:

Editar la página de película que muestra la película que se va a editar

Puede cambiar cualquiera de los valores. Al enviar los cambios, el código de la página actualiza la base de datos y vuelve a la lista de películas.

Esta parte del proceso funciona casi exactamente igual que la página AddMovie. cshtml que creó en el tutorial anterior, por lo que gran parte de este tutorial le resultará familiar.

Hay varias maneras de implementar una forma de editar una película individual. Se ha elegido el enfoque que se muestra porque es fácil de implementar y fácil de comprender.

Para empezar, deberá actualizar la página de películas para que cada lista de películas también contenga un vínculo de edición .

Abra el archivo movies. cshtml .

En el cuerpo de la página, cambie el marcado WebGrid agregando una columna. Este es el marcado modificado:

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

La nueva columna es esta:

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

El punto de esta columna es mostrar un vínculo (elemento<a>) cuyo texto dice "Edit". Lo que es después es crear un vínculo similar al siguiente cuando se ejecuta la página, con el valor id diferente para cada película:

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

Este vínculo invocará una página denominada EditMoviey pasará la cadena de consulta ?id=7 a esa página.

La sintaxis de la nueva columna podría parecer un poco compleja, pero esto solo se debe a que une varios elementos. Cada elemento individual es sencillo. Si se concentra solo en el elemento <a>, verá este marcado:

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

Información general sobre cómo funciona la cuadrícula: la cuadrícula muestra las filas, una para cada registro de base de datos, y muestra las columnas de cada campo en el registro de la base de datos. Mientras se construye cada fila de la cuadrícula, el objeto item contiene el registro de base de datos (elemento) de esa fila. Esta disposición le proporciona una forma de obtener el código para obtener los datos de esa fila. Eso es lo que se ve aquí: la expresión item.ID obtiene el valor de identificador del elemento de base de datos actual. Puede obtener cualquiera de los valores de la base de datos (title, Genre o Year) del mismo modo mediante item.Title, item.Genreo item.Year.

La expresión "~/EditMovie?id=@item.ID combina la parte codificada de forma rígida de la dirección URL de destino (~/EditMovie?id=) con este identificador derivado de forma dinámica. (Vio el operador ~ en el tutorial anterior; es un operador ASP.NET que representa la raíz del sitio web actual).

El resultado es que esta parte del marcado en la columna simplemente genera algo parecido al siguiente marcado en tiempo de ejecución:

href="/EditMovie?id=2"

Naturalmente, el valor real de id será diferente para cada fila.

Crear una presentación personalizada para una columna de cuadrícula

Ahora vuelva a la columna Grid. Las tres columnas que originalmente tenía en la cuadrícula solo muestran valores de datos (título, género y año). Para especificar esta presentación, debe pasar el nombre de la columna de base de datos — por ejemplo, grid.Column("Title").

Esta nueva columna de edición de vínculo es diferente. En lugar de especificar un nombre de columna, está pasando un parámetro format. Este parámetro permite definir el marcado que se representará en la aplicación auxiliar de WebGrid junto con el valor item para mostrar los datos de la columna en negrita o verde, o en el formato que desee. Por ejemplo, si desea que el título aparezca en negrita, puede crear una columna como en este ejemplo:

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

(Los distintos @ caracteres que se ven en la propiedad format marcan la transición entre el marcado y un valor de código).

Una vez que conozca la propiedad format, es más fácil comprender cómo se agrupa la nueva columna de vínculo de edición :

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

La columna solo está formada por el marcado que representa el vínculo, más parte de la información (el ID.) que se extrae del registro de la base de datos de la fila.

Tip

Parámetros con nombre y parámetros posicionales para un método

Muchas veces, cuando se llama a un método y se le pasan parámetros, simplemente se muestran los valores de los parámetros separados por comas. A continuación se muestran un par de ejemplos:

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

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

No mencionamos el problema la primera vez que vio este código, pero en cada caso, va a pasar parámetros a los métodos en un orden específico — nombre, el orden en el que se definen los parámetros en dicho método. Por db.Execute y Validation.RequireFields, si mezcla el orden de los valores que pasa, recibirá un mensaje de error al ejecutar la página o al menos algunos resultados extraños. Claramente, tiene que conocer el orden en el que debe pasar los parámetros. (En WebMatrix, IntelliSense puede ayudarle a averiguar el nombre, el tipo y el orden de los parámetros).

Como alternativa a pasar valores en orden, puede usar parámetros con nombre. (El paso de parámetros en orden se conoce como usar parámetros posicionales). En el caso de los parámetros con nombre, se incluye explícitamente el nombre del parámetro al pasar su valor. Ha usado parámetros con nombre ya varias veces en estos tutoriales. Por ejemplo:

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

y

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

Los parámetros con nombre son útiles para un par de situaciones, especialmente cuando un método toma muchos parámetros. Una es cuando desea pasar solo uno o dos parámetros, pero los valores que desea pasar no están entre las primeras posiciones de la lista de parámetros. Otra situación es cuando desea hacer que el código sea más legible pasando los parámetros en el orden que le resulte más conveniente.

Obviamente, para usar parámetros con nombre, debe conocer los nombres de los parámetros. IntelliSense de WebMatrix puede Mostrar los nombres, pero actualmente no puede rellenarlos.

Crear la página de edición

Ahora puede crear la página EditMovie . Cuando los usuarios hagan clic en el vínculo Editar , terminarán en esta página.

Cree una página denominada EditMovie. cshtml y reemplace lo que hay en el archivo con el marcado siguiente:

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

Este marcado y código es similar a lo que tiene en la página AddMovie . Hay una pequeña diferencia en el texto del botón Enviar. Al igual que en la página AddMovie , hay una llamada Html.ValidationSummary que mostrará los errores de validación, si hay alguno. Esta vez se omiten las llamadas a Validation.Message, ya que los errores se mostrarán en el Resumen de la validación. Como se indicó en el tutorial anterior, puede utilizar el Resumen de validación y los mensajes de error individuales en diversas combinaciones.

Observe de nuevo que el atributo method del elemento <form> está establecido en post. Como con la página AddMovie. cshtml , esta página realiza cambios en la base de datos. Por lo tanto, este formulario debe realizar una operación de POST. (Para obtener más información sobre la diferencia entre las operaciones de GET y POST, vea la barra lateral de seguridad del verbo GET, post y http en el tutorial sobre formularios HTML).

Como vimos en un tutorial anterior, los value atributos de los cuadros de texto se establecen con código Razor para cargarlos previamente. Sin embargo, esta vez se usan variables como title y genre para esa tarea en lugar de Request.Form["title"]:

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

Como antes, este marcado cargará previamente los valores del cuadro de texto con los valores de la película. Verá en un momento por qué es práctico usar variables esta vez en lugar de usar el objeto Request.

También hay un <input type="hidden"> elemento en esta página. Este elemento almacena el ID. de la película sin que esté visible en la página. El identificador se pasa inicialmente a la página mediante el uso de un valor de cadena de consulta (?id=7 o similar en la dirección URL). Al colocar el valor de identificador en un campo oculto, puede asegurarse de que está disponible cuando se envía el formulario, aunque ya no tenga acceso a la dirección URL original con la que se invocó la página.

A diferencia de la página AddMovie , el código de la página EditMovie tiene dos funciones distintas. La primera función es que cuando se muestra la página por primera vez (y solo después), el código obtiene el ID. de la película de la cadena de consulta. A continuación, el código usa el identificador para leer la película correspondiente de la base de datos y mostrarla (cargar previamente) en los cuadros de texto.

La segunda función es que cuando el usuario hace clic en el botón Enviar cambios , el código tiene que leer los valores de los cuadros de texto y validarlos. El código también tiene que actualizar el elemento de base de datos con los nuevos valores. Esta técnica es similar a agregar un registro, como se vio en AddMovie.

Agregar código para leer una sola película

Para realizar la primera función, agregue este código en la parte superior de la página:

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

La mayor parte de este código se encuentra dentro de un bloque que inicia if(!IsPost). El operador ! significa "no", por lo que la expresión significa si esta solicitud no es un envío post, lo que es una forma indirecta de indicar si esta solicitud es la primera vez que se ha ejecutado esta página. Como se indicó anteriormente, este código debe ejecutarse solo la primera vez que se ejecuta la página. Si no incluyó el código en if(!IsPost), se ejecutaría cada vez que se invoque la página, ya sea la primera vez o en respuesta a un clic de botón.

Tenga en cuenta que el código incluye un bloque else esta vez. Como hemos comentado cuando hemos introducido if bloques, a veces desea ejecutar código alternativo si la condición que está probando no es verdadera. Este es el caso aquí. Si la condición se supera (es decir, si el identificador pasado a la página es correcto), se lee una fila de la base de datos. Sin embargo, si no se supera la condición, se ejecuta el bloque else y el código establece un mensaje de error.

Validar un valor que se pasa a la página

El código usa Request.QueryString["id"] para obtener el identificador que se pasa a la página. El código garantiza que un valor se ha pasado realmente para el identificador. Si no se ha pasado ningún valor, el código establece un error de validación.

Este código muestra una manera diferente de validar la información. En el tutorial anterior, ha trabajado con el ayudante de Validation. Ha registrado campos para validar, y ASP.NET ha realizado automáticamente la validación y ha mostrado errores mediante Html.ValidationMessage y Html.ValidationSummary. Sin embargo, en este caso, no está validando realmente la entrada del usuario. En su lugar, está validando un valor que se pasó a la página desde otra parte. La aplicación auxiliar de Validation no lo hace por usted.

Por lo tanto, para comprobar el valor, pruébelo con if(!Request.QueryString["ID"].IsEmpty()). Si hay algún problema, puede mostrar el error mediante Html.ValidationSummary, como hizo con la aplicación auxiliar de Validation. Para ello, llame a Validation.AddFormError y pásele un mensaje para mostrarlo. Validation.AddFormError es un método integrado que le permite definir mensajes personalizados que se asocian con el sistema de validación con el que ya está familiarizado. (Más adelante en este tutorial hablaremos acerca de cómo hacer que este proceso de validación sea un poco más robusto).

Después de asegurarse de que hay un identificador para la película, el código lee la base de datos y solo busca un elemento de base de datos. (Probablemente ha observado el patrón general para las operaciones de base de datos: Abra la base de datos, defina una instrucción SQL y ejecute la instrucción). Esta vez, la instrucción de SQL Select incluye WHERE ID = @0. Dado que el identificador es único, solo se puede devolver un registro.

La consulta se realiza mediante db.QuerySingle (no db.Query, como se ha usado para la lista de películas) y el código coloca el resultado en la variable row. El nombre row es arbitrario; puede asignar el nombre que desee a las variables. Las variables inicializadas en la parte superior se rellenan con los detalles de la película para que estos valores se puedan mostrar en los cuadros de texto.

Probar la página de edición (hasta ahora)

Si desea probar la página, ejecute la página películas ahora y haga clic en un vínculo de edición junto a cualquier película. Verá la página EditMovie con los detalles rellenados para la película seleccionada:

Editar la página de película que muestra la película que se va a editar

Observe que la dirección URL de la página incluye algo como ?id=10 (o algún otro número). Hasta ahora, ha probado que los vínculos de edición en la página de la película funcionan, que la página está leyendo el identificador de la cadena de consulta y que la consulta de base de datos para obtener un único registro de película funciona.

Puede cambiar la información de la película, pero no ocurre nada al hacer clic en Enviar cambios.

Agregar código para actualizar la película con los cambios del usuario

En el archivo EditMovie. cshtml , para implementar la segunda función (guardar cambios), agregue el código siguiente justo dentro de la llave de cierre del bloque @. (Si no está seguro de dónde colocar el código exactamente, puede ver la lista de código completa de la página Editar película que aparece al final de este tutorial).

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

De nuevo, este marcado y el código son similares al código de AddMovie. El código está en un bloque if(IsPost), ya que este código solo se ejecuta cuando el usuario hace clic en el botón Enviar cambios — es decir, cuando se ha publicado el formulario (y solo cuando). En este caso, no está usando una prueba como if(IsPost && Validation.IsValid()), es decir, no está combinando ambas pruebas mediante y. En esta página, primero se determina si hay un envío de formulario (if(IsPost)) y solo se registran los campos para la validación. A continuación, puede probar los resultados de la validación (if(Validation.IsValid()). El flujo es ligeramente diferente que en la página AddMovie. cshtml , pero el efecto es el mismo.

Los valores de los cuadros de texto se obtienen mediante Request.Form["title"] y un código similar para los demás elementos de <input>. Observe que esta vez, el código obtiene el ID. de película del campo oculto (<input type="hidden">). Cuando se ejecutó la página por primera vez, el código obtenía el ID. de la cadena de consulta. Obtiene el valor del campo oculto para asegurarse de que está obteniendo el identificador de la película que se mostró originalmente, en caso de que la cadena de consulta se modificara de algún modo desde entonces.

La diferencia realmente importante entre el código AddMovie y este código es que en este código se utiliza la instrucción SQL Update en lugar de la instrucción Insert Into. En el ejemplo siguiente se muestra la sintaxis de la instrucción de SQL Update:

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

Puede especificar cualquier columna en cualquier orden y no es necesario actualizar todas las columnas durante una operación de Update. (No se puede actualizar el propio identificador, ya que esto haría en efecto que el registro se guardara como un registro nuevo y eso no se permite para una operación Update).

Note

Importante La cláusula Where con el identificador es muy importante, ya que es la forma en que la base de datos sabe qué registro de base de datos desea actualizar. Si deja fuera de la cláusula Where, la base de datos actualizaría todos los registros de la base de datos. En la mayoría de los casos, esto sería un desastre.

En el código, los valores que se van a actualizar se pasan a la instrucción SQL mediante marcadores de posición. Para repetir lo que hemos dicho antes: por razones de seguridad, use solo los marcadores de posición para pasar valores a una instrucción SQL.

Una vez que el código usa db.Execute para ejecutar la instrucción de Update, redirige de nuevo a la página de lista, donde puede ver los cambios.

Tip

Diferentes instrucciones SQL, métodos diferentes

Es posible que haya observado que usa métodos ligeramente diferentes para ejecutar diferentes instrucciones SQL. Para ejecutar una consulta Select que puede devolver varios registros, se usa el método Query. Para ejecutar una consulta de Select que sepa que solo devolverá un elemento de base de datos, use el método QuerySingle. Para ejecutar comandos que realizan cambios pero que no devuelven elementos de base de datos, use el método Execute.

Debe tener métodos diferentes porque cada uno de ellos devuelve resultados diferentes, como ya vio en la diferencia entre Query y QuerySingle. (El método Execute devuelve realmente un valor que también — nombre, el número de filas de base de datos afectadas por el comando — pero se ha omitido hasta ahora).

Por supuesto, el método Query podría devolver solo una fila de base de datos. Sin embargo, ASP.NET siempre trata los resultados del método Query como una colección. Incluso si el método devuelve solo una fila, tendrá que extraer esa fila de la colección. Por lo tanto, en situaciones en las que sepa que solo obtendrá una fila, es un poco más práctico usar QuerySingle.

Hay otros métodos que realizan tipos específicos de operaciones de base de datos. Puede encontrar una lista de métodos de base de datos en la referencia rápida de ASP.NET Web pages API.

Realización de la validación del identificador más sólida

La primera vez que se ejecuta la página, obtiene el ID. de la película de la cadena de consulta para que pueda obtener esa película desde la base de datos. Asegúrese de que realmente haya un valor para buscar, que ha hecho con este código:

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

Usó este código para asegurarse de que si un usuario llega a la página de EditMovies sin seleccionar primero una película en la página películas , la página mostraría un mensaje de error descriptivo. (De lo contrario, los usuarios verán un error que probablemente simplemente les confundiría).

Sin embargo, esta validación no es muy robusta. La página también se puede invocar con estos errores:

  • El identificador no es un número. Por ejemplo, la página se podría invocar con una dirección URL como http://localhost:nnnnn/EditMovie?id=abc.
  • El identificador es un número, pero hace referencia a una película que no existe (por ejemplo, http://localhost:nnnnn/EditMovie?id=100934).

Si tiene curiosidad por ver los errores resultantes de estas direcciones URL, ejecute la página películas . Seleccione una película para editarla y, a continuación, cambie la dirección URL de la página EditMovie por una dirección URL que contenga un identificador alfabético o el ID. de una película no existente.

¿Qué debe hacer? La primera corrección es asegurarse de que no solo se pasa un identificador a la página, pero que el identificador es un entero. Cambie el código para que la prueba de !IsPost sea similar a la de este ejemplo:

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

Ha agregado una segunda condición a la prueba de IsEmpty, vinculada con && (AND lógico):

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

Es posible que recuerde de la Introducción a ASP.NET Web pages tutorial de programación que métodos como AsBool un AsInt convertir una cadena de caracteres a algún otro tipo de datos. El método IsInt (y otros, como IsBool y IsDateTime) son similares. Sin embargo, solo prueban si puede convertir la cadena, sin realizar realmente la conversión. Por lo tanto, aquí está diciendo en esencia si el valor de la cadena de consulta se puede convertir en un entero... .

El otro problema potencial es buscar una película que no existe. El código para obtener una película es similar a este código:

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

Si pasa un valor movieId al método QuerySingle que no se corresponde con una película real, no se devuelve nada y las instrucciones siguientes (por ejemplo, title=row.Title) producen errores.

Una vez más, hay una solución fácil. Si el método db.QuerySingle no devuelve ningún resultado, la variable row será null. Por lo tanto, puede comprobar si la variable row es NULL antes de intentar obtener valores de ella. En el código siguiente se agrega un bloque if alrededor de las instrucciones que obtienen los valores del objeto row:

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

Con estas dos pruebas de validación adicionales, la página se vuelve más detallada. El código completo de la rama !IsPost ahora es similar a este ejemplo:

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

Tendremos en cuenta que esta tarea es un buen uso para un bloque de else. Si no se superan las pruebas, los bloques de else establecen mensajes de error.

Un detalle final y útil es volver a agregar un vínculo a la página películas . En el flujo de eventos normal, los usuarios se inician en la página películas y hacen clic en un vínculo Editar . Esto los coloca en la página EditMovie , donde pueden editar la película y hacer clic en el botón. Una vez que el código procesa el cambio, redirige de nuevo a la página de películas .

Pero:

  • El usuario puede decidir no cambiar nada.
  • Es posible que el usuario haya llegado a esta página sin hacer clic primero en el vínculo Editar de la página películas .

En cualquier caso, desea que resulte fácil volver a la lista principal. Es una solución sencilla — agregar el marcado siguiente justo después de la etiqueta de cierre </form> en el marcado:

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

Este marcado usa la misma sintaxis para un elemento <a> que ha visto en otro lugar. La dirección URL incluye ~ que significa "raíz del sitio web".

Probar el proceso de actualización de la película

Ahora puede probar. Ejecute la página películas y haga clic en Editar junto a una película. Cuando aparezca la página EditMovie , realice cambios en la película y haga clic en Enviar cambios. Cuando aparezca la lista de películas, asegúrese de que se muestran los cambios.

Para asegurarse de que la validación funciona, haga clic en Editar para otra película. Cuando llegue a la página EditMovie , borre el campo Genre (o el campo Year , o ambos) e intente enviar los cambios. Verá un error, como cabría esperar:

Página Editar película que muestra los errores de validación

Haga clic en el vínculo volver a la lista de películas para abandonar los cambios y volver a la página películas .

Próxima

En el siguiente tutorial, verá cómo eliminar un registro de película.

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

Lista completa de páginas para editar película

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

Recursos adicionales