将模型添加到 ASP.NET Core MVC 应用

作者:Rick AndersonTom Dykstra

在本部分中将添加用于管理数据库中的电影的类。 这些类将是 MVC 应用的“Model”部分 。

可以结合 Entity Framework Core (EF Core) 使用这些类来处理数据库。 EF Core 是对象关系映射 (ORM) 框架,可以简化需要编写的数据访问代码。

要创建的模型类称为 POCO 类(源自“简单传统 CLR 对象”),因为它们与 EF Core 没有任何依赖关系 。 它们只定义将存储在数据库中的数据的属性。

在本教程中,首先要编写模型类,然后 EF Core 将创建数据库。

添加数据模型类

使用以下代码更新 Movie.cs 文件 :

using System;
using System.ComponentModel.DataAnnotations;

namespace MvcMovie.Models
{
    public class Movie
    {
        public int Id { get; set; }
        public string Title { get; set; }

        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }
        public string Genre { get; set; }
        public decimal Price { get; set; }
    }
}

Movie 类包含一个 Id 字段,数据需要该字段作为主键。

ReleaseDate 上的 DataType 特性指定数据的类型 (Date)。 通过此特性:

  • 用户无需在数据字段中输入时间信息。
  • 仅显示日期,而非时间信息。

DataAnnotations 会在后续教程中介绍。

添加 NuGet 包

创建数据库上下文类

需要一个数据库上下文类来协调 Movie 模型的 EF Core 功能(创建、读取、更新和删除)。 数据库上下文派生自 Microsoft.EntityFrameworkCore.DbContext 并指定要包含在数据模型中的实体。

创建一个“Data”文件夹 。

使用以下代码添加 Data/MvcMovieContext.cs 文件 :

using Microsoft.EntityFrameworkCore;
using MvcMovie.Models;

namespace MvcMovie.Data
{
    public class MvcMovieContext : DbContext
    {
        public MvcMovieContext (DbContextOptions<MvcMovieContext> options)
            : base(options)
        {
        }

        public DbSet<Movie> Movie { get; set; }
    }
}

前面的代码为实体集创建 DbSet<Movie> 属性。 在实体框架术语中,实体集通常与数据表相对应。 实体对应表中的行。

注册数据库上下文

ASP.NET Core 通过依赖关系注入 (DI) 生成。 在应用程序启动过程中,必须向 DI 注册服务(如 EF Core DB 上下文)。 需要这些服务(如 Razor 页面)的组件通过构造函数提供相应服务。 本教程的后续部分介绍了用于获取 DB 上下文实例的构造函数代码。 本部分会将数据库上下文注册到 DI 容器。

将以下 using 语句添加到 Startup.cs 顶部 :

using MvcMovie.Data;
using Microsoft.EntityFrameworkCore;

将以下突出显示的代码添加到 Startup.ConfigureServices

通过调用 DbContextOptions 对象中的一个方法将连接字符串名称传递到上下文。 进行本地开发时, ASP.NET Core 配置系统appsettings.json 文件中读取数据库连接字符串。

添加数据库连接字符串

将连接字符串添加到 appsettings.json 文件 :

生成项目以检查编译器错误。

基架电影页面

使用基架工具为电影模型生成“创建”、“读取”、“更新”和“删除”(CRUD) 页面。

你还不能使用基架页面,因为该数据库不存在。 如果运行应用并单击“Movie App”链接,则会出现“无法打开数据库”或“无此类表 : Movie”错误消息。

初始迁移

使用 EF Core 迁移功能来创建数据库。 迁移是可用于创建和更新数据库以匹配数据模型的一组工具。

InitialCreate 类

检查 Migrations/{timestamp}_InitialCreate.cs 迁移文件 :

public partial class Initial : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.CreateTable(
            name: "Movie",
            columns: table => new
            {
                Id = table.Column<int>(nullable: false)
                    .Annotation("SqlServer:ValueGenerationStrategy", 
                                 SqlServerValueGenerationStrategy.IdentityColumn),
                Title = table.Column<string>(nullable: true),
                ReleaseDate = table.Column<DateTime>(nullable: false),
                Genre = table.Column<string>(nullable: true),
                Price = table.Column<decimal>(nullable: false)
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_Movie", x => x.Id);
            });
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropTable(
            name: "Movie");
    }
}

Up 方法创建 Movie 表,并将 Id 配置为主键。 Down 方法可还原 Up 迁移所做的架构更改。

测试应用

  • 运行应用并单击“Movie App”链接 。

    如果遇到类似于以下情况的异常:

可能缺失迁移步骤

  • 测试“创建”页 。 输入并提交数据。

    备注

    可能无法在 Price 字段中输入十进制逗号。 若要使 jQuery 验证支持使用逗号(“,”)表示小数点的非英语区域设置,以及支持非美国英语日期格式,应用必须进行全球化。 有关全球化的说明,请参阅此 GitHub 问题

  • 测试“编辑”、“详细信息”和“删除”页 。

控制器中的依赖项注入

强类型模型和 @model 关键词

在本教程之前的内容中,已经介绍了控制器如何使用 ViewData 字典将数据或对象传递给视图。 ViewData 字典是一个动态对象,提供了将信息传递给视图的方便的后期绑定方法。

MVC 还提供将强类型模型对象传递给视图的功能。 此强类型方法启用编译时代码检查。 基架机制通过 MoviesController 类和视图使用了此方法(即传递强类型模型)。

检查 Controllers/MoviesController.cs 文件中生成的 Details 方法 :

// GET: Movies/Details/5
public async Task<IActionResult> Details(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie
        .FirstOrDefaultAsync(m => m.Id == id);
    if (movie == null)
    {
        return NotFound();
    }

    return View(movie);
}

id 参数通常作为路由数据传递。 例如 https://localhost:5001/movies/details/1 的设置如下:

  • 控制器被设置为 movies 控制器(第一个 URL 段)。
  • 操作被设置为 details(第二个 URL 段)。
  • ID 被设置为 1(最后一个 URL 段)。

还可以使用查询字符串传入 id,如下所示:

https://localhost:5001/movies/details?id=1

在未提供 ID 值的情况下,id 参数可定义为可以为 null 的类型 (int?)。

Lambda 表达式会被传入 FirstOrDefaultAsync 以选择与路由数据或查询字符串值相匹配的电影实体。

var movie = await _context.Movie
    .FirstOrDefaultAsync(m => m.Id == id);

如果找到了电影,Movie 模型的实例则会被传递到 Details 视图:

return View(movie);

检查 Views/Movies/Details.cshtml 文件的内容 :

@model MvcMovie.Models.Movie

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

<h1>Details</h1>

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

视图文件顶部的 @model 语句可指定视图期望的对象类型。 创建影片控制器时,将包含以下 @model 语句:

@model MvcMovie.Models.Movie

@model 指令允许访问控制器传递给视图的影片。 Model 对象为强类型对象。 例如,在 Details.cshtml 视图中,代码通过强类型的 Model 对象将每个电影字段传递给 DisplayNameForDisplayForHTML 帮助程序 。 CreateEdit 方法以及视图也传递一个 Movie 模型对象。

检查电影控制器中的 Index.cshtml 视图和 Index 方法 。 请注意代码在调用 View 方法时是如何创建 List 对象的。 代码将此 Movies 列表从 Index 操作方法传递给视图:

// GET: Movies
public async Task<IActionResult> Index()
{
    return View(await _context.Movie.ToListAsync());
}

创建影片控制器后,基架将以下 @model 语句包含在 Index.cshtml 文件的顶部 :

@model IEnumerable<MvcMovie.Models.Movie>

@model 指令使你能够使用强类型的 Model 对象访问控制器传递给视图的电影列表。 例如,在 Index.cshtml 视图中,代码使用 foreach 语句通过强类型 Model 对象对电影进行循环遍历 :

@model IEnumerable<MvcMovie.Models.Movie>

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

<h1>Index</h1>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <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></th>
        </tr>
    </thead>
    <tbody>
@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>
                <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>
}
    </tbody>
</table>

因为 Model 对象为强类型(作为 IEnumerable<Movie> 对象),因此循环中的每个项都被类型化为 Movie 除其他优点之外,这意味着可对代码进行编译时检查。

其他资源

上一篇:将视图添加到 ASP.NET Core MVC 应用

下一篇:在 ASP.NET Core 中使用 SQL

关注微信小程序
程序员编程王-随时随地学编程

扫描二维码
程序员编程王

扫一扫关注最新编程教程