索引:
Adding a model to an ASP.NET Core MVC app
在 asp.net core mvc 中添加一个model (模型)
2017-3-30 8 分钟阅读时长
本文内容
1. Add a data model class
添加一个数据模型类
2. Scaffolding a controller
控制器基架
3. Add EF tooling and perform initial migration
添加EF工具并做基本迁移
4. Test the app
测试应用
5. Dependency Injection
依赖注入
6. Strongly typed models and the @model keyword
强类型模型与 @model 关键字
7. Additional resources
附加资源
By Rick Anderson and Tom Dykstra
In this section you'll add some classes for managing movies in a database.
在本节,我们将添加一些类用于在db中管理 movies。
These classes will be the "Model" part of the MVC app.
这些类是 MVC 中的 Model部分。
You’ll use these classes with the Entity Framework Core (EF Core) to work with a database.
我们将使用 EF core 在DB上操作这些类与数据。
EF Core is an object-relational mapping (ORM) framework that simplifies the data-access code that you have to write.
EF core 是一个对象关系映射框架,可以简化操作数据库所需要写的代码及代码量。
For this tutorial you'll use SQLite, but EF Core supports many database engines.
本教程中我们使用 SQLite数据库,当然EF core 支持很多种数据库。
The model classes you'll create are known as POCO classes (from "plain-old CLR objects") because they don't have any dependency on EF Core.
我们将创建一些简单模型类,因为他们对EF core 没有任何依赖。
They just define the properties of the data that will be stored in the database.
仅在类中定义DB中所要存储的字段属性。
In this tutorial you'll write the model classes first, and EF Core will create the database.
在本教程中,我们采用 Code First 模式,先定义类,再用EF core 创建DB.
An alternate approach not covered here is to generate model classes from an already-existing database.
另一种做法是DB First 模式,用一个已存在的DB自动生成数据模型类。
For information about that approach, see ASP.NET Core - Existing Database.
查看文章 ASP.NET Core - Existing Database. 以获取更多关于DB First 模式的信息。
Add a data model class
添加一个数据模型类
In Solution Explorer, right click the MvcMovie project > Add > New Folder. Name the folder Models.
在解决方案资源管理器中,右击 MvcMovie 项目 > Add > New Folder 菜单。并命名文件夹为 Models 。
Right click the Models folder > Add > Class. Name the class Movie and add the following properties:
右击 Models 文件夹 > Add > Class 菜单。命名类的名字为Movie ,并在其中添加如下的属性代码:
1 using System; 2 3 namespace MvcMovie.Models 4 { 5 public class Movie 6 { 7 public int ID { get; set; } 8 public string Title { get; set; } 9 public DateTime ReleaseDate { get; set; } 10 public string Genre { get; set; } 11 public decimal Price { get; set; } 12 } 13 }
The ID field is required by the database for the primary key.
ID 字段是数据库要求必须有的主键。
Build the project to verify you don't have any errors. You now have a Model in your MVC app.
编译项目检查确保没有错误。现在我们在程序中就有了MVC中的M。
Scaffolding a controller
控制器基架
In Solution Explorer, right-click the Controllers folder > Add > Controller.
在解决方案资源管理器中,右击 Controllers 文件夹,选择 > Add > Controller 菜单。
In the Add MVC Dependencies dialog, select Minimal Dependencies, and select Add.
在Add MVC Dependencies 对话框中,选择 Minimal Dependencies 并点击Add 按钮。
Visual Studio adds the dependencies needed to scaffold a controller, but the controller itself is not created.
VS会添加控制器基架所需的依赖项,但控制器现在还没有被创建。
The next invoke of > Add > Controller creates the controller.
继续点击 > Add > Controller 菜单,会添加一个控制器。
In Solution Explorer, right-click the Controllers folder > Add > Controller.
在解决方案资源管理器中,右击 Controllers 文件夹并选择> Add > Controller 菜单。
In the Add Scaffold dialog, tap MVC Controller with views, using Entity Framework > Add.
在 Add Scaffold 对话框中,点击 MVC Controller with views, using Entity Framework 选项并点击Add 按钮。
Complete the Add Controller dialog:
完成 Add Controller 对话框:
• Model class: Movie (MvcMovie.Models)
Model class :Movie (MvcMovie.Models)(前边儿添加的模型类)
• Data context class: Select the + icon and add the default MvcMovie.Models.MvcMovieContext
Data context class :点击 + 按钮并添加默认的 MvcMovie.Models.MvcMovieContext 。
• Views: Keep the default of each option checked
Views:保持默认的选项选择状态
• Controller name: Keep the default MoviesController
Controller name:保持默认的名字 MoviesController 。
• Tap Add
点击 Add 按钮。
Visual Studio creates:
VS将会创建如下项:
• An Entity Framework Core database context class (Data/MvcMovieContext.cs)
一个 EF Core 数据上下文类:Data/MvcMovieContext.cs
• A movies controller (Controllers/MoviesController.cs)
一个控制器类:Controllers/MoviesController.cs
• Razor view files for Create, Delete, Details, Edit and Index pages (Views/Movies/.cshtml*)
CRUD的视图文件:Views/Movies/.cshtml*
The automatic creation of the database context and CRUD (create, read, update, and delete) action methods and views is known as scaffolding.
自动创建 DB上下文类,CRUD 控制器 方法及相应视图的工具是一个 被称为基架。
You'll soon have a fully functional web application that lets you manage a movie database.
你马上就会有一个完整功能的web应用,可以让你管理一个 movie DB。
If you run the app and click on the Mvc Movie link, you'll get an error similar to the following:
如果你运行应用并点击 Mvc Movie 链接,你会看到如下一个错误提示:
An unhandled exception occurred while processing the request. SqlException: Cannot open database "MvcMovieContext-<GUID removed>" requested by the login. The login failed. Login failed for user Rick
You need to create the database, and you'll use the EF Core Migrations feature to do that.
你需要创建一个DB,我们将用EF Core的Migrations 特性来实现。
Migrations lets you create a database that matches your data model and update the database schema when your data model changes.
Migrations 特性可以让你由项目中的Models创建一个DB,并且当model变化时会将变化同步到DB结构中。
Add EF tooling and perform initial migration
添加EF工具并执行初始化迁移
In this section you'll use the Package Manager Console (PMC) to:
在本节,我们将使用包管理控制台:
• Add the Entity Framework Core Tools package. This package is required to add migrations and update the database.
添加 EF core 工具包。这个包要求有migrations 及更新 db。
• Add an initial migration.
添加一个初始化的migration
• Update the database with the initial migration.
用初始化的migration 更新数据库。
From the Tools menu, select NuGet Package Manager > Package Manager Console.
在Tools 菜单,选择 NuGet Package Manager > Package Manager Console 菜单:
In the PMC, enter the following commands:
在 PMC 命令板上,输入下面的命令:
Install-Package Microsoft.EntityFrameworkCore.Tools Add-Migration Initial Update-Database
The Add-Migration command creates code to create the initial database schema.
Add-Migration 命令生成了初始化db结构的代码。
The schema is based on the model specified in the DbContext(In the *Data/MvcMovieContext.cs file).
Db结构 基于专门创建的 DbContext 模型类。
The Initialargument is used to name the migrations. You can use any name, but by convention you choose a name that describes the migration.
Initial 参数用于命名migrations 。你可以在这里使用任何名字,但是习惯上要使用一个可以描述 migration 的名字。
See Introduction to migrations for more information.
查看 Introduction to migrations 可以获得更多信息。
The Update-Database command runs the Up method in the Migrations/<time-stamp>_InitialCreate.csfile, which creates the database.
Update-Database 命令执行了 Migrations/<time-stamp>_InitialCreate.csfile 文件中的 Up 方法创建DB。
Test the app
测试应用
• Run the app and tap the Mvc Movie link.
运行应用并点击 Mvc Movie 链接。
• Tap the Create New link and create a movie.
点击 Create New 链接并创建一条电影。
• You may not be able to enter decimal points or commas in the Price field.
你可能不能在 Price 字段里输入小数点或逗号。
To support jQuery validation for non-English locales that use a comma (",") for a decimal point,
使用 jQuery validation 支持在非英文场景使用逗号与小数点,
and non US-English date formats, you must take steps to globalize your app.
以及非美式日期格式,你需要做一些操作来全球化你的应用。
See Additional resourcesfor more information.
查看 Additional resources 可以获得更多信息。
For now, just enter whole numbers like 10.
目前,我先只输入像10这样的整数。
• In some locales you need to specify the date format. See the highlighted code below.
在某些场景,你需要专门指定特殊的日期格式。看下面高亮的代码部分:
1 using System; 2 using System.ComponentModel.DataAnnotations; 3 4 namespace MvcMovie.Models 5 { 6 public class Movie 7 { 8 public int ID { get; set; } 9 public string Title { get; set; } 10 [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)] 11 public DateTime ReleaseDate { get; set; } 12 public string Genre { get; set; } 13 public decimal Price { get; set; } 14 } 15 }
We'll talk about DataAnnotations later in the tutorial.
我们将在本教程的后面讲解数据注解。
Tapping Create causes the form to be posted to the server, where the movie information is saved in a database.
点击 Create 将会向服务器发送表单,然后电影数据的信息就会保存到数据库。
The app redirects to the /Movies URL, where the newly created movie information is displayed.
应用重定向到 /Movies 地址,在这个页面,新创建的电影信息就会显示出来。
Create a couple more movie entries. Try the Edit, Details, and Delete links, which are all functional.
创建更多的电影条目,尝试 Edit, Details, and Delete 链接操作,他们都是功能完整的。
Dependency Injection
依赖注入
Open the Startup.cs file and examine ConfigureServices:
打开 Startup.cs 文件,并查看 ConfigureServices 方法:
1 public void ConfigureServices(IServiceCollection services) 2 { 3 // Add framework services. 4 services.AddMvc(); 5 6 services.AddDbContext<MvcMovieContext>(options => 7 options.UseSqlServer(Configuration.GetConnectionString("MvcMovieContext"))); 8 }
The highlighted code above shows the movie database context being added to the Dependency Injection container.
上面高亮的代码显示 movie DB上下文已经添加到了DI容器中。
The line following services.AddDbContext<MvcMovieContext>(options => is not shown (see your code).
services.AddDbContext<MvcMovieContext>(options => 这行代码下的代码没有展示(查看代码文件就能看到)。
It specifies the database to use and the connection string. => is a lambda operator.
它指定了数据库使用的连接字符串。=> 符号是 lambda 操作符。
Open the Controllers/MoviesController.cs file and examine the constructor:
打开 Controllers/MoviesController.cs 文件并查看构造函数:
1 public class MoviesController : Controller 2 { 3 private readonly MvcMovieContext _context; 4 5 public MoviesController(MvcMovieContext context) 6 { 7 _context = context; 8 }
The constructor uses Dependency Injection to inject the database context (MvcMovieContext) into the controller.
构造函数使用 DI 注入DB上下文到控制器中。
The database context is used in each of the CRUD methods in the controller.
DB上下文将会在控制器中的每个CRUD方法中使用。
Strongly typed models and the @model keyword
强类型Model与@model 关键字
Earlier in this tutorial, you saw how a controller can pass data or objects to a view using the ViewDatadictionary.
在教程的前面部分,你已经明白如何用 ViewData 字典将数据从控制器传递给视图使用。
The ViewData dictionary is a dynamic object that provides a convenient late-bound way to pass information to a view.
ViewData 字典是一个动态对象,它提供了一个后绑定方式以传递数据到视图中。
MVC also provides the ability to pass strongly typed model objects to a view.
MVC同时也提供了向视图传递强类型视图的方式。
This strongly typed approach enables better compile-time checking of your code.
强类型在编译代码时能更好的检查你的代码。
The scaffolding mechanism used this approach (that is, passing a strongly typed model) with the MoviesController class and views when it created the methods and views.
基架的机制使用的类似这种,在创建控制器方法与视图的时候。
Examine the generated Details method in the Controllers/MoviesController.cs file:
在 Controllers/MoviesController.cs 文件中查看自动生成的 Details 方法:
1 // GET: Movies/Details/5 2 public async Task<IActionResult> Details(int? id) 3 { 4 if (id == null) 5 { 6 return NotFound(); 7 } 8 9 var movie = await _context.Movie 10 .SingleOrDefaultAsync(m => m.ID == id); 11 if (movie == null) 12 { 13 return NotFound(); 14 } 15 16 return View(movie); 17 }
The id parameter is generally passed as route data. For example http://localhost:5000/movies/details/1 sets:
id 参数通常是路由参数传递过来的。例如 http://localhost:5000/movies/details/1 中有多个路由段:
• The controller to the movies controller (the first URL segment).
第一段是 movies 控制器。
• The action to details (the second URL segment).
第二段是 details action方法。
• The id to 1 (the last URL segment).
第三段是 id=1 参数。
You can also pass in the id with a query string as follows:
当然你也可以吧 id 参数放到查询字符串里面,如下URL:
http://localhost:1234/movies/details?id=1
The id parameter is defined as a nullable type (int?) in case an ID value is not provided.
id 参数被定义为了可空类型,以适应ID未提供的情况。
A lambda expression is passed in to SingleOrDefaultAsync to select movie entities that match the route data or query string value.
一个lambda 表达式 被做为 SingleOrDefaultAsync 方法的参数以找出相应的数据实体(与路由参数或查询字符串参数一致的的)。
1 var movie = await _context.Movie 2 .SingleOrDefaultAsync(m => m.ID == id);
If a movie is found, an instance of the Movie model is passed to the Details view:
如果数据实体被找到,则会如代码所示的方式传递给视图:
1 return View(movie);
Examine the contents of the Views/Movies/Details.cshtml file:
查看 Views/Movies/Details.cshtml 文件的内容,如下:
1 @model MvcMovie.Models.Movie 2 3 @{ 4 ViewData["Title"] = "Details"; 5 } 6 7 <h2>Details</h2> 8 9 <div> 10 <h4>Movie</h4> 11 <hr /> 12 <dl class="dl-horizontal"> 13 <dt> 14 @Html.DisplayNameFor(model => model.Title) 15 </dt> 16 <dd> 17 @Html.DisplayFor(model => model.Title) 18 </dd> 19 <dt> 20 @Html.DisplayNameFor(model => model.ReleaseDate) 21 </dt> 22 <dd> 23 @Html.DisplayFor(model => model.ReleaseDate) 24 </dd> 25 <dt> 26 @Html.DisplayNameFor(model => model.Genre) 27 </dt> 28 <dd> 29 @Html.DisplayFor(model => model.Genre) 30 </dd> 31 <dt> 32 @Html.DisplayNameFor(model => model.Price) 33 </dt> 34 <dd> 35 @Html.DisplayFor(model => model.Price) 36 </dd> 37 </dl> 38 </div> 39 <div> 40 <a asp-action="Edit" asp-route-id="@Model.ID">Edit</a> | 41 <a asp-action="Index">Back to List</a> 42 </div>
By including a @model statement at the top of the view file, you can specify the type of object that the view expects.
通过在顶部包含一个@model 语句,你可以指定视图所要使用的模型类型。
When you created the movie controller, Visual Studio automatically included the following @model statement at the top of the Details.cshtml file:
在你添加movie控制器时,vs 自动在Details.cshtml 文件的顶部包含了@model 语句,如下所示:
1 @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.
@model 指令允许你在视图上以强类型的方式访问控制器传递过来的Model 对象。
For example, in the Details.cshtml view, the code passes each movie field to the DisplayNameFor and DisplayFor HTML Helpers with the strongly typed Modelobject.
例如在Details.cshtml 视图中,代码用 DisplayNameFor 和DisplayFor 展现强类型Model 对象的每一个字段。
The Create and Edit methods and views also pass a Movie model object.
Create 和Edit 同样在视图中解析Movie 模型对象。
Examine the Index.cshtml view and the Index method in the Movies controller.
查看Index.cshtml 视图及控制器中的 Index 方法。
Notice how the code creates a List object when it calls the View method.
注意代码中在调用View 方法时是如何创建一个List 集合对象的。
The code passes this Movies list from the Index action method to the view:
代码中从Index 方法传递Movies 列表到视图中,如下:
1 // GET: Movies 2 public async Task<IActionResult> Index() 3 { 4 return View(await _context.Movie.ToListAsync()); 5 }
When you created the movies controller, scaffolding automatically included the following @modelstatement at the top of the Index.cshtml file:
当你创建movie控制器,基价自动会将如下代码放到Index.cshtml 文件的顶部:
1 @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.
@model 指令允许你以强类型的方式在视图上访问控制器传递过来的movies 列表。
For example, in the Index.cshtml view, the code loops through the movies with a foreach statement over the strongly typed Model object:
例如,在Index.cshtml 视图中,通过foreach 语句循环movie列表中的每个强类型Model 对象:
1 @model IEnumerable<MvcMovie.Models.Movie> 2 3 @{ 4 ViewData["Title"] = "Index"; 5 } 6 7 <h2>Index</h2> 8 9 <p> 10 <a asp-action="Create">Create New</a> 11 </p> 12 <table class="table"> 13 <thead> 14 <tr> 15 <th> 16 @Html.DisplayNameFor(model => model.Title) 17 </th> 18 <th> 19 @Html.DisplayNameFor(model => model.ReleaseDate) 20 </th> 21 <th> 22 @Html.DisplayNameFor(model => model.Genre) 23 </th> 24 <th> 25 @Html.DisplayNameFor(model => model.Price) 26 </th> 27 <th></th> 28 </tr> 29 </thead> 30 <tbody> 31 @foreach (var item in Model) { 32 <tr> 33 <td> 34 @Html.DisplayFor(modelItem => item.Title) 35 </td> 36 <td> 37 @Html.DisplayFor(modelItem => item.ReleaseDate) 38 </td> 39 <td> 40 @Html.DisplayFor(modelItem => item.Genre) 41 </td> 42 <td> 43 @Html.DisplayFor(modelItem => item.Price) 44 </td> 45 <td> 46 <a asp-action="Edit" asp-route-id="@item.ID">Edit</a> | 47 <a asp-action="Details" asp-route-id="@item.ID">Details</a> | 48 <a asp-action="Delete" asp-route-id="@item.ID">Delete</a> 49 </td> 50 </tr> 51 } 52 </tbody> 53 </table>
Because the Model object is strongly typed (as an IEnumerable<Movie> object), each item in the loop is typed as Movie.
因为Model 对象是强类型的,循环中的每个对象都是Movie 类型。
Among other benefits, this means that you get compile-time checking of the code:
还有其它有点,比如你在编译的同时也由编译器自动检查了代码的正确性:
Additional resources
其它资源
• Tag Helpers
• Globalization and localization
蒙
2017-07-20 16:31 周四
2017-07-21 15:10 修正