Adding a New Field to the Movie Model and Table (C#)
[!NOTE] An updated version of this tutorial is available here that uses ASP.NET MVC 5 and Visual Studio 2013. It’s more secure, much simpler to follow and demonstrates more features.
This tutorial will teach you the basics of building an ASP.NET MVC Web application using Microsoft Visual Web Developer 2010 Express Service Pack 1, which is a free version of Microsoft Visual Studio. Before you start, make sure you’ve installed the prerequisites listed below. You can install all of them by clicking the following link: Web Platform Installer. Alternatively, you can individually install the prerequisites using the following links:
- Visual Studio Web Developer Express SP1 prerequisites
- ASP.NET MVC 3 Tools Update
- SQL Server Compact 4.0(runtime + tools support)
If you’re using Visual Studio 2010 instead of Visual Web Developer 2010, install the prerequisites by clicking the following link: Visual Studio 2010 prerequisites.
A Visual Web Developer project with C# source code is available to accompany this topic. Download the C# version. If you prefer Visual Basic, switch to the Visual Basic version of this tutorial.
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 Rating
property like this one:
[!code-csharpMain]
1: public string Rating { get; set; }
The complete Movie
class now looks like the following code:
[!code-csharpMain]
1: public class Movie
2: {
3: public int ID { get; set; }
4: public string Title { get; set; }
5: public DateTime ReleaseDate { get; set; }
6: public string Genre { get; set; }
7: public decimal Price { get; set; }
8: public string Rating { get; set; }
9: }
Recompile the application using the Debug >Build Movie menu command.
Now that you’ve updated the Model
class, you also need to update the .cshtml and .cshtml view templates in order to support the new Rating
property.
Open the .cshtml file and add a <th>Rating</th>
column heading just after the Price column. 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:
[!code-cshtmlMain]
1: <table>
2: <tr>
3: <th></th>
4: <th>Title</th>
5: <th>Release Date</th>
6: <th>Genre</th>
7: <th>Price</th>
8: <th>Rating</th>
9: </tr>
10:
11: @foreach (var item in Model) {
12: <tr>
13: <td>
14: @Html.DisplayFor(modelItem => item.Title)
15: </td>
16: <td>
17: @Html.DisplayFor(modelItem => item.ReleaseDate)
18: </td>
19: <td>
20: @Html.DisplayFor(modelItem => item.Genre)
21: </td>
22: <td>
23: @Html.DisplayFor(modelItem => item.Price)
24: </td>
25: <td>
26: @Html.DisplayFor(modelItem => item.Rating )
27: </td>
28: <td>
29: @Html.ActionLink("Edit Me", "Edit", new { id=item.ID }) |
30: @Html.ActionLink("Details", "Details", new { id=item.ID }) |
31: @Html.ActionLink("Delete", "Delete", new { id=item.ID })
32: </td>
33: </tr>
34: }
35: </table>
Next, open the .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.
[!code-cshtmlMain]
1: <div class="editor-label">
2: @Html.LabelFor(model => model.Rating)
3: </div>
4: <div class="editor-field">
5: @Html.EditorFor(model => model.Rating)
6: @Html.ValidationMessageFor(model => model.Rating)
7: </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:
- 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!
- 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.
[!NOTE]
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:
[!code-csharpMain]
1: using System;
2: using System.Collections.Generic;
3: using System.Data.Entity;
4:
5: namespace MvcMovie.Models {
6: public class MovieInitializer : DropCreateDatabaseIfModelChanges<MovieDBContext> {
7: protected override void Seed(MovieDBContext context) {
8: var movies = new List<Movie> {
9:
10: new Movie { Title = "When Harry Met Sally",
11: ReleaseDate=DateTime.Parse("1989-1-11"),
12: Genre="Romantic Comedy",
13: Rating="R",
14: Price=7.99M},
15:
16: new Movie { Title = "Ghostbusters ",
17: ReleaseDate=DateTime.Parse("1984-3-13"),
18: Genre="Comedy",
19: Rating="R",
20: Price=8.99M},
21:
22: new Movie { Title = "Ghostbusters 2",
23: ReleaseDate=DateTime.Parse("1986-2-23"),
24: Genre="Comedy",
25: Rating="R",
26: Price=9.99M},
27:
28: new Movie { Title = "Rio Bravo",
29: ReleaseDate=DateTime.Parse("1959-4-15"),
30: Genre="Western",
31: Rating="R",
32: Price=3.99M},
33: };
34:
35: movies.ForEach(d => context.Movies.Add(d));
36: }
37: }
38: }
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 an Application_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:
[!code-csharpMain]
1: using System.Data.Entity; // Database.SetInitialize
2: 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:
[!code-csharpMain]
1: protected void Application_Start()
2: {
3: Database.SetInitializer<MovieDBContext>(new MovieInitializer());
4:
5: AreaRegistration.RegisterAllAreas();
6: RegisterGlobalFilters(GlobalFilters.Filters);
7: RegisterRoutes(RouteTable.Routes);
8: }
The Database.SetInitializer
statement you just added indicates that the database used by the MovieDBContext
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 the MovieInitializer
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:
Click the Create New link to add a new movie. Note that you can add a rating.
Click Create. The new movie, including the rating, now shows up in the movies listing:
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.
|