Agregando un campo nuevo a una aplicación ASP.NET Core MVC

En esta sección vamos a usar migraciones Code First de Entity Framework para agregar un campo nuevo al modelo y migrar ese cambio a la base de datos.

Cuando usamos EF Code First para crear de manera automática la base de datos, Code First agrega una tabla en la base de datos para llevar cuenta de si el esquema de base de datos está sincronizado con el modelo de clases del que fue generado. Si no estan sincronizados, EF lanza una excepción. Esto hace que sea más facil encontrar problemas de insconsistencia entre la base de datos y el código.

Agregar la propiedad Rating al modelo de películas

Abramos el archivo Models/Movie.cs y agreguemos una propiedad Rating:

public class Movie
{
    public int ID { get; set; }
    public string Title { get; set; }

    [Display(Name = "Release Date")]
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }
    public string Genre { get; set; }

    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }
    public string Rating { get; set; }
}

Compilemos la aplicación (Ctrl+Shift+B)

Porque agregamos un campo nuevo a la clase Movie, tambien necesitamos actualizar la lista blanca de campos permitidos para incluir esta nueva propiedad. En el archivo MovieController.cs, actualiza el atributo [Bind] para los métodos Create y Edit para que incluyan la propiedad:

[Bind("ID,Title,ReleaseDate,Genre,Price,Rating")]

También vamos a necesitar actualizar las plantillas de vista para que muestren, creen y editen la nueva propiedad Rating.

Editemos el archivo /Views/Movies/Index.cshtml y agreguemos un campo Rating:

<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.movies[0].Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.movies[0].ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.movies[0].Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.movies[0].Price)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.movies[0].Rating)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model.movies)
        {
            <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>

Actualicemos el archivo /Views/Movies/Create.cshtml agregando un campo Rating. Podemos copiar y pegar el “form group” anterior y permitir que IntelliSense nos ayude a actualizar los campos. IntelliSense funciona con los Tag Helpers Nota: Si tenemos una versión desactualizada de Visual Studio 2017 puede que necesitemos instalar Razor Language Services para Razor IntelliSense.

Intellisense ayudando con la propiedad Rating en la vista

La aplicación no va a funcionar hasta que no actualicemos la base de datos para que incluya el campo nuevo. Si lo ejecutamos ahora, vamos a obtener la siguiente excepción SqlException:

SqlException: Invalid column name 'Rating'.

Estamos viendo este error porque el modelo de la clase Movie actualizada es diferente del esquema de la tabla Movie en la base de datos existente. (No hay columna Rating en la tabla de la base de datos).

Hay algunas formas de resolver el error:

  1. Hagamos que Entity Framework borre y después vuelva a crear la base de datos basándose en un nuevo modelo de esquema de clases. Esta manera de trabajar es muy conveniente en etapas tempranas del ciclo de desarrollo cuando no sabemos bien la forma que va a tener nuestro modelo / base de datos. Nos permite ir cambiando de manera rápida el modelo y el esquema de base de datos al mismo tiempo. La desventaja, sin embargo, es que vamos a perder los datos existentes en la base de datos. Así que no vamos a hacer esto en una base de datos de producción. Utilizar un inicializador para hacer de semilla a una base de datos con datos de producción es una manera muy efectiva de trabajar.
  2. Modificar el esquema de la base de datos existente de manera explícita para que coincida con las clases del modelo. La ventaja de esta manera de trabajar es que conservaremos los datos existentes. Se pueden hacer los cambios de manera manual o creando un script de cambios para la base de datos.
  3. Utilizar migraciones Code First para actualizar el esquema de base de datos.

Actualicemos la clase SeedData para que provea un valor para la nueva columna. Un ejemplo del cambio se muestra a continuación, pero debemos asegurarnos de hacer este cambio para cada uno de los new Movie.

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

Compilemos la solución.

Desde el menú Herramientas, seleccionemos Administrador de paquetes Nuget > Consola del Administrador de Paquetes.

Menú del Administrador de paquetes Nuget

En la consola, ingresa los siguientes comandos:

Add-Migration Rating
Update-Database

El comando Add-Migration le dice al framework de migraciones que examine el modelo actual de la clase Movie con el esquema actual de la base de datos y cree el código necesario para migrar la base de datos al modelo nuevo. El nombre “Rating” es arbitrario y se usa para nombrar el archivo de migración. Una cosa muy util acá es poner un nombre que sea representativo.

Si borramos todos los registros en la base de datos, la inicialización de la clase SeedData va a generar datos nuevos e incluir el campo Rating. El borrado se puede hacer desde los enlaces Delete en la aplicación o usando el SQL Server Object Explorer.

Ejecutemos la palicación y verifiquemos que podemos crear/editar/mostrar películas con el campo Rating. También deberíamos ver que el campo Rating esté agregado a las vistas Edit, Details y Delete.

En la siguiente parte del tutorial vamos a ver la validación en detalle.