Adding a model

By Rick Anderson

In this section you’ll add some classes for managing movies in a database. These classes will be the “Model” part of the MVC app.

You’ll use a .NET Framework data-access technology known as the Entity Framework to define and work with these model classes. The Entity Framework (often referred to as EF) supports a development paradigm called Code First. Code First allows you to create model objects by writing simple classes. (These are also known as POCO classes, from “plain-old CLR objects.”) You can then have the database created on the fly from your classes, which enables a very clean and rapid development workflow. If you are required to create the database first, you can still follow this tutorial to learn about MVC and EF app development.

Adding Model Classes

In Solution Explorer, right click the Models folder > Add > Class.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
using System;

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

In addition to the properties you’d expect to model a movie, the ID field is required by the DB for the primary key.

Build the project. If you don’t build the app, you’ll get an error in the next section. We’ve finally added a Model to our MVC app.

Scaffolding a controller

In Solution Explorer, right-click the Controllers folder > Add > Controller.

../../_images/add_controller1.png

In the Add Scaffold dialog, tap MVC 6 Controller with views, using Entity Framework > Add.

../../_images/add_scaffold2.png
  • Complete the Add Controller dialog

    • Model class: Movie(MvcMovie.Models)
    • Data context class: ApplicationDbContext(MvcMovie.Models)
    • Controller name: Keep the default MoviesController
    • Views:: Keep the default of each option checked
    • Controller name: Keep the default MoviesController
    • Tap Add
../../_images/add_controller2.png

The Visual Studio scaffolding engine creates the following:

  • A movies controller (MoviesController.c)

  • Create, Delete, Details, Edit and Index Razor view files

  • Migrations classes

    • The CreateIdentitySchema class creates the ASP.NET Identity membership database tables. The Identity database stores user login information that is needed for authentication. We won’t cover authentication in this tutorial, for that you can follow Additional resources at the end of this tutorial.
    • The ApplicationDbContextModelSnapshot class creates the EF entities used to access the Identity database. We’ll talk more about EF entities later in the tutorial.

Visual Studio automatically created the CRUD (create, read, update, and delete) action methods and views for you (the automatic creation of CRUD action methods and views is known as scaffolding). You’ll soon have a fully functional web application that lets you create, list, edit, and delete movie entries.

Use data migrations to create the database

  • Open a command prompt in the project directory (MvcMovie/src/MvcMovie). Follow these instructions for a quick way to open a folder in the project directory.

    • Open a file in the root of the project (for this example, use Startup.cs.)
    • Right click on Startup.cs > Open Containing Folder.
    ../../_images/quick.png
    • Shift + right click a folder > Open command window here
    ../../_images/folder.png
    • Run cd .. to move back up to the project directory
  • Run the following commands in the command prompt:

dnu restore
dnvm use 1.0.0-rc1-update1 -p
dnx ef migrations add Initial
dnx ef database update
../../_images/cmd.png
  • dnu restore This command looks at the dependencies in the project.json file and downloads them. For more information see Working with DNX Projects and DNX Overview.

  • dnvm use <version> dnvm is the .NET Version Manager, which is a set of command line utilities that are used to update and configure .NET Runtime. In this case we’re asking dnvm add the 1.0.0-rc1 ASP.NET 5 runtime to the PATH environment variable of the current shell.

  • dnx DNX stands for .NET Execution Environment.

    • dnx ef The ef command is specified in the project.json file:
1
2
3
4
5
  "commands": {
    "web": "Microsoft.AspNet.Server.Kestrel",
    "ef": "EntityFramework.Commands"
  },
  • dnx ef migrations add Initial Creates a class named Initial
public partial class Initial : Migration

The parameter “Initial” is arbitrary, but customary for the first (initial) database migration. You can safely ignore the warning may result in the loss of data, it is dropping foreign key constraints and not any data. The warning is a result of the initial create migration for the Identity model not being up-to-date. This will be fixed in the next version.

  • dnx ef database update Updates the database, that is, applies the migrations.

Test the app

  • Run the app and tap the Mvc Movie link
  • Tap the Create New link and create a movie
../../_images/movies.png

Note

You may not be able to enter decimal points or commas in the Price field. To support jQuery validation for non-English locales that use a comma (”,”) for a decimal point, and non US-English date formats, you must take steps to globalize your app. See Additional resources for more information. For now, just enter whole numbers like 10.

Tapping Create causes the form to be posted to the server, where the movie information is saved in a database. You are then redirected to the /Movies URL, where you can see the newly created movie in the listing.

../../_images/h.png

Create a couple more movie entries. Try the Edit, Details, and Delete links, which are all functional.

Examining the Generated Code

Open the Controllers/MoviesController.cs file and examine the generated Index method. A portion of the movie controller with the Index method is shown below:

public class MoviesController : Controller
{
    private ApplicationDbContext _context;

    public MoviesController(ApplicationDbContext context)
    {
        _context = context;
    }


    public IActionResult Index() {
        return View(_context.Movie.ToList());
    }

The constructor uses Dependency Injection to inject the database context into the controller. The database context is used in each of the CRUD methods in the controller.

A request to the Movies controller returns all the entries in the Movies table and then passes the data to the Index view.

Strongly typed models and the @model keyword

Earlier in this tutorial, you saw how a controller can pass data or objects to a view template using the ViewData dictionary. The ViewData dictionary is a dynamic object that provides a convenient late-bound way to pass information to a view.

MVC also provides the ability to pass strongly typed objects to a view template. This strongly typed approach enables better compile-time checking of your code and richer IntelliSense in the Visual Studio editor. The scaffolding mechanism in Visual Studio used this approach (that is, passing a strongly typed model) with the MoviesController class and view templates when it created the methods and views.

Examine the generated Details method in the Controllers/MoviesController.cs file. The Details method is shown below.

// GET: Movies/Details/5
public IActionResult Details(int? id)
{
    if (id == null)
    {
        return HttpNotFound();
    }

    Movie movie = _context.Movie.Single(m => m.ID == id);
    if (movie == null)
    {
        return HttpNotFound();
    }

    return View(movie);
}

The id parameter is generally passed as route data, for example http://localhost:1234/movies/details/1 sets:

  • The controller to the movies controller (the first URL segment)
  • The action to details (the second URL segment)
  • The id to 1 (the last URL segment)

You could also pass in the id with a query string as follows:

http://localhost:1234/movies/details?id=1

If a Movie is found, an instance of the Movie model is passed to the Details view:

return View(movie);

Examine the contents of the Views/Movies/Details.cshtml file:

@model MvcMovie.Models.Movie

@{
    ViewData["Title"] = "Details";
}

<h2>Details</h2>

<div>
    <h4>Movie</h4>
    <hr />
    <dl class="dl-horizontal">
        <dt>
            @Html.DisplayNameFor(model => model.Genre)
        </dt>
        <dd>
            @Html.DisplayFor(model => model.Genre)
        </dd>
        <dt>
            @Html.DisplayNameFor(model => model.Price)
        </dt>
        <dd>
            @Html.DisplayFor(model => model.Price)
        </dd>
        <dt>
            @Html.DisplayNameFor(model => model.ReleaseDate)
        </dt>
        <dd>
            @Html.DisplayFor(model => model.ReleaseDate)
        </dd>
        <dt>
            @Html.DisplayNameFor(model => model.Title)
        </dt>
        <dd>
            @Html.DisplayFor(model => model.Title)
        </dd>
    </dl>
</div>
<p>
    <a asp-action="Edit" asp-route-id="@Model.ID">Edit</a> |
    <a asp-action="Index">Back to List</a>
</p>

By including a @model statement at the top of the view template file, you can specify the type of object that the view expects. When you created the movie controller, Visual Studio automatically included the following @model statement at the top of the Details.cshtml file:

@model MvcMovie.Models.Movie

This @model directive allows you to access the movie that the controller passed to the view by using a Model object that’s strongly typed. For example, in the Details.cshtml template, the code passes each movie field to the DisplayNameFor and DisplayFor HTML Helpers with the strongly typed Model object. The Create and Edit methods and view templates also pass a Movie model object.

Examine the Index.cshtml view template and the Index method in the Movies controller. Notice how the code creates a List object when it calls the View helper method in the Index action method. The code then passes this Movies list from the Index action method to the view:

public IActionResult Index()
{
       return View(_context.Movie.ToList());
}

When you created the movies controller, Visual Studio automatically included the following @model statement at the top of the Index.cshtml file:

@model IEnumerable<MvcMovie.Models.Movie>

The @model directive allows you to access the list of movies that the controller passed to the view by using a Model object that’s strongly typed. For example, in the Index.cshtml template, the code loops through the movies with a foreach statement over the strongly typed Model object:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
@model IEnumerable<MvcMovie.Models.Movie>

@{
    ViewData["Title"] = "Index";
}

<h2>Index</h2>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.Genre)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Price)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.ReleaseDate)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Title)
        </th>
        <th></th>
    </tr>
    
@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Genre)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Price)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.ReleaseDate)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Title)
        </td>
        <td>
            <a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
            <a asp-action="Details" asp-route-id="@item.ID">Details</a> |
            <a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
        </td>
    </tr>
}
</table>

Because the Model object is strongly typed (as an IEnumerable<Movie> object), each item in the loop is typed as Movie. Among other benefits, this means that you get compile-time checking of the code and full IntelliSense support in the code editor:

../../_images/ints.png

Note

The RC1 version of the scaffolding engine generates HTML Helpers to display fields (@Html.DisplayNameFor(model => model.Genre)). The next version will use Tag Helpers to render fields.

You now have a database and pages to display, edit, update and delete data. In the next tutorial, we’ll work with the database.