《音乐商店》第4集:自动生成StoreManager控制器
一、自动生成StoreManager控制器
二、查看 StoreManager 控制器的代码
现在,Store Manager 控制器中已经包含了一定数量的代码,我们从头到尾重新过一下。
1.访问数据库代码
首先,在控制器中包含了标准的 MVC 控制器的代码,为了使用方便,还可以引用我们的模型类所在的命名空间 MvcMusicStore.Models。控制器还拥有了一个私有的 MusicStoreDBContext的私有成员,以方便控制器中的每个 Action 访问数据库。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc; using MvcMusicStore.Models; namespace MvcMusicStore.Controllers
{
public class StoreManagerController : Controller
{
MvcMusicStore.Models.MusicStoreDBContext storeDB
= new MvcMusicStore.Models.MusicStoreEntities();
2.Index 和 Details Action
Index 视图获取专辑的列表,包含每一个专辑引用的流派和艺术家信息,向我们在前面 Store控制器的 Browse时候看到的,Index 视图中需要包含对于链接到的流派和艺术家对象来显示相关的信息,所以,在 Index 的 Action 方法中,需要包含这些数据。
public ActionResult Index()
{
var albums = storeDB.Albums.Include("Genre").Include("Artist");
return View(albums.ToList());
}
在 Details 方法中,类似于 Store 控制器的 Details 方法,通过专辑的 Id 来获取专辑对象,这里使用 Find() 方法完成,最后,把这个对象传递给视图。
//
// GET: /StoreManager/Details/5 public ViewResult Details(int id)
{
MvcMusicStore.Models.Album album = storeDB.Albums.Find(id);
return View(album);
}
3.创建方法 Create
与前面看到的不同,Create 方法需要处理表单,当用户第一次访问地址 /StoreManager/Create 的时候,用户将会看到一个空的表单,HTML 页面中包含一个 <form> 元素,其中包含了下拉列表和文本框等输入元素,用户可以借助他们输入专辑的详细信息。
当用户填写了专辑的信息之后,可以通过点击 “保存” 按钮来提交表单信息到服务器,我们的应用程序可以获取这些信息保存到数据库中。在用户点击 “保存” 的时候,浏览器发出一个 Http 的 Post 请求,到 /StoreManager/Create 地址,表单的内容作为这个 Post 请求的一部分发送回服务器。
ASP.NET MVC 允许我们容易地分割这两种同样对于 Create 方法的请求处理,通过提供两个同名的 Create 方法,一个用来处理 Http Get 请求,一个用来处理 Http Post 请求,区分的方式是在处理 Post 请求的方法前面增加一个 [HttpPost] 的标签。如果增加 [HttpGet] 标签,则表示这个方法仅仅处理 Http Get 请求。通常没有这个标签,则表示无论是 Get 请求还是 Post 请求都可以由这个 Action 方法处理。
使用 ViewBag 向视图传递信息
我们曾经在这个教程的开始使用过 ViewBag, 但是,没有深入讨论它,ViewBag 允许我们向视图传递信息而不需要首先定义强类型的 Model,在创建专辑的 Action 中,因为在表单中需要两个列表框,我们需要向视图传递列表所需要的数据,以便在视图中填充下拉列表框,最简单的方式就是通过 ViewBag 来实现。
ViewBag 是动态对象,这意味着你可以使用 ViewBag.Foo 或者 ViewBag.YourNameHere 形式的属性而不需要预先定义这些属性,控制器中的代码使用 ViewBag.GenreId 和 ViewBag.Artisid 传递流派和艺术家的信息以便生成表单中下拉列表的值,以后,用来在新创建的专辑中使用。
传递到视图的下拉列表的值使用 SelectList 对象表示,对于我们的要求,使用下面的代码。
ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name");
方法中的三个参数被用于创建这个对象:
用来生成下拉列表中信息的集合,注意,不是一个字符串集合,我们这里是流派对象的集合。
方法的第二个参数提供下拉列表中的值,这是一个字符串,实际上是流派对象的一个属性 GenreId。
最后的参数提供下拉列表中显示出来的值,这里使用流派的 Name 属性。
理解了上面的内容,代码就很简单了,两个 SelectList 对象通过 ViewBag 传递给视图,没有使用模型对象,我们也没有创建这样用途的模型。
// // GET: /StoreManager/Create public ActionResult Create() { ViewBag.GenreId = new SelectList(storeDB.Genres, "GenreId", "Name"); ViewBag.ArtistId = new SelectList(storeDB.Artists, "ArtistId", "Name"); return View(); }
在 Create 视图中使用 HtmlHelper 来显示下拉列表
下拉列表的数据已经被传递到了视图中,现在,我们看一下视图如何使用这些数据显示一个下拉列表,在 Create 视图中,将原来显示流派标识的代码
@Html.LabelFor(model => model.GenreId)
修改为
@Html.DropDownList("GenreId", String.Empty)
这里使用了 HtmlHelper ,一个用于视图中生成 Html 的实用工具,使用 HtmlHelper 可以保持我们的视图清楚和易读。Html.DropDownList 助手方法由 ASP.NET MVC 提供,后面可以看到,我们也可以提供自己的助手方法进行扩展。
Html.DropDownList 方法需要两个参数,从哪里获取显示用的列表,和哪一个值需要被预先选中,方法的第一个参数, GenreId,告诉DropDownList 从模型对象或者 ViewBag 对象中寻找名为 GenreId 的属性值,第二个参数用来指出下拉列表默认选中的值。这是创建专辑的表单,所以,没有需要预先选中的值,这里传递了一个 String.Empty 。
获取 Post 表单中的值
我们在前面讨论过,对于一个表单可以有两个对应的处理方法,一个处理 Http Get 请求显示表单,另外一个用于处理 Http Post 请求,用于处理提交的表单数据,注意,在控制器中,处理 Http Post 请求的方法需要通过标签 [HttpPost] 进行标注,这样,这个方法将会被 ASP。NET 仅仅用来处理 Post 请求。
// // POST: /StoreManager/Create [HttpPost] public ActionResult Create(Album album) { if (ModelState.IsValid) { storeDB.Albums.Add(album); storeDB.SaveChanges(); return RedirectToAction("Index"); } ViewBag.GenreId = new SelectList(storeDB.Genres, "GenreId", "Name", album.GenreId); ViewBag.ArtistId = new SelectList(storeDB.Artists, "ArtistId", "Name", album.ArtistId); return View(album); }
这个 Action 方法完成四个任务:
- 读取表单的数据
- 检查表单的数据是否通过了验证规则
- 如果表单通过了验证,保存数据,然后显示更新之后的专辑列表
- 如果表单没有通过验证,重新显示带有验证提示信息的表单。
通过模型绑定获取表单数据
控制器处理的表单提交中包含了流派的标识 GenreId 和 艺术家标识 ArtistId,这些来自下拉列表框,以及通过文本框输入的 Title,Price 等等数据,虽然可以直接通过 FormCollection 来访问表单数据,但是,更好的做法是使用 ASP.NET MVC 内置提供的模型绑定。
当 Action 方法的参数是模型类型的时候,ASP.NET MVC 将会试图使用表单中的数据来填充对象的属性,它通过检查表单参数的名字是否匹配模型对象的属性来进行,例如,对于专辑对象的 GenreId 属性来说,它将会在表单数据中查找名为 GenreId 的值赋予它。当使用标准的模型方式生成视图的时候,表单会使用模型对象的属性名称来生成表单输入项目的名称,这样,在发出表单的时候,请求参数就会正好匹配模型的属性了。
验证模型
通过访问 ModelState 的 IsValid 属性就可以检查模型是否通过验证。这里我们还没有为 Album 提供任何的验证规则,后面我们就会提供,所以,这里的验证并没有实际的作用。验证的重要性取决于我们定义的在模型上的验证规则,如果我们已经提供了对于 ModelState 的 IsValid 检查的话,以后增加验证规则就不需要修改这里的代码。
保存提交的数据
如果提交的数据通过了验证,下一步就可以保存到数据库中,使用 EF,仅仅需要将模型对象加入到 Albums 的集合中,然后调用 SaveChanges 方法就可以了。
db.Albums.Add(album);
db.SaveChanges();
EF 将会生成适当的 SQL 命令来持久化对象,保存数据之后,我们重定向到专辑列表的页面,以便看到更新之后的内容。这可以通过调用 RedirectToAction 方法,并提供 Action 方法的名称来完成。在这里,我们使用 Index 。
显示带有验证提示信息的表单
如果没有通过验证,与 GET 处理的时候相同,我们通过 ViewBag 传递下拉列表的值,通过模型传递其他的数据,验证的提示信息由 @HtmlValidationMessageFor 助手方法自动显示在页面上。
测试创建表单
测试一下,运行程序,访问 /StoreManager/Create,你将会看到一个由 StoreManagerController 的 Create 方法处理 Http Get 请求生成的空白表单。
填写一些内容,然后点击创建按钮提交表单。
可以看到内容已经被添加。
处理编辑
编辑处理的一对 Action 方法非常类似我们刚刚看到的 Create 处理。由于编辑的情况需要对已经存在的唱片进行处理,在编辑的 Get 方法中,我们使用唱片的 Id 来加载原有的唱片,这个参数通过路由传递过来,实际的代码类似在 Details 中看到的处理。除了专辑对象,同时还有处理下拉列表,所以,这里也通过 ViewBag 来处理,这样就允许我们在传递一个 Model 的同时还通过 ViewBag 传递了两个额外的 SelectList。
// // GET: /StoreManager/Edit/5 public ActionResult Edit(int id) { Album album = storeDB.Albums.Find(id); ViewBag.GenreId = new SelectList(storeDB.Genres, "GenreId", "Name", album.GenreId); ViewBag.ArtistId = new SelectList(storeDB.Artists, "ArtistId", "Name", album.ArtistId); return this.View(album); }
处理 Post 请求的 Edit 方法也非常类似于 Create 的 Post 处理方法,仅有的不同就是不用创建一个新的专辑对象加入到集合中,而是将现有的专辑对象,注意已经通过模型绑定获取了请求参数,将这个对象的状态属性 State 修改为 Modified ,这就回告诉 EF 我们正在修改一个存在的专辑对象,而不是创建一个新的。
// POST: /StoreManager/Edit/5 [HttpPost] public ActionResult Edit(Album album) { if (ModelState.IsValid) { storeDB.Entry(album).State = System.Data.EntityState.Modified; storeDB.SaveChanges(); return RedirectToAction("Index"); } ViewBag.GenreId = new SelectList(storeDB.Genres, "GenreId", "Name", album.GenreId); ViewBag.ArtistId = new SelectList(storeDB.Artists, "ArtistId", "Name", album.ArtistId); return View(album); }
注意,这个时候,编译器会提示一个错误:
类型“System.Data.EntityState”在未被引用的程序集中定义。必须添加对程序集“System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089”的引用。 F:\Lesson\MVC\MvcMusicStore\MvcMusicStore\Controllers\StoreManagerController.cs 76 17 MvcMusicStore
添加这个程序集的引用。
下面我们运行程序测试一下,浏览/StoreManager,然后点击 Edit 链接。
点击 Save, 回到专辑列表,可以看到值已经被更新了。
处理删除
删除的处理模式与 Edit 和 Create 一样,使用一个控制器的 Action 显示确认信息,使用另外一个 Action 来处理提交。
删除的 Get 处理非常类似于前面的 Details 处理。
// // GET: /StoreManager/Delete/5 public ActionResult Delete(int id) { Album album = storeDB.Albums.Find(id); return View(album); }
使用 Delete 视图模板显示强类型的 Album 表单。
默认的 Delete 视图使用模型来显示信息,但是,我们仅仅需要简单地显示确认信息就可以了,把这个视图修改一下,变成下面的样子。
@model MvcMusicStore.Models.Album @{ ViewBag.Title = "Delete"; } <h2> Delete Confirmation</h2> <p> Are you sure you want to delete the album titled <strong>@Model.Title</strong>? </p> @using (Html.BeginForm()) { <p> <input type="submit" value="Delete" /> </p> <p> @Html.ActionLink("Back to List", "Index") </p> }
这样,确认页面就成了下面的样子。
点击 Delete 按钮之后,将导致表单发送到服务器,执行 DeleteConfirmed 的 Action 处理方法。
// // POST: /StoreManager/Delete/5 [HttpPost, ActionName("Delete")] public ActionResult DeleteConfirmed(int id) { Album album = storeDB.Albums.Find(id); storeDB.Albums.Remove(album); storeDB.SaveChanges(); return RedirectToAction("Index"); }
在我们的 Post 处理中,完成了下面的任务
- 通过专辑的 Id 加载专辑对象
- 删除专辑,然后保存所做的修改
- 重新定向到 Index, 显示删除专缉之后的列表。
测试一下这些工作,运行程序,选择一个专辑,然后删除它。
点击删除之后,显示了第一张专辑的删除确认页面。
点击删除之后,原来的专辑已经消失了。
二、修改Index视图
记住,虽然脚手架可以为我们自动生成代码,但只是标准的 ASP.NET MVC 代码, 就像我们的这个教程可以节省你的学习时间一样,支架可以节省你手工创建控制器,以及强类型视图的时间,但是,具体的细节内容还是需要自己来处理。
所以,让我们来快速编辑一下 StoreManager 的 Index 视图(/Views/StoreManager/Index.cshtml)。这个视图通过一个 table 表格显示专辑的列表,包含专辑的公共属性,还带有进行编辑/详细内容/删除的链接。我们要删除专辑艺术家的链接,我们不需要显示这个值,在视图中的 <table> 部分,删除 AlbumArtUrl 相关的 <th> 和 <td> 元素,下面的代码中高亮显示的部分。
这样, Index 视图的代码应该如下所示:
@model IEnumerable<MvcMusicStore.Models.Album>
@{
ViewBag.Title = "Index";
}
<h2>
Index</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
Genre
</th>
<th>
Artist
</th>
<th>
Title
</th>
<th>
Price
</th>
<th>
</th>
</tr>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Genre.Name)
</td>
<td>
@Truncate(item.Artist.Name, )
</td>
<td>
@Truncate(item.Title, )
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id = item.AlbumId }) |
@Html.ActionLink("Details", "Details", new { id = item.AlbumId }) |
@Html.ActionLink("Delete", "Delete", new { id = item.AlbumId })
</td>
</tr>
}
</table>
三、运行效果
现在,可以运行一下了,访问 /StoreManager 可以得到如下的结果。
点击编辑链接,将会显示一个带有专辑字段的编辑表单。
点击位于底部的返回列表链接,然后,点击详细内容链接, 将会显示单个专辑的详细信息。
再来一次,回到列表,点击删除链接,现在将会看到一个确认对话框,显示了专辑的详细内容,请你确认是否真的需要删除。
点击底部的删除按钮,将会删除这个专辑,然后返回 Index 列表视图,专辑已经被删除了。
我们的工作还没有完成,我们要开始对控制器和视图的 CRUD 操作进行处理了。
《音乐商店》第4集:自动生成StoreManager控制器的更多相关文章
- ci框架根据配置自动生成controller控制器和model控制器(改版本)
CI修改如下: if($modle_file=config_item('modle_file')) { if ($modle_file === TRUE) { $modle_file=config_i ...
- Groovy元编程应用之自动生成订单搜索接口测试用例集
背景 在 "Groovy元编程简明教程" 一文中,简明地介绍了 Groovy 元编程的特性. 那么,元编程可以应用哪些场合呢?元编程通常可以用来自动生成一些相似的模板代码. 在 & ...
- 为测试框架model类自动生成xml结果集
问题:有大量类似于theProductId这样名字的字符串需要转换成the_product_id这种数据库column名的形式. 思路:见到(见)大写字母(缝)就插入(插)一个“_”字符(针)进去,最 ...
- MVC 音乐商店 第 8 部分: 购物车与 Ajax 更新
MVC 音乐商店是介绍,并分步说明了如何使用 ASP.NET MVC 和 Visual Studio 为 web 开发教程应用程序. MVC 音乐商店是一个轻量级的示例存储实现它卖音乐专辑在线,并实现 ...
- MVC 音乐商店 第 9 部分: 注册和结帐
MVC 音乐商店是介绍,并分步说明了如何使用 ASP.NET MVC 和 Visual Studio 为 web 开发教程应用程序. MVC 音乐商店是一个轻量级的示例存储实现它卖音乐专辑在线,并实现 ...
- ASP.NET MVC 音乐商店 - 3. 视图与模型
上一篇中使用字符串,这一篇我们就开始使用视图来处理. 我们已经可以从控制器的 Action 中返回一个字符串,这可以帮助我们更好地理解 Controller 是如何工作的.但是对于创建一个 Web 程 ...
- Hibernate Tools 自动生成hibernate的hbm文件
本文有待商榷 当我们在新增插件的时候发现会出现duplicate location,意思是所选的anchive所包含的zip路径已经复用,现象如下: 如上图所示黄色标记部分“Duplicate loc ...
- 利用 Oracle EM 企业管理器 进行oracle SQL的优化(自动生成索引)
利用 Oracle EM 企业管理器 进行oracle SQL的优化(自动生成索引) ##应用情景 项目中有大量的SQL,尤其是涉及到统计报表时,表关联比较多,当初开发建表时也没搞好索引关联的,上线后 ...
- T4 模板自动生成带注释的实体类文件
T4 模板自动生成带注释的实体类文件 - 只需要一个 SqlSugar.dll 生成实体就是这么简单,只要建一个T4文件和 文件夹里面放一个DLL. 使用T4模板教程 步骤1 创建T4模板 如果你没有 ...
随机推荐
- Web开发在线工具
JSON: JSON格式化工具 JSON检验并格式化工具 专为Web开发者准备的 63个免费在线工具
- CentOS 6.5 PYPI本地源制作
转载:blog.csdn.net/tantexian 一.安装pip2pi工具: pip install pip2pi 或 git clone https://github.com/wolever ...
- codeforces 463E . Caisa and Tree
题目链接 给一棵树, 两种操作, 一种是将点u的权值改为y, 另一种是查询根节点到点u的路径上, gcd(v, u)>1的深度最深的点v. 修改操作不超过50次. 这个题, 暴力可以过, 但是在 ...
- Judge loop in directed graph
1 深度优先方法 首先需要更改矩阵初始化函数init_graph() 然后我们需要初始化vist标记数组 深度优先访问图,然后根据是否存在back edge判断是否存在环路 算法如下: #includ ...
- CMake学习小结
假定有vegagis工程,工程的目录结构如下: #--vegagis# |--src 源文件目录# |--gui 界面工程,输出类型:dll,依赖于QT的QtCore.QtGui.QtXml ...
- ImageMagick 拼图及切图方法
ImageMagick 拼图方法1. 拼图montage *.jpg -tile 22x2 -geometry 64x256+0+0 10-.jpg将目录里的jpg文件按顺序拼成x轴22块,y轴2 ...
- STL 源代码剖析 算法 stl_algo.h -- partition
本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie partition ------------------------------------ ...
- C语言中操作符的优先级大全
C语言中操作符的优先级大全, 当然c++, Objective-C,大部分语言都试用. 下面是来自The C Programming Language 2th的总结. OperatorsAssocia ...
- leetcode先刷_Search in Rotated Sorted Array II
上一页下一页,找到相同的旋转阵列的问题.假设数组元素一再怎么办呢?会发生什么? 我给大家举一个极端的例子.如果是这样的阵列中的元件.1,1,2,1,1,1,1,我们想看看这个数组2,刚开始A[midd ...
- android FragmentPagerAdapter的“标准”配置
private class ImagePagerAdapter extends FragmentPagerAdapter { public List<ImageItem> ...