ASP.NET MVC part 7 Adding a New Field to the Movie Model and Table


Adding a New Field to the Movie Model and Database Table

In this section you’ll make some changes to the model classes and learn how you can update the database schema to match the model changes.

Adding a Rating Property to the Movie Model

Start by adding a new Rating property to the existing Movie class. Open the Movie.cs file and add the Ratingproperty like this one:

public string Rating { get; set; }

The complete Movie class now looks like the following code:

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

Recompile the application using the Debug > Build Movie menu command.

Now that you’ve updated the Model class, you also need to update the \Views\Movies\Index.cshtml and\Views\Movies\Create.cshtml view templates in order to support the new Rating property.

Open the \Views\Movies\Index.cshtml file and add a <th>Rating</th> column heading just after the Pricecolumn. Then add a <td> column near the end of the template to render the @item.Rating value. Below is what the updated Index.cshtml view template looks like:

<table>
    <tr>
        <th></th>
        <th>Title</th>
        <th>Release Date</th>
        <th>Genre</th>
        <th>Price</th>
        <th>Rating</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 Me", "Edit", new { id=item.ID }) |
            @Html.ActionLink("Details", "Details", new { id=item.ID }) |
            @Html.ActionLink("Delete", "Delete", new { id=item.ID })
        </td>
    </tr>
}
</table>

Next, open the \Views\Movies\Create.cshtml file and add the following markup near the end of the form. This renders a text box so that you can specify a rating when a new movie is created.

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

Managing Model and Database Schema Differences

You’ve now updated the application code to support the new Rating property.

Now run the application and navigate to the /Movies URL. When you do this, though, you’ll see the following error:

You’re seeing this error because the updated Movie model class in the application is now different than the schema of the Movie table of the existing database. (There’s no Rating column in the database table.)

By default, when you use Entity Framework Code First to automatically create a database, as you did earlier in this tutorial, Code First adds a table to the database to help track whether the schema of the database is in sync with the model classes it was generated from. If they aren’t in sync, the Entity Framework throws an error. This makes it easier to track down issues at development time that you might otherwise only find (by obscure errors) at run time. The sync-checking feature is what causes the error message to be displayed that you just saw.

There are two approaches to resolving the error:

  1. Have the Entity Framework automatically drop and re-create the database based on the new model class schema. This approach is very convenient when doing active development on a test database, because it allows you to quickly evolve the model and database schema together. The downside, though, is that you lose existing data in the database — so you don’t want to use this approach on a production database!
  2. Explicitly modify the schema of the existing database so that it matches the model classes. The advantage of this approach is that you keep your data. You can make this change either manually or by creating a database change script.

For this tutorial, we’ll use the first approach — you’ll have the Entity Framework Code First automatically re-create the database anytime the model changes.

Automatically Re-Creating the Database on Model Changes

Let’s update the application so that Code First automatically drops and re-creates the database anytime you change the model for the application.

Warning   You should enable this approach of automatically dropping and re-creating the database only when you’re using a development or test database, and never on a production database that contains real data. Using it on a production server can lead to data loss.

In Solution Explorer, right click the Models folder, select Add, and then select Class.

Name the class “MovieInitializer”. Update the MovieInitializer class to contain the following code:

using System;
using System.Collections.Generic;
using System.Data.Entity;

namespace MvcMovie.Models {
    public class MovieInitializer : DropCreateDatabaseIfModelChanges<MovieDBContext> {
        protected override void Seed(MovieDBContext context) {
            var movies = new List<Movie> {  
  
                 new Movie { Title = "When Harry Met Sally",   
                             ReleaseDate=DateTime.Parse("1989-1-11"),   
                             Genre="Romantic Comedy",  
                             Rating="R",  
                             Price=7.99M},  

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

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

            movies.ForEach(d => context.Movies.Add(d));
        }
    }
}

The MovieInitializer class specifies that the database used by the model should be dropped and automatically re-created if the model classes ever change. The code includes a Seed method to specify some default data to automatically add to the database any time it’s created (or re-created). This provides a useful way to populate the database with some sample data, without requiring you to manually populate it each time you make a model change.

Now that you’ve defined the MovieInitializer class, you’ll want to wire it up so that each time the application runs, it checks whether the model classes are different from the schema in the database. If they are, you can run the initializer to re-create the database to match the model and then populate the database with the sample data.

Open the Global.asax file that’s at the root of the MvcMovies project:

The Global.asax file contains the class that defines the entire application for the project, and contains anApplication_Start event handler that runs when the application first starts.

Let’s add two using statements to the top of the file. The first references the Entity Framework namespace, and the second references the namespace where our MovieInitializer class lives:

using System.Data.Entity;            // Database.SetInitialize
using MvcMovie.Models;              // MovieInitializer

Then find the Application_Start method and add a call to Database.SetInitializer at the beginning of the method, as shown below:

protected void Application_Start()
{
    Database.SetInitializer<MovieDBContext>(new MovieInitializer());

    AreaRegistration.RegisterAllAreas();
    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);
}

The Database.SetInitializer statement you just added indicates that the database used by theMovieDBContext instance should be automatically deleted and re-created if the schema and the database don’t match. And as you saw, it will also populate the database with the sample data that’s specified in theMovieInitializer class.

Close the Global.asax file.

Re-run the application and navigate to the /Movies URL. When the application starts, it detects that the model structure no longer matches the database schema. It automatically re-creates the database to match the new model structure and populates the database with the sample movies:

7_MyMovieList_SM

Click the Create New link to add a new movie. Note that you can add a rating.

7_CreateRioII

Click Create. The new movie, including the rating, now shows up in the movies listing:

7_ourNewMovie_SM

In this section you saw how you can modify model objects and keep the database in sync with the changes. You also learned a way to populate a newly created database with sample data so you can try out scenarios. Next, let’s look at how you can add richer validation logic to the model classes and enable some business rules to be enforced.

Posted on 23 April 2011, in ASP.NET MVC. Bookmark the permalink. 2 Comments.

  1. Hi there! I’m at work surfing around your blog from
    my new iphone 3gs! Just wanted to say I love reading through
    your blog and look forward to all your posts!
    Carry on the great work!

  2. Undeniably believe that which you stated. Your favorite justification seemed
    to be at the net the simplest thing to understand of.
    I say to you, I certainly get annoyed at the same time as people consider worries that they just don’t recognise
    about. You managed to hit the nail upon the top and defined out the entire
    thing without having side effect , folks can take a signal.
    Will likely be back to get more. Thanks

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: