推荐
关注
功能
  • 分享到微博
  • 分享到微信
  • 分享到豆瓣
  • 分享到 QQ
  • 分享到 QZone
  • 收藏到博客园
  • 联系博主
TOP
Message

ASP.NET Core 中文文档 第二章 指南(4.4)添加 Model

原文:Adding a model
作者:Rick Anderson
翻译:娄宇(Lyrics)
校对:许登洋(Seay)孟帅洋(书缘)姚阿勇(Mr.Yao)夏申斌

在这一节里,你将添加一些类来管理数据库中的电影数据。这些类将成为 MVC 应用程序中的 “Model” 部分。

你将使用 .NET Framework 中名为 Entity Framework Core 的数据库访问技术来定义和使用这些数据模型类。Entity Framework Core (通常被称为 EF Core) 有一种具有特色的被称为 Code First 的开发模式。你先编写代码,然后通过这些代码创建数据库表。 Code First 允许你通过编写一些简单的类(也被称为 POCO 类, "plain-old CLR objects." )来创建数据模型对象,然后根据你的类创建数据库。如果你需要先创建数据库,你仍然可以按照本教程来学习 MVC 和 EF 应用程序开发。

使用个人用户账户身份认证创建新项目

在 Visual Studio 当前版本的 ASP.NET Core MVC 工具中,仅在以个人用户账户身份认证方式创建新项目时支持通过基架生成模型。我们希望在下一个工具更新中修复这个问题。直到问题被修复之前,你需要以相同的名称创建新项目。因为项目有相同的名字,你需要在其他的文件夹中创建。

在 Visual studio 起始页(Start Page),点击 新建项目(New Project)

或者,你可以使用菜单来创建新项目。点击 文件(File)> 新建(New) > 项目(Project)

完成 新建项目(New Project) 对话框:

  • 在左窗格,点击 Web
  • 在中间窗格,点击 ASP.NET Core Web Application (.NET Core)
  • 将位置更改为你创建的前一个项目的不同目录,否则你将遇到错误
  • 命名项目为“MvcMovie”(将项目命名为“MvcMovie”非常重要,当你复制代码时,命名空间将会匹配)
  • 点击 确定(OK)

警告
在本教程中,你必须将 身份验证(Authentication) 设置为 个人用户账户(Individual User Accounts) ,以便基架引擎能正常工作(译者注:不同的身份认证通过基架引擎生成的代码不一样,为了教程顺利进行,此处必须选用个人用户账户的认证方式)。

New ASP.NET Core Web Application - MvcMovie 对话框中:

  • 点击 Web 应用程序(Web Application)
  • 点击 更改身份验证(Change Authentication) 按钮并将身份验证改为 Individual User Accounts(个人用户账户) 之后点击 确定(OK)

按照 change-title-link-reference-label 的指示你可以点击 MvcMovie 链接来调用 Movie 控制器(Controller)。我们将在本教程中通过基架生成 Movie 控制器(Controller)。

添加数据模型类

在解决方案资源管理器中,右键点击 Models 文件夹 > 添加 > 。将类名命名为 Movie 并且添加以下属性:

using System;

namespace MvcMovie.Models
{
    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; }
    }
}

除了你用来构造电影的属性,还需要一个 ID 字段来作为数据库主键。生成项目。如果你没有生成这个应用程序,你将在下一节中遇到错误。我们终于为这个 MVC 应用程序添加了一个 Model 。

通过基架生成一个控制器(Controller)

解决方案资源管理器 中,右键点击 Controllers 文件夹 > 添加 > 控制器

添加基架 对话框中,点击 MVC Controller with views, using Entity Framework > 添加

完成 添加控制器(Add Controller) 对话框

  • 模型类(Model class): Movie(MvcMovie.Models)
  • 数据上下文类(Data context class): ApplicationDbContext(MvcMovie.Models)
  • 视图(Views): 保持默认的选项
  • 控制器名称(Controller name): 保持默认的 MoviesController
  • 点击 添加(Add)

Visual Studio 基架引擎创建的东西如下:

  • 一个电影控制器(Controller)(Controllers/MoviesController.cs
  • Create、Delete、Details、Edit 以及 Index 的 Razor 视图文件(Views/Movies)

Visual Studio 为你自动创建 CRUD(创建、读取、更新以及删除)Action 方法和视图(View)(自动创建 CRUD Action 方法和 View 视图被称为 搭建基架(scaffolding))。很快你将拥有一个可以让你创建、查看、编辑以及删除电影条目的完整功能的 Web 应用程序。

运行这个应用程序并且点击 Mvc Movie 链接。你将遇到以下错误:

我们将按照这些指示来为 Movie 应用程序准备好数据库。

更新数据库

警告
你必须在更新数据库之前停止 IIS Express。

停止 IIS Express:

  • 右键点击通知区域的 IIS Express 系统托盘图标

  • 点击 退出(Exit) 或者 停止站点(Stop Site)

  • 除此之外, 你可以退出并重启 Visual Studio

  • 在项目文件夹(MvcMovie/src/MvcMovie)打开命令提示符。按照以下说明,以一个快捷的方式打开项目文件夹

    • 打开一个在项目根目录下的文件(在这个例子中,使用 Startup.cs )。
    • 右键点击 Startup.cs > 打开所在的文件夹(Open Containing Folder)

    • Shift + 右键点击一个文件夹 > 在此处打开命令窗口(Open command window here)

    • 运行 cd .. 将路径退回项目文件夹
  • 在命令提示符中运行以下命令:

  dotnet ef migrations add Initial
  dotnet ef database update

注意
如果 IIS-Express 在运行中,你会遇到错误 CS2012: Cannot open 'MvcMovie/bin/Debug/netcoreapp1.0/MvcMovie.dll' for writing -- 'The process cannot access the file 'MvcMovie/bin/Debug/netcoreapp1.0/MvcMovie.dll' because it is being used by another process.'

dotnet ef 命令

  • dotnet (.NET Core) 是 .NET 的跨平台实现。你可以在这里了解它。
  • dotnet ef migrations add Initial 运行 Entity Framework .NET Core CLI 迁移命令并创建初始化迁移。参数 "Initial" 可以是任意值,但是通常用这个作为第一个(初始的) 数据库迁移。这个操作创建了一个 Data/Migrations/_Initial.cs 文件,这个文件包含了添加(或删除)Movie 表到数据库的迁移命令。
  • dotnet ef database update dotnet ef database update 用我们刚刚创建的迁移来更新数据库。

测试一下

注意
如果你的浏览器不能连接到 Movie 应用程序,你可能需要等待 IIS Express 加载它。它有时需要 30 秒来构建应用程序并准备好响应请求。

  • 运行应用程序并点击 Mvc Movie 链接
  • 点击 Create New 链接并创建电影

注意
你也许不能在 Price 字段中输入小数点或逗号。为了实现对非英语环境中用逗号(",")来表示小数点,以及非美国英语日期格式的 jQuery 验证,你必须采取措施国际化你的应用程序。查看额外的资源获取更多的信息。现在仅仅输入完整的数字,比如10。


注意
在某些地区你需要指定日期格式。查看下方高亮代码。

点击 Create 提交表单到服务器,将电影数据保存到数据库中。然后重定向到 /Movies URL ,你可以在列表中看到新创建的电影。

using System;
using System.ComponentModel.DataAnnotations; //手动高亮

namespace MvcMovie.Models
{
    public class Movie
    {
        public int ID { get; set; }
        public string Title { get; set; }
        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)] //手动高亮
        public DateTime ReleaseDate { get; set; }
        public string Genre { get; set; }
        public decimal Price { get; set; }
    }
}

再创建几个电影条目。尝试 EditDetailsDelete 链接来执行各个功能。

检查生成的代码

打开 Controllers/MoviesController.cs 文件并检查生成的 Index 方法。 MoviesController 中包含 Index 方法的部分如下所示:

public class MoviesController : Controller
{
    private readonly ApplicationDbContext _context;

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

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

构造函数使用依赖注入将数据库上下文注入到控制器(Controller)。 数据上下文在控制器(Controller)中被用来执行增删改查(CRUD)方法。

一个到 MoviesController 的请求从 Movies 表返回所有的条目,然后传递数据到 Index 视图 (View) 。

强类型模型与 @model 关键字

在之前的教程中,你看到了控制器(Controller)如何通过 ViewData 字典传递数据到一个视图(View)。 ViewData 字典是一个动态类型对象,它提供了一种便捷的后期绑定方式将信息传递给视图。

MVC 也提供了传递强类型数据给视图的能力。这种强类型的方式可以提供给你更好的代码编译时检查,并在 Visual Studio(VS) 中具有更丰富的智能感知。VS 中的基架机制在为 MoviesController 类创建方法(Action)和视图(View)的时候就采用了这种方式(即,传递强类型模型)。

检查在 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.SingleOrDefaultAsync(m => m.ID == id);
    if (movie == null)
    {
        return NotFound();
    }

    return View(movie);
}

id 参数一般作为路由数据传递,例如 http://localhost:1234/movies/details/1 将:

  • Controller 设置为 movies(对应第一个 URL 段)
  • Action 设置为 details(对应第二个 URL 段)
  • id 设置为 1(对应最后一个 URL 段)

你也可以向下面一样通过查询字符串(Query String)传递 id

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

如果电影被找到了, Movie 模型(Model)的实例将被传递给 Details 视图(View)。

  return View(movie);

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

@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>
<div>
    <a asp-action="Edit" asp-route-id="@Model.ID">Edit</a> |
    <a asp-action="Index">Back to List</a>
</div>

通过在视图(View Template)文件顶部加入一个 @model 语句,你可以指定视图(View)所期望的对象类型。当你创建这个 MoviesController 时, Visual Studio 自动在 Details.cshtml 顶部加入了 @model 语句后面的部分。

  @model MvcMovie.Models.Movie

@model 指令允许你访问从控制器(Controller)传递给视图(View)的这个强类型电影 Model 对象。例如,在 Details.cshtml 视图中,代码用强类型 Model 对象传递所有的电影字段到 DisplayNameForDisplayFor HTML 帮助类(HTML Helper)里。 CreateEdit 方法和视图(View)也传递一个 Movie 模型(Model)对象。

检查 Index.cshtml 视图(View)和 MoviesController 里的 Index 方法。注意观察代码在调用 View 方法时,是如何创建一个 列表(List) 对象的。这段代码将 Movies 列表从 Index Action 方法传递给视图(View):

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

当你创建这个 MoviesController 时,Visual Studio 自动在 Index.cshtml 顶部加入以下 @model 语句:

@model IEnumerable<MvcMovie.Models.Movie>

@model 指令允许你访问电影列表这个从控制器(Controller)传递给视图(View)的强类型 Model 对象。例如,在 Index.cshtml 视图中,代码通过 foreach 语句遍历了电影列表这个强类型的 模型(Model) 对象。

@model IEnumerable<MvcMovie.Models.Movie>   <!--手动高亮-->

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

<h2>Index</h2>
<p>
    <a asp-action="Create">Create New</a>
</p>

<table class="table">
    <thead>
        <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>
    </thead>
    <tbody>
@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>
}
    </tbody>
</table>

因为 模型(Model) 对象是强类型的(作为 IEnumerable<Movie> 对象),循环中的每一个 item 的类型被类型化为 Movie 。除了其他好处外,这意味着你将获得代码的编译时检查以及在代码编辑器里得到完整的智能感知支持:

现在你有了数据库和用于显示、编辑、更新以及删除数据的页面。在下一篇教程中,我们将学习使用数据库。

额外的资源

修订历史

  1. 2016/07/08,MS1;
  2. 2016/07/09,修订至 1.0.0

返回目录

posted @ 2016-06-16 09:08  .NET_CORE_COMMUNITY  阅读(12143)  评论(23编辑  收藏  举报