Agregar un nuevo campo a la tabla y modelo de películas

De Rick Anderson

Nota:

Hay disponible aquí una versión actualizada de este tutorial que usa ASP.NET MVC 5 y Visual Studio 2013. Es más seguro, mucho más sencillo de seguir y muestra más características.

En esta sección usará Migraciones de Code First de Entity Framework para migrar algunos cambios a las clases de modelo para que el cambio se aplique a la base de datos.

De forma predeterminada, cuando se usa Entity Framework Code First para crear automáticamente una base de datos, como hizo anteriormente en este tutorial, Code First agrega una tabla a la base de datos para ayudar a realizar un seguimiento de si el esquema de la base de datos está sincronizado con las clases de modelo de las que se generó. Si no están sincronizados, Entity Framework produce un error. Esto facilita el seguimiento de problemas durante el desarrollo que, de lo contrario, solo encontraría (por errores ocultos) en tiempo de ejecución.

Configuración de migraciones de Code First para cambios de modelo

Si usa Visual Studio 2012, haga doble clic en el archivo Movies.mdf del Explorador de soluciones para abrir la herramienta de base de datos. Visual Studio Express para Web mostrará el Explorador de bases de datos, Visual Studio 2012 mostrará el Explorador de servidores. Si usa Visual Studio 2010, use el Explorador de objetos de SQL Server.

En la herramienta de base de datos (Explorador de bases de datos, Explorador de servidores o Explorador de objetos de SQL Server), haga clic con el botón derecho en MovieDBContext y seleccione Eliminar para quitar la base de datos de películas.

Screenshot that shows the Server Explorer window. Delete is selected in the Movie D B Context right click menu.

Vuelva al Explorador de soluciones. Haga clic con el botón derecho en el archivo Movies.mdf y seleccione Eliminar para quitar la base de datos de películas.

Screenshot that shows the Solution Explorer window. Delete is selected in the Movies dot m d f right click menu.

Compile la aplicación para asegurarse de que no hay ningún error.

En el menú Tools (Herramientas), haga clic en Administrador de paquetes NuGet y luego en Consola del Administrador de paquetes.

Add Pack Man

En la ventana Consola del administrador de paquetes, en el indicador PM> introduzca "Enable-Migrations -ContextTypeName MvcMovie.Models.MovieDBContext".

Screenshot that shows the Package Manager Console window. The Enable Migrations command is entered.

El comando Enable-Migrations (mostrado anteriormente) crea un archivo Configuration.cs en una nueva carpeta de Migraciones.

Screenshot that shows the Solution Explorer window. The Migrations folder and Configuration dot c s file are circled in red.

Visual Studio abre el archivo Configuration.cs. Reemplace el método Seed en el archivo Configuration.cs por el código siguiente:

protected override void Seed(MvcMovie.Models.MovieDBContext context)
{
    context.Movies.AddOrUpdate( i => i.Title,
        new Movie
        {
            Title = "When Harry Met Sally",
            ReleaseDate = DateTime.Parse("1989-1-11"),
            Genre = "Romantic Comedy",
            Price = 7.99M
        },

         new Movie
         {
             Title = "Ghostbusters ",
             ReleaseDate = DateTime.Parse("1984-3-13"),
             Genre = "Comedy",
             Price = 8.99M
         },

         new Movie
         {
             Title = "Ghostbusters 2",
             ReleaseDate = DateTime.Parse("1986-2-23"),
             Genre = "Comedy",
             Price = 9.99M
         },

       new Movie
       {
           Title = "Rio Bravo",
           ReleaseDate = DateTime.Parse("1959-4-15"),
           Genre = "Western",
           Price = 3.99M
       }
   );
   
}

Haga clic con el botón derecho en la línea ondulada roja debajo de Movie y seleccione Resolver y, a continuación, useMvcMovie.Models;

Screenshot that shows Resolve selected in the Movie right click menu.

Al hacerlo, se agregan las siguientes instrucciones using:

using MvcMovie.Models;

Nota:

Migraciones de Code First llama al método Seed después de cada migración (es decir, llama a update-database en la consola del Administrador de paquetes) y este método actualiza las filas que ya se han insertado o las inserta si aún no existen.

Presione CTRL-MAYÚS-B para compilar el proyecto (se producirá un error en los pasos siguientes si no se compila en este momento).

El siguiente paso es crear una clase DbMigration para la migración inicial. Esta migración crea una nueva base de datos, es por ello que eliminó el archivo movie.mdf en un paso anterior.

En la ventana Consola del Administrador de paquetes, escriba el comando "add-migration Initial" para crear la migración inicial. El nombre "Initial" es arbitrario y se usa para asignar un nombre al archivo de migración.

Screenshot that shows the Package Manager Console window. The paragraph that begins with The Designer Code for this migration file is highlighted.

Migraciones de Code First crea otro archivo de clase en la carpeta Migraciones (con el nombre {DateStamp}_Initial.cs) y esta clase contiene el código que crea el esquema de la base de datos. El nombre de archivo de la migración lleva una marca de tiempo para ayudar con el orden. Examine el archivo {DateStamp}_Initial.cs, contiene las instrucciones para crear la tabla Movies para Movie DB. Al actualizar la base de datos en las instrucciones siguientes, este archivo {DateStamp}_Initial.cs se ejecutará y creará el esquema de la base de datos. A continuación, el método Seed se ejecutará para rellenar la base de datos con datos de prueba.

En la Consola del Administrador de paquetes, escriba el comando "update-database" para crear la base de datos y ejecutar el método Seed.

Screenshot that shows the Package Manager Console window. The update database command is entered.

Si recibe un error que indica que ya existe una tabla y no se puede crear, es probable que se deba a que ejecutó la aplicación después de eliminar la base de datos y antes de ejecutar update-database. En ese caso, elimine de nuevo el archivo Movies.mdf y vuelva a intentarlo con el comando update-database. Si sigue recibiendo un error, elimine la carpeta de migraciones y el contenido, comience con las instrucciones de la parte superior de esta página (es decir, elimine el archivo Movies.mdf y, a continuación, continúe con Enable-Migrations).

Ejecute la aplicación y navegue a la URL /Movies. Se muestran los datos de inicialización.

Screenshot that shows the M V C Movie Index page with a list of four movies.

Adición de una propiedad de clasificación al modelo Movie

Para empezar, agregue una nueva propiedad Rating a la clase Movie existente. Abra el archivo Models\Movie.cs y agregue la propiedad Rating como esta:

public string Rating { get; set; }

La clase Movie completa ahora tiene el siguiente aspecto:

public class Movie
{
    public int ID { get; set; }
    public string Title { get; set; }
    public DateTime ReleaseDate { get; set; }
    public string Genre { get; set; }
    public decimal Price { get; set; }
    public string Rating { get; set; }
}

Construya la aplicación utilizando el comando de menú Compilar>Compilar película o pulsando CTRL-SHIFT-B.

Ahora que ha actualizado la clase Model, también debe actualizar las plantillas de vista Views\Movies\Index.cshtml y Views\Movies\Create.cshtml para mostrar la nueva propiedad Rating en la vista del navegador.

Abra el archivo \Views\Movies\Index.cshtml y agregue un encabezado de columna <th>Rating</th> justo después de la columna Price. Después, agregue una columna <td> cerca del final de la plantilla para representar el valor @item.Rating. A continuación se muestra el aspecto de la plantilla de vista Index.cshtml actualizada:

@model IEnumerable<MvcMovie.Models.Movie>

@{
    ViewBag.Title = "Index";
}

<h2>Index</h2>

<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table>
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.Title)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.ReleaseDate)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Genre)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Price)
        </th>
         <th>
            @Html.DisplayNameFor(model => model.Rating)
        </th>
        <th></th>
    </tr>

@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Title)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.ReleaseDate)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Genre)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Price)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Rating)
        </td>
        <td>
            @Html.ActionLink("Edit", "Edit", new { id=item.ID }) |
            @Html.ActionLink("Details", "Details", new { id=item.ID }) |
            @Html.ActionLink("Delete", "Delete", new { id=item.ID })
        </td>
    </tr>
}

</table>

A continuación, abra el archivo \Views\Movies\Create.cshtml y agregue el siguiente marcado cerca del final del formulario. Esto representa un cuadro de texto para que pueda especificar una clasificación cuando se crea una película.

<div class="editor-label">
    @Html.LabelFor(model => model.Rating)
</div>
<div class="editor-field">
    @Html.EditorFor(model => model.Rating)
    @Html.ValidationMessageFor(model => model.Rating)
</div>

Ahora ha actualizado el código de la aplicación para admitir la nueva propiedad Rating.

Ejecute la aplicación y vaya a la dirección URL /Movies. Sin embargo, al hacerlo, verá uno de los siguientes errores:

Screenshot that shows the error Invalid Operation Exception was unhandled by user code.

Screenshot that shows the browser window with an error that states Server Error in Application.

Este error se muestra porque la clase del modelo Movie actualizada en la aplicación es diferente del esquema de la tabla Movie de la base de datos existente. (No hay ninguna columna Rating en la tabla de la base de datos).

Este error se puede resolver de varias maneras:

  1. Haga que Entity Framework quite de forma automática la base de datos y la vuelva a crear basándose en el nuevo esquema de la clase del modelo. Este enfoque resulta muy conveniente cuando se realiza el desarrollo activo en una base de datos de prueba; permite desarrollar rápidamente el esquema del modelo y la base de datos de manera conjunta. La desventaja es que se pierden los datos existentes en la base de datos, así que no use este enfoque en una base de datos de producción. Usar un inicializador para inicializar automáticamente una base de datos con datos de prueba suele ser una manera productiva de desarrollar una aplicación. Para obtener más información sobre los inicializadores de base de datos de Entity Framework, consulte el tutorial ASP.NET MVC/Entity Framework de Tom Dykstra.
  2. Modifique explícitamente el esquema de la base de datos existente para que coincida con las clases del modelo. La ventaja de este enfoque es que se conservan los datos. Puede realizar este cambio de forma manual o mediante la creación de un script de cambio de base de datos.
  3. Use Migraciones de Code First para actualizar el esquema de la base de datos.

Para este tutorial se usa Migraciones de Code First.

Actualice el método Seed para que proporcione un valor para la nueva columna. Abra el archivo Migrations\Configuration.cs y agregue un campo Rating a cada objeto Movie.

new Movie
{
    Title = "When Harry Met Sally",
    ReleaseDate = DateTime.Parse("1989-1-11"),
    Genre = "Romantic Comedy",
    Rating = "G",
    Price = 7.99M
},

Compile la solución, abra la ventana Consola del Administrador de paquetes y escriba el siguiente comando:

add-migration AddRatingMig

El comando add-migration indica al marco de migración que examine el modelo de película actual con el esquema de base de datos de película actual y cree el código necesario para migrar la base de datos al nuevo modelo. AddRatingMig es arbitrario y se usa para asignar un nombre al archivo de migración. Resulta útil usar un nombre descriptivo para el paso de migración.

Cuando este comando finaliza, Visual Studio abre el archivo de clase que define la nueva clase derivada DbMigration y, en el método Up, puede ver el código que crea la nueva columna.

public partial class AddRatingMig : DbMigration
{
    public override void Up()
    {
        AddColumn("dbo.Movies", "Rating", c => c.String());
    }
    
    public override void Down()
    {
        DropColumn("dbo.Movies", "Rating");
    }
}

Compile la solución y escriba el comando "update-database" en la ventana Consola del administrador de paquetes.

En la imagen siguiente se muestra la salida en la ventana Consola del administrador de paquetes (la marca de fecha pendiente AddRatingMig será diferente).

Screenshot that shows the update database command.

Vuelva a ejecutar la aplicación y vaya a la dirección URL de /Movies. Puede ver el nuevo campo Clasificación.

Screenshot that shows the M V C Movie Index page with four movies listed.

Haga clic en el vínculo Crear nueva para agregar una nueva película. Tenga en cuenta que puede agregar una clasificación.

7_CreateRioII

Haga clic en Crear. La nueva película, incluida la clasificación, ahora aparece en la lista de películas:

7_ourNewMovie_SM

También debe agregar el campo Rating a las plantillas de vista Editar, Detalles y SearchIndex.

Puede volver a escribir el comando "update-database" en la ventana Consola del administrador de paquetes y no se realizarían cambios, ya que el esquema coincide con el modelo.

En esta sección ha visto cómo puede modificar objetos de modelo y mantener la base de datos sincronizada con los cambios. También ha aprendido a rellenar una base de datos recién creada con datos de ejemplo para probar escenarios. A continuación, verá cómo puede agregar lógica de validación más completa a las clases de modelo y permitir que se apliquen algunas reglas de negocios.