ASP.NET MVC with Entity Framework and CSS一开翻体系作品的第二章节:利用型类创设视图、控制器和数据库

  在即时等同章中,大家以一向进去项目,并且也活及归类添加一些基本的模型类。我们拿当Entity
Framework的代码优先模式下,利用那多少个模型类创设一个数据库。大家还用学怎么在代码中开创数据库上下文类、指定数据库连接字符串以及开创一个数据库。最终,我们尚将补充加视图和控制器来保管和显式产品与归类数据。

  注意:假诺你想循本章的代码编写示例,你必须完成第一章要间接由www.apress.com下载第一段的源代码。

2.1 添加模型类

   Entity
Framework的代码优先格局允许大家打模型类制造数据库。我们将创表示活与分类的有限单模型类来开本章的读。我们还拿当产品及归类之内加加0或1针对性几近的关系,表示一个产品得以属于一个分拣或非属其他分类,一个分类可以分包五个活。

  右击Models文件夹,然后打菜单中选用【添加】->【类】,创制一个称为吧“Product”的新类,然后以此类中上加如下代码:

 1 namespace BabyStore.Models
 2 {
 3     public class Product
 4     {
 5         public int ID { get; set; }
 6         public string Name { get; set; }
 7         public string Description { get; set; }
 8         public decimal Price { get; set; }
 9         public int? CategoryID { get; set; }
10         public virtual Category Category { get; set; }
11     }
12 }

  于文件的顶端移除所有未必要之using语句。

  提示:万一移除不不必要的using语句,大家只待用光标悬停于using语句上,点击出现的艳情灯泡,然后选用“删除不必要的using”选项即可。

  Product类包含以下属性:

  • ID—用于表示活(product)在数据库被的主键。
  • Name—产品(product)的名称。
  • Description—关于产品的文本描述。
  • Price—表示活的价。
  • CategoryID—表示指定为产品(product)的归类(category)ID。在数据库被平时给安装为外键。我们尚用欠属性之类型设置为可空整型(int?),用于描述这样一个实:某个产品或许不属其他分类。这足以避以对分类实施删除操作时,该分类下之持有成品也为删的景观暴发。默认情形下,Entity
    Framework对而空类型外键启用级联删除,也就是说,假诺CategoryID不是可空的,当一个分拣为去除时,所有和该分类相关联的活呢会于删去。
  • Category—导航属性。导航属性包含与该实体相关的外实体,在这种场馆下,这几个特性将富含该产品所属的归类实体。假使一个导航数据可涵盖多单实体,那么它要给定义也会聚类型。通常用ICollection类型。导航属性平常为定义也virtual,以便能好某些特殊的效用,比如延迟加载。

   提示:我们得以Visual
Studio中输入prop,然后遵照两不善Tab键来自动生成属性。

  下边,我们以Models文件夹下还新建一个曰也“Category”的模子类,然后于此类中补充加如下代码:

 1 using System.Collections.Generic;
 2 
 3 namespace BabyStore.Models
 4 {
 5     public class Category
 6     {
 7         public int ID { get; set; }
 8         public string Name { get; set; }
 9         public virtual ICollection<Product> Products { get; set; }
10     }
11 }

  移除文件上有非必要之using语句。Category类包含的特性如下所示:

  • ID—主键。
  • Name—分类的称号。
  • Products—导航属性,该属性包含属于该分类的富有成品实业。

2.2 添加数据库上下文

  对于数据模型来说,数据库上下文是协调Entity Framework功效最好根本的好像。

  以缓解方案资源管理器中,右键单击BabyStore项目,然后创制一个名为吧“DAL”的文件夹。在拖欠公文夹着开创一个叫作吧“StoreContext.cs”的切近,然后于此类中上加如下代码:

 1 using BabyStore.Models;
 2 using System.Data.Entity;
 3 
 4 namespace BabyStore.DAL
 5 {
 6     public class StoreContext : DbContext
 7     {
 8         public DbSet<Product> Products { get; set; }
 9         public DbSet<Category> Categories { get; set; }
10     }
11 }

  上下文类继承自System.Data.Entity.DbContext类,通常状态下,一个数据库对应一个数据库上下文类,在好几比较复杂的档次蒙可能对许多单。每一个DbSet类型的性为叫做实体集,通常对许数据库被的某个一个讲明,比如Products属性对应数据库中之Products表。代码DbSet<Product>告诉Entity
Framework使用Product类来代表Products表中之一条龙数。

2.3 指定连接字符串

  现在,大家早就闹矣数据库上下文和组成部分模型类,现在需要大家报告Entity
Framework怎么样连接至数据库。在Web.config文件的connectionString节点参与一个新的条款:

1 <connectionStrings>
2     <add name="DefaultConnection" connectionString="Data Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\aspnet-BabyStore-20161229112118.mdf;Initial Catalog=aspnet-BabyStore-20161229112118;Integrated Security=True"
3       providerName="System.Data.SqlClient" />
4     <add name="StoreContext" connectionString="Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\BabyStore.mdf;Initial Catalog=BabyStore;Integrated Security=True"
5       providerName="System.Data.SqlClient" />
6   </connectionStrings>

  那一个条款告诉Entity
Framework要连接的是种App_Data文件夹着的BabyStore.mdf数据库。我们选取于这个文件夹着存储数据库是为它们亦可从项目联合为复制。AttachDbFilename=|DataDirectory|\BabyStore.mdf;指定在App_Data文件夹着开创数据库。

  一个可选的指定连接字符串的章是Data
Source=(LocalDB)\MSSQLLocalDB;Initial Catalog=BabyStore.mdf;Integrated
Security=True,它指定在用户文件夹(通常在Windows系统中凡是C:\Users\User)中开创数据库。

  以connectionString节点中设有的此外条款是当我们创设工程时自动成立的,之所以会自行创制是数据库是因大家于身份验证选项中采取了“个人用户账户”。大家将以本书的后续章节研商那多少个题材。

  值得注意的是,大家得无在web.config文件中定义连接字符串,尽管如此做的话,Entity
Framework将会用基于上下文类的默认设置。

  注意:保险下的凡种根本目录下的Web.config文件,而休是Views文件夹着的Web.config文件。

2.4 添加控制器和视图

   现在大家需要加上一些控制器和视图来治本和显式我们的出品与分类数据。

2.4.1 添加分类控制器和视图

1、从Visual
Studio菜单中,点击【生成】->【生成解决方案】来充足成解决方案。

2、右击Controllers文件夹,然后接纳【添加】->【控制器】。

3、在“添加基架”窗体中,选拔“包含视图的MVC 5 控制器(使用 Entity
Framework)”选项,如图2-1所展现。

图片 1

 图2-1:用Entity Framework成立控制器和视图

 4、点击“添加”按钮,然后以“添加控制器”窗口被甄选下列选项:

  • 模型类:Category
  • 多少上下文类:StoreContext
  • 保证生成视图、引用脚本库和动用布局页选项于勾选上
  • 保存控制器名称设置也CategoriesController(全体端详参见图2-2)

图片 2

图2-2:加加新分类控制器的抉择

5、点击“添加”按钮,则会以Controllers文件夹着开创一个CategoriesController类,与的有关的视图会创制以Views\Categories文件夹着。

2.4.2
检查CategoriesController类和章程

  新搭建之CategoriesController.cs文件包含对分类实施CRUD(新建、查询、更新和去)操作的大三只模式。

  代码private StoreContext db = new
StoreContext();起先化了控制器要运的一个上下文对象。该对象在控制器的满贯生命周期中都可运,在控制器的Dispose方法为调用时放。

  CategoriesController包含下列形式。

  Inex方法用于重返所有分类的列表给Views\Categories\Index.cshtml视图:

1 // GET: Categories
2 public ActionResult Index()
3 {
4     return View(db.Categories.ToList());
5 }

  Details方法基于id参数从数据库查询有分类信息,就像咱当第1章看到的那样,系统运用路由于网将URL中的id参数传递给该措施的id参数。

 1 // GET: Categories/Details/5
 2 public ActionResult Details(int? id)
 3 {
 4     if (id == null)
 5     {
 6         return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
 7     }
 8     Category category = db.Categories.Find(id);
 9     if (category == null)
10     {
11         return HttpNotFound();
12     }
13     return View(category);
14 }

  Create方法的GET版本只是简短地回来Create视图。第一赖看到此法恐怕来接触陌生,它的意义是回到一个视图,在拖欠视图中显一个空的HTML表单,用于创立一个初的归类。

1 // GET: Categories/Create
2 public ActionResult Create()
3 {
4     return View();
5 }

  Create方法的另外一个本子用HTTP
POST请求。该办法在用户提交创造(Create)视图的表单时为调用。它富含一个Category类型的参数,并拿拖欠参数表示的Category对象上加到数据库被。假设该办法执行成功则回到目录(Index)视图,否则,它会师再次加载成立(Create)视图。

 1 // POST: Categories/Create
 2 // 为了防止“过多发布”攻击,请启用要绑定到的特定属性,有关 
 3 // 详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkId=317598。
 4 [HttpPost]
 5 [ValidateAntiForgeryToken]
 6 public ActionResult Create([Bind(Include = "ID,Name")] Category category)
 7 {
 8     if (ModelState.IsValid)
 9     {
10         db.Categories.Add(category);
11         db.SaveChanges();
12         return RedirectToAction("Index");
13     }
14 
15     return View(category);
16 }

  因为该办法是一个HTTP POST,它含有额外的代码:

  • [HttpPost]特征告诉控制器当调用Create动作方法的央浼是一个POST请求时,使用该法,而无拔取外重载的Create方法。
  • [ValidateAntiForgeryToken]管Token通过HTML表单传递,从而证实请求。这样做的目的是包请求确确实实地是来自于大家所欲之表单,以预防跨站请求伪造。简单的话,跨站请求伪作育是出自于另外站点的表单请求伪装成大家温馨站点的请,从而执行带有恶意目的的操作。
  • 参数([Bind(Include = “ID,Name”)] Category
    category)告诉法在抬高一个新的归类时才含有ID和Name属性。Bind特性使用Include属性成立了一个安全性能列表,只来该列表中的特性允许为修改,从而制止overposting攻击。然而,就如我们后探究的这样,它不像咱所梦想的这样行事。由此,我们要利用同样种不同之形式来拍卖部分值可能为空的编写和新建操作。举一个overposting的例子,考虑下一栽情景,当用户提交一个成品订单的下,该产品之价位也受付,overposting攻击会尝试通过买一个比逊色价格之商品来修改都给交给的产品价格。

  Edit方法的GET版本包含的代码和Details方法的代码一样。该措施按照ID找到一个分拣,然后用拖欠分类数据传递让视图。该视图据一定之格式显示分类信息,并允许进行编辑。

 1 // GET: Categories/Edit/5
 2 public ActionResult Edit(int? id)
 3 {
 4     if (id == null)
 5     {
 6         return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
 7     }
 8     Category category = db.Categories.Find(id);
 9     if (category == null)
10     {
11         return HttpNotFound();
12     }
13     return View(category);
14 }

  Edit方法的POST版本和Create方法的POST版本很接近。它含有一行额外的代码用于在将实体保存到数据库以前检查该实体是否被改动了,假设方式执行成功,则归到目录(Index)视图,否则再显示编辑(Edit)视图。

 1 // POST: Categories/Edit/5
 2 // 为了防止“过多发布”攻击,请启用要绑定到的特定属性,有关 
 3 // 详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkId=317598。
 4 [HttpPost]
 5 [ValidateAntiForgeryToken]
 6 public ActionResult Edit([Bind(Include = "ID,Name")] Category category)
 7 {
 8     if (ModelState.IsValid)
 9     {
10         db.Entry(category).State = EntityState.Modified;
11         db.SaveChanges();
12         return RedirectToAction("Index");
13     }
14     return View(category);
15 }

  Delete方法为生零星只本子。ASP.NET
MVC基架将要去的详细音信展示给用户,在用户真正付诸删除请求以前开展确认。大家在当时先排有GET版本的Delete方法,大家会合注意到该情势及Details方法好列,使用ID找到一个分类,并将拖欠分类数据传递给视图。

 1 // GET: Categories/Delete/5
 2 public ActionResult Delete(int? id)
 3 {
 4     if (id == null)
 5     {
 6         return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
 7     }
 8     Category category = db.Categories.Find(id);
 9     if (category == null)
10     {
11         return HttpNotFound();
12     }
13     return View(category);
14 }

  Delete方法的POST版本执行一个防伪检查,它首先接纳ID找到一个分类,然后移除它,最后保存对数据库的修改。

 1 // POST: Categories/Delete/5
 2 [HttpPost, ActionName("Delete")]
 3 [ValidateAntiForgeryToken]
 4 public ActionResult DeleteConfirmed(int id)
 5 {
 6     Category category = db.Categories.Find(id);
 7     db.Categories.Remove(category);
 8     db.SaveChanges();
 9     return RedirectToAction("Index");
10 }

  由于产品实业包含了一个针对性分类实体的外键引用,自动生成的Delete方法无可以对的办事。我们拿当第4回上怎样修正该问题。

  注意:暴发差不五只由致ASP.NET拔取了无同意GET请求更新数据库的主意,也发生广大有关这样做的安全性的品和争议。不过,这样做的最为要害的原由是找引擎爬行器会爬行我们站点中的备公开的超链接,假使这么些链接中蕴藏无证实即可删除记录的链接,那么,可能会师招数据库中之连带数据被删。稍后我们谋面于编制分类添加安全机制,因而,这将成为一个暴发争议之题目。

2.4.3 检查分类视图

  与分类有关的视图可在\Views\Categories文件夹着找到。每一个CRUD动作(详情、创立、编辑和去)都出一个视图,索引(Index)视图用于展现所有分类的一个列表。

2.4.3.1 分类的目录(Index)视图

  自动生成的Categories\Views\Index.cshtml视图文件如下所示:

 1 @model IEnumerable<BabyStore.Models.Category>
 2 
 3 @{
 4     ViewBag.Title = "Index";
 5 }
 6 
 7 <h2>Index</h2>
 8 
 9 <p>
10     @Html.ActionLink("Create New", "Create")
11 </p>
12 <table class="table">
13     <tr>
14         <th>
15             @Html.DisplayNameFor(model => model.Name)
16         </th>
17         <th></th>
18     </tr>
19 
20     @foreach (var item in Model)
21     {
22         <tr>
23             <td>
24                 @Html.DisplayFor(modelItem => item.Name)
25             </td>
26             <td>
27                 @Html.ActionLink("Edit", "Edit", new { id = item.ID }) |
28                 @Html.ActionLink("Details", "Details", new { id = item.ID }) |
29                 @Html.ActionLink("Delete", "Delete", new { id = item.ID })
30             </td>
31         </tr>
32     }
33 
34 </table>

  在是视图中之次第条目如下所示:

  • @model
    IEnumerable<BabyStore.Models.Category>是拖欠视图所遵照的型。CategoriesController控制器类的Index方法为索引(Index)视图传递了一个分类列表。在那事例中,视图需要向用户展现分类音讯列表,因而模型指定为落实了IEnumerable接口的归类集合。
  • 眼前页的title属性使用下列代码举办了安:

    1 @{
    2 ViewBag.Title = “Index”;
    3 }

  • @Html.ActionLink(“Create New”, “Create”)制造了一个文书也“Create
    New”的、链接到创造(Create)视图的超链接。这是一个以HTML协助器的事例,ASP.NET
    MVC通过动这些协理器来渲染各个不同之数据驱动之HTML元素。

  • @Html.DisplayNameFor(model =>
    model.Name)展现模型中指定属性的价。在这事例中,它显得了归类的Name属性的的价值。
  • 接下来代码循环遍历模型中带有的各级一个分拣,并出示每个分类的Name属性所富含的价,前边紧跟三只链接:Edit、Details和Delete(如图2-3)。ActionLink方法的老五个参数用于为链接打开的视图提供分类的id。

    1 @foreach (var item in Model)
    2 {
    3

    4

    5 @Html.DisplayFor(modelItem => item.Name)
    6

    7

    8 @Html.ActionLink(“Edit”, “Edit”, new { id = item.ID }) |
    9 @Html.ActionLink(“Details”, “Details”, new { id = item.ID }) |
    10 @Html.ActionLink(“Delete”, “Delete”, new { id = item.ID })
    11

    12

    13 }

图片 3

图2-3:分类索引(Index)视图生成的HTML页面(包括示例数据)

  译者注:示范数据的充足我们后会摆到,这儿来接触提前。

.4.3.2
分类的详情(Details)视图

  由基架生成的Views\Categories\Details.cshtml视图文件如下所示:

 1 @model BabyStore.Models.Category
 2 
 3 @{
 4     ViewBag.Title = "Details";
 5 }
 6 
 7 <h2>Details</h2>
 8 
 9 <div>
10     <h4>Category</h4>
11     <hr />
12     <dl class="dl-horizontal">
13         <dt>
14             @Html.DisplayNameFor(model => model.Name)
15         </dt>
16 
17         <dd>
18             @Html.DisplayFor(model => model.Name)
19         </dd>
20 
21     </dl>
22 </div>
23 <p>
24     @Html.ActionLink("Edit", "Edit", new { id = Model.ID }) |
25     @Html.ActionLink("Back to List", "Index")
26 </p>

  这段代码比索引(Index)视图简单,它只是展示单一实体。文件之首先履代码所指定的型是一个纯实体而无是会聚。

  @model BabyStore.Models.Category

  以拖欠视图中应用了跟索引(Index)视图中相同的HTML援助器,但这一次未需利用循环,因为就发一个单纯实体,如图2-4所出示。

图片 4

图2-4:分拣详细(Details)视图生成的HTML页面

2.4.3.3
分类的创导(Create)视图

  成立(Create)视图显示了一个空表单因允许我们创设一个分类。为了转变一个HTML表单,该视图实现了一些当目录(Index)视图和详情(Details)视图中绝非包括的初特性。这个表单使用POST请求提交,该要会为POST版本的Create方法处理。这个视图自动生成的代码如下所示:

 1 @model BabyStore.Models.Category
 2 
 3 @{
 4     ViewBag.Title = "Create";
 5 }
 6 
 7 <h2>Create</h2>
 8 
 9 @using (Html.BeginForm())
10 {
11     @Html.AntiForgeryToken()
12 
13     <div class="form-horizontal">
14         <h4>Category</h4>
15         <hr />
16         @Html.ValidationSummary(true, "", new { @class = "text-danger" })
17         <div class="form-group">
18             @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
19             <div class="col-md-10">
20                 @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })
21                 @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
22             </div>
23         </div>
24 
25         <div class="form-group">
26             <div class="col-md-offset-2 col-md-10">
27                 <input type="submit" value="Create" class="btn btn-default" />
28             </div>
29         </div>
30     </div>
31 }
32 
33 <div>
34     @Html.ActionLink("Back to List", "Index")
35 </div>
36 
37 @section Scripts {
38     @Scripts.Render("~/bundles/jqueryval")
39 }

  图2-5显了所大成的HTML页面。下边是上述代码中之一些首要点:

  • 首先只新特点应用的代码是@Using(Html.BeginForm()),该代码行告诉视图将以此using语句被之保有代码都打包在HTML表单中。
  • @Html.AntiForgeryToken()生成一个anti-forgery
    token,被匹配的POST版本的Create方法用于检查(使用[ValidateAntiForgeryToken]特性)。
  • @Html.ValidationSummary(true, “”, new { @class = “text-danger”
    })是别一个协理器,用于显示一个荒唐摘要(导致表单无效的任何原因)。第一只参数告诉摘要排除任何性质错误,只彰显模型级其余缪,第六个参数new
    { @class = “text-danger” }用于拔取Bootstrap的text-danger
    CSS类样式化错误音讯(这是一个红的文书,更多关于Bootstrap和CSS的学问包含在本书后续章节)。
  • @Html.LabelFor(model => model.Name, htmlAttributes: new { @class
    = “control-label col-md-2” })创制了一个新的HTML
    label元素,该label元素与继的HTML输入控件(分类的Name属性)相关联。
  • @Html.EditorFor(model => model.Name, new { htmlAttributes = new {
    @class = “form-control” }
    })是其余一个HTML襄助器方法,可以依照指定属性的数码格式来展现是的HTML输入元素。在那个事例中,属性是Name,因此EditorFor方法尝试在呈现对的HTML元素类型为允许用户编辑字符串。在是情形下,它在HTML表单中创设了一个文本框元素,所以用户可以输入分类的名目。
  • 当此视图中之末梢一个初HTML援助器是@Html.ValidationMessageFor(model
    => model.Name, “”, new { @class = “text-danger”
    })。这段代码对性上加了相当的证实音信,假诺用户输入的属性值违法了当程序中安的表明规则,则会沾一个荒唐。当前,大家尚没有安装规则,不过咱拿当第4节上怎么着设置它。
  • 于那视图中还有一个额外的有是在目录(Index)视图和详情(Details)视图文件中没的,它用于包含验证所要的JavaScript文件(更多知识点将在第4节讲述):

    1 @section Scripts {
    2 @Scripts.Render(“~/bundles/jqueryval”)
    3 }

图片 5

图2-5:分拣的创立(Create)视图所万分成的HTML页面,那些页面包含一个用来提交新分类消息的HTML表单

2.4.3.4 分类的编制(Edit)视图

  分类的编辑视图彰显了一个同意用户编辑分类消息之HTML表单,分类音讯由CategoriesController控制器类的Edit方法(GET版本)传递给该视图。这多少个视图万分相近于创建(Create)视图。该视图自动生成的代码如下所示:

 1 @model BabyStore.Models.Category
 2 
 3 @{
 4     ViewBag.Title = "Edit";
 5 }
 6 
 7 <h2>Edit</h2>
 8 
 9 @using (Html.BeginForm())
10 {
11     @Html.AntiForgeryToken()
12 
13     <div class="form-horizontal">
14         <h4>Category</h4>
15         <hr />
16         @Html.ValidationSummary(true, "", new { @class = "text-danger" })
17         @Html.HiddenFor(model => model.ID)
18 
19         <div class="form-group">
20             @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
21             <div class="col-md-10">
22                 @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })
23                 @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
24             </div>
25         </div>
26 
27         <div class="form-group">
28             <div class="col-md-offset-2 col-md-10">
29                 <input type="submit" value="Save" class="btn btn-default" />
30             </div>
31         </div>
32     </div>
33 }
34 
35 <div>
36     @Html.ActionLink("Back to List", "Index")
37 </div>
38 
39 @section Scripts {
40     @Scripts.Render("~/bundles/jqueryval")
41 }

  图2-6展示了所十分成的编写页面。在这视图中唯一的一个初的HTML协理器方法是@Html.HiddenFor(model
=>
model.ID)。该语句创立了一个涵盖分类ID的隐藏的HTML输入元素,用于CategoriesController控制器类的Edit方法(POST版本)的Bind元素:public
ActionResult Edit([Bind(Include = “ID,Name”)] Category category)。

图片 6

图2-6:分类的编制(Edit)视图所杀成的HTML页面,分类的时称被先行填充在输入框中。

2.4.3.5
分类的删减(Delete)视图

   删除(Delete)视图和详情(Details)视图很相近,而且也隐含一个HTML表单,用于提交到CategoriesController控制器类的Delete方法(POST版本)。除了前方大家所检查的视图所蕴含的情外,该视图没有含其他任何新的性状。自动生成的代码如下所示,该视图所生成的HTML如图2-7所著:

 1 @model BabyStore.Models.Category
 2 
 3 @{
 4     ViewBag.Title = "Delete";
 5 }
 6 
 7 <h2>Delete</h2>
 8 
 9 <h3>Are you sure you want to delete this?</h3>
10 <div>
11     <h4>Category</h4>
12     <hr />
13     <dl class="dl-horizontal">
14         <dt>
15             @Html.DisplayNameFor(model => model.Name)
16         </dt>
17 
18         <dd>
19             @Html.DisplayFor(model => model.Name)
20         </dd>
21 
22     </dl>
23 
24     @using (Html.BeginForm())
25     {
26         @Html.AntiForgeryToken()
27 
28         <div class="form-actions no-color">
29             <input type="submit" value="Delete" class="btn btn-default" /> |
30             @Html.ActionLink("Back to List", "Index")
31         </div>
32     }
33 </div>

图片 7

2.4.4 添加产品控制器和视图

1、右击Controllers文件夹,然后采用【添加】->【控制器】。

2、在“添加基架”窗体中,采纳“包含视图的 MVC 5 控制器(使用 Entity
Framework)”选项(如图2-1)。

3、点击“添加”按钮,然后在“添加控制器”窗口中精选下列选项:

  • 模型类:Product
  • 数据上下文类:StoreContext
  • 保险生成视图、引用脚本库和用布局页选项为勾选上
  • 封存控制器名称设置为ProductsController(全部端详参见图2-8)

图片 8

图2-8:上加新产品控制器的取舍

4、点击“添加”按钮,则会当Controllers文件夹着开创一个ProductsController类,与之相关的视图会成立于Views\Products文件夹着。

2.4.4.1 检查产品控制器和视图

  ProductsController控制器类和和的有关的视图和前面所讲述的CategoriesController类分外相似,我们虽不再详细描述了。可是,该视图包含了一个挺紧要的初效用,应用程序需要提供平等种植艺术关联产品与分类,在拖欠视图中所用的法是使select元素显示一个下拉列表,以便用户以开立产品以及编制产品平日可挑选产品所对应之归类。

  以控制器中,实现这些效能的代码可以在Edit方法(GET版本与POST版本)和Create方法(POST版本)中找到:

ViewBag.CategoryID = new SelectList(db.Categories, “ID”, “Name”,
product.CategoryID);

  于Create方法的GET版本被,与的相互接近之代码如下所示:

ViewBag.CategoryID = new SelectList(db.Categories, “ID”, “Name”);

  那段代码用一个章赋值给了ViewBage的CategoryID属性。这么些条款是一个SelectList对象,该目的包括数据库被的富有分类,每一个条款下Name属性作为要显得的文件,使用ID属性作为该价值。可摘的季只参数决定于select列表中先行选定的条文。举个例子,假如第六个参数product.CategoryID设置为2,那么视图中的归类下拉列表中拿会师先行选定分类Toys。图2-9形了其以视图中之样板。

  于视图中显HTML的select元素使用下列HTML协理器方法:@Html.DropDownList(“CategoryID”,
null, htmlAttributes: new { @class = “form-control” })。

  这段代码基于ViewBag.CategoryID属性生成一个HTML元素,并将拖欠因素的CSS
class属性设置也form-control。在DropDownList帮助器方法吃,即使第一单字符串参数的值匹配ViewBag属性的讳,它将会见自行使用此价值,而休晤面重新指定一个暨ViewBag的援。

图片 9

图2-9:行使product.CategoryID参数在下拉列表中先行选定的元素值

2.5 使用新的出品与归类视图

  我们无期待用户在浏览器地址栏中手动输入URL来导航及我们新建的视图,因而,我们用更新主站点的导航栏:

1、打开Views\Shared\_Layout.cshtml文件。

2、在代码<li>@Html.ActionLink(“联系情势”, “Contact”,
“Home”)</li>的脚添加分类以及产品的目录(Index)页面:

 1 <div class="navbar-collapse collapse">
 2     <ul class="nav navbar-nav">
 3         <li>@Html.ActionLink("主页", "Index", "Home")</li>
 4         <li>@Html.ActionLink("关于", "About", "Home")</li>
 5         <li>@Html.ActionLink("联系方式", "Contact", "Home")</li>
 6         <li>@Html.ActionLink("分类", "Index", "Categories")</li>
 7         <li>@Html.ActionLink("产品", "Index", "Products")</li>
 8     </ul>
 9     @Html.Partial("_LoginPartial")
10 </div>

3、点击【调试】->【最先执行(不调试)】,Web站点将碰面启动。点击“分类”链接的下以会出两件事:

  • 分拣的目录(Index)视图将晤面世。可能该视图无含有其他数据,因为我们还不曾在数据库中上加多少(如图2-10)。
  • Entity Framework会拔取Code
    First情势,基于我们的型类创制BabyStore数据库。为了查看该数据库,在Visual
    Studio中开拓SQL Server对象资源管理器。假使SQL
    Server对象资源管理器没有起,则由主菜单吃点击【视图】->【SQL
    Server对象资源管理器】。

图片 10

图2-10:分类的目录(Index)页面

2.5.1
检查新创制的BabyStore数据库

  要来看数据库中之新列,在SQL Server对象资源管理器中进行以下节点:SQL
Server>(localdb)\MSSQLLocalDB>数据库>BabyStore>表>dbo.Categories>列。同时为拿dbo.Products>列展开,如图2-11。

图片 11

图2-11:SQL
Server对象资源管理器中形的早期的BabyStore数据库,分类及活声明底列依次展开,并显示有每个列的数据类型

  于数据库被列有底每个列都和模型类的属性相匹配。表名被默认设置为复数格局。Categories表包含ID和Name列。Products表包含ID、Name、Description、普赖斯(Price)(Price)列以及一个外键列CategoryID。每个列的数据类型和模型类吃之习性之数据类型相配合。

  要怀恋愈详细地查看每个表底详情,右击表,然后于菜单中拔取【视图设计器】。使用视图设计器,我们好进一步详实地查看表中的每个列,以及外键。在觊觎2-12中,大家得以视Products表的规划以及T-SQL部分,T-SQL部分的第8履行代码用于安装外键约束,表面该外键列引用Categories表中的ID列。

图片 12

图2-12:寓外键约束的Products表的设计器

2.5.2 使用视图添加有数目

  为了测试新视图的效能,大家点击分类的目录(Index)视图中之Create
New链接来补偿加有数。添加三单分类:Clothes、Toys和Feeding。当我们成功这个操作后,分类的目录(Index)页面如图2-13所出示。

图片 13

图2-13:涵盖多只测试分类数据的分类索引(Index)页面

  新长的分类新闻就给补充加至数据库中,因为当用户点击分类的成立(Create)页面被之Create按钮时,CategoriesController类中之Create方法(POST版本)被调用,然后拿新分类音信保存到数据库中。

  点击产品链接,然后再点击Create
New链接来补偿加有活数据。添加的活数量如表2-1所显示。

表2-1:累加到站点的出品新闻

图片 14
  每一样不善点击产品的创造(Create)页面的Create按钮,ProductsController类的Create方法(POST版本)都会晤被调用,从而保留活数量到数据库中。

  一旦成功长,产品之目(Index)页面应要图2-14所著。数据现在也别保存及数据库中,如图2-15。要查阅数据库被的数,可以于SQL
Server对象资源管理器中右键单击dbo.Products表,然后打菜单中采取【查看数据】菜单项。

图片 15

图2-14:寓产品数据的产品目录(Index)页面

图片 16

图2-15:查看数据库中之Products表数据

注意:于视图中自动生成的默认的表头和标签对用户之应用非绝好,因而作者在继的截图中对她们开展了更正。如若我们想念协调举行更正,可以参考第二节的源码,该源码可以从www.Apress.com下载。作者没有于本书中对代码举行更正,因为其最过重复与麻烦。

2.5.3
使用数据注脚的计更改分类及制品的Name属性的来得

  产品之目(Index)页面包含两单名吧Name的题,如图2-16所体现。这是盖当视图中运用了@Html.DisplayNameFor(model
=>
model.Category.Name)代码来彰显分类的Name属性,紧接着也应用了拖欠法来显示产品的Name属性。在活的详情(Details)页面也有相同的题目,这导致了用户用的迷惑。

图片 17

图5-16:出品之目(Index)页面被的鲜单Name表头

  为了缓解者问题,我们好使用一个号称数据讲明的ASP.NET特性在分拣与制品的模型类的Name属性上添加一个Display特性。

  在Models\Category.cs文件中上加如下高亮展现的代码:

 1 using System.Collections.Generic;
 2 using System.ComponentModel.DataAnnotations;
 3 
 4 namespace BabyStore.Models
 5 {
 6     public class Category
 7     {
 8         public int ID { get; set; }
 9 
10         [Display(Name = "Category Name")]
11         public string Name { get; set; }
12         public virtual ICollection<Product> Products { get; set; }
13     }
14 }

  [Display(Name = “Category
Name”)]告诉MVC框架在亮属性名称标签的上,不动Name而是使用Category
Name。

  按平的情势修改Models\Product.cs文件被之代码:

 1 using System.ComponentModel.DataAnnotations;
 2 
 3 namespace BabyStore.Models
 4 {
 5     public class Product
 6     {
 7         public int ID { get; set; }
 8         [Display(Name = "Product Name")]
 9         public string Name { get; set; }
10         public string Description { get; set; }
11         public decimal Price { get; set; }
12         public int? CategoryID { get; set; }
13         public virtual Category Category { get; set; }
14     }
15 }

  从菜单栏中摘【生成解决方案】,然后重新择【调试】->【起初实施(不调试)】菜单项来启动应用程序。点击产品链接打开产品目录(Index)页面,我们会晤看零星只Name标题现在变成了Category
Name和Product Name,如图2-17所著。

图片 18

图2-17:产品目录(Index)页面突显的数注脚的来得名称

  以类似吃使数据声明可以使得大家的代码更便于维护,因为对于性名称的来得只待以一个地点开展支配即可。我们啊堪当视图中改展现名称,但这事关到一定量单文件,因而变得难以维护,其它,对于大家应用该属性成立的视图,未来犹要为更新。

2.5.3.1
使用MetaDataType将数据注脚分割为其他一个文件

  一些开发人士喜欢模型类尽可能地简单明了,由此,不情愿本着范类添加数据评释。这可下MetaDataType类来形成那种求。

  于Models文件夹着上加一个称为吧ProductMetaData.cs的文本,然后修改其代码如下所示:

 1 using System.ComponentModel.DataAnnotations;
 2 
 3 namespace BabyStore.Models
 4 {
 5     [MetadataType(typeof(ProductMetaData))]
 6     public partial class Product
 7     {
 8     }
 9 
10     public class ProductMetaData
11     {
12         [Display(Name = "Product Name")]
13         public string Name;
14     }
15 }

  现在用Product类阐明成了一个分部类,这象征将此类分割为多独文本。数据注明[MetadataType(typeof(ProductMetaData))]用以告诉.NET要未来自于ProductMetaData类的老大数据应用被Product类。

  将Product类修改成原来的状态,可是用她阐明也一个分部类,以便与阐明在ProductMetaData.cs文件被的Product类注解进行联。

 1 namespace BabyStore.Models
 2 {
 3     public partial class Product
 4     {
 5         public int ID { get; set; }
 6         public string Name { get; set; }
 7         public string Description { get; set; }
 8         public decimal Price { get; set; }
 9         public int? CategoryID { get; set; }
10         public virtual Category Category { get; set; }
11     }
12 }

  修正后的代码所来的结果以同图2-17亮的服从一样。但是,使用这种编码方法,除了将Product类讲明也一个分部类以外,没有针对Product类举行其他修改。当我们应用有自动生成的近乎,而我们又无思念对这一个看似举行改动时,这是均等种很管用的政策,比如,当我们用Entity
Framework的DataBase First形式时。在本书中,我们尚无涵盖Entity
Framework的Database
First相关知识,不过咱将叙其它一栽情景:对一个就存在的数据库使用Code
First。

2.6
简单询问:遵照字母顺序对分类举办排序

  在分拣的目(Index)视图中所突显的分类目前是按部就班ID来开展排序的,我们好修改成仍字母顺序对分类的名目举办排序。

  实现这效果非凡简,打开Controllers\CategoriesController.cs文件,然后将Index方法修改成如下代码:

1 // GET: Categories
2 public ActionResult Index()
3 {
4     return View(db.Categories.OrderBy(c => c.Name).ToList());
5 }

  点击【调试】->【开首履行(不调试)】启动应用程序,然后点击分类链接。现在分门别类将汇合坚守字母逐一对产品的称号举办排序,如图2-18所出示。

图片 19

图2-18:以字母顺序对分类名举办排序

  这段代码应用LINQ方波兰语法(method
syntax)来指定对孰列举行排序。lambda表明式用于指定要排序的列是Name列。这段代码用赶回一个排序过之归类列表给视图显示。LINQ表示Language-Integrated
Query,它是置于在.NET框架中之一个查询语言。使用LINQ方塞尔维亚语法(method
syntax)意味着所创办的询问好使用点“.”迅速地以多单艺术举办链接。一个但是替换方印度语印尼语法(method
syntax)的法门是使用查询语法(query
syntax),大家将以第3章为闹一个编的一个相比复杂的查询例子。方日语法(method
syntax)在外观及再也像SQL的语法,对于相比较复杂的查询好叫咱重新便于了解。可是,对于有些少的查询其显示就相比长。

  lambda表达式是匿名格局,这一个主意而用来创建委托。简单的话,lambda表明式能够于我们创造一个表达式,该表明式的lambda操作符(=>)左侧的价值是输入参数,左侧的是设总结的表达式和归值。考虑地方我们输入的lambda表明式,它富含一个Category类型的输入参数,然后回分类的Name属性。因此,简单的讲,它表明的意思就是是随分类的Name属性排序。

  于本书中,大家并未详尽描述LINQ或lambda说明式。倘诺你想对其打听之又多,大家提出您念下AndrewTroelsen编写的一致照好优秀之书本:Pro C#(粤语图书名也:精晓C#)。

2.7
依照连串过滤产品:使用导航属性与Include搜索相关实业

  我们都观察什么创设一个杀基本的页面用于显示不同实体的列表。现在,大家将丰裕一些实用的功效由此被这么些列表举行交互。大家用运用分类列表中给增选的价来过滤产品列表。为了上那目标,大家得修改下列代码:

  • 修改ProductsController的Index方法,使它们亦可吸纳一个参数,该参数表示接纳的归类,并且重返一个属该分类的成品列表。
  • 以分类索引(Index)页中之文书列表修改成超链接列表,该超链接的目的是ProductsController的Index方法。

  第一高居变更是ProductsController的Index方法,如下所示:

1 public ActionResult Index(string category)
2 {
3     var products = db.Products.Include(p => p.Category);
4     if (!string.IsNullOrEmpty(category))
5     {
6         products = products.Where(p => p.Category.Name == category);
7     }
8     return View(products.ToList());
9 }

  这段代码给Index方法上加了一个名叫也category的字符串参数。if语句用于检查category参数是否也空,假诺该参数不也空,将会见使Product类的领航属性Category来对产品举行过滤,代码为:products
= products.Where(p => p.Category.Name == category);。

  下边一行代码所显示的Include方法是一个利用预先加载(eager
loading)的例证:

1 var products = db.Products.Include(p => p.Category);

  它报告Entity
Framework去实践一个单一查询,检索出富有的制品及这一个活有关的归类音信。预先加载(eager
loading)会导致一个SQL连接查询,它一样赖找出所急需的拥有数据。我们得忽略Include方法,这时,Entity
Framework将会晤动用延缓加载(lazy
loading),这将干多独查询而休是一个纯净的总是查询。

  选取使用这同样种植加载方法暴发一部分特性达到之区别。预先加载对数据库举办相同坏询问就好拿走结果,可是,假设使用相比较复杂的接连语句会造成性降低。延迟加载会对数据库举行反复查询才可以得到所欲数。在此时,大家采纳预先加载是坐连续语句相比简单,同时,我们需要加载相关的归类信息以便对合举办搜索。

  products变量使用Where方法匹配产品之归类名和传递进入的category参数值一致的那一个产品。这说不定暴发接触小题大做,同时,我们或为会合迷惑为啥我们无选择CategoryID而是使用字符串来深受Index方法传值。关键原因在于,当咱们接纳路由于时,使用分类名更加有意义。我们拿当本书后续章节讲述相关文化。

  这是一个挺好之例子,它显得了导航属性是生实惠和有力的。由于用了Product类中之导航属性,我们得运用相比较少的代码来寻觅六只有关的实体。假诺我们记挂遵照分类名来配合产品,不过非以导航属性的语,我们得以ProductsController中加载分类实体,然则据常规,ProductsController只针对成品进行管制。

  为了演示新章程及的效率,我们启动站点,然后导航及产品之目录(Index)页面。现在我们在URL后边最佳代码?category=clothes。现在,产品列表将会让匹配的类别过滤,如图2-19。

图片 20

图2-19:利用URL地址栏按照clothes分类过滤产品

  在查询字符串中的另外参数都碰面活动匹配目的措施的参数。由此,在是事例中,URL中之?category=clothes匹配ProductsController中之Index方法的category参数,此时,该参数的值为clothes。

  注意:对刚刚起初使用Entity
Framework的编码人员的话,最广大的谬误是以错误的地点拔取了ToList()方法。在一个法被,LINQ平日用于创建一个询问,不过未执这么些查询!查询才当ToList()方法让调用时才为实施。初级编码人士每每以他们方法的伊始即动ToList()方法,这一般导致相比多的记录(通常是兼具的笔录)从数据库中寻找出来,其中有些记录并无是所要之,从而对性能有震慑。所有这些记录还为保存在内存中,并视作内存中的列表举行拍卖,这通常是不可取之,它会如站点的惦记可以大幅降低。作为选项,我们还都并非调用ToList()方法,当加载视图时,查询会叫执行。那多少个话题让称为延迟执行,延迟执行归功给查询只有当ToList()方法为调用时才会尽。

  为了成功因分类过滤产品的职能,我们要改分类的目(Index)页面被的活列表,将其变动为链条接到ProductsController的Index方法的超链接。

  为了用分类更改为超链接,大家修改Views\Categories\Index.cshtml文件,将那些文件中之@Html.DisplayFor(modelItem
=> item.Name)修改也:

 1 @foreach (var item in Model)
 2 {
 3     <tr>
 4         <td>
 5             @*@Html.DisplayFor(modelItem => item.Name)*@
 6             @Html.ActionLink(item.Name, "Index", "Products", new { category = item.Name }, null)
 7         </td>
 8         <td>
 9             @Html.ActionLink("Edit", "Edit", new { id = item.ID }) |
10             @Html.ActionLink("Details", "Details", new { id = item.ID }) |
11             @Html.ActionLink("Delete", "Delete", new { id = item.ID })
12         </td>
13     </tr>
14 }

  这段代码应用HTML的ActionLink匡助器方法好成一个超链接,该链接的显得文本是分类的称谓,目的是ProductsController的Index方法。第三只参数是程由于参数,用于将分类的Name属性值赋值给category参数,该参数会跟随URL传递给目标措施参数。使用那种措施和咱们应用手动智的听从一样,都晤面当URL的末尾多category=caegoryname样式的参数。

  通过上述的修改,分类的目(Index)页面现在带有了链子接到ProductsController的Index方法的超链接,如图2-20所展示。

  点击每一个链接,现在还会晤打开产品的目(Index)页面,在拖欠页面中单独突显了与该分类有关的成品音信。

图片 21

图2-20:涵盖超链接的、用于过滤产品的分类索引(Index)页面。标红的片段是clothes链接生成的URL。

2.8 小节

   以就无异于回中,大家学习了争创建模型类与怎样遵照模型类生成数据库。我们还学了哪些指定数据库连接字符串,以及哪些创立数据库上下文。这一个类似和大家的模型类可用于创立控制器和视图,大家尚创建与填充了数据库。

  数据库创立了之后,咱们还上了安检查其跟哪些修改视图为修正与基架相关的题目。从当下起,本章余下的有重大讲述了怎么着行使分类过滤产品,怎么着行使导航属性和咋样从视图链接到不同的动作方法。

相关文章