《Entity Framework 6 Recipes》中文翻译系列 (21) -----第四章 ASP.NET MVC中使用实体框架之在页面中创建查询和使用ASP.NET URL路由过虑
2015-05-21 20:48
1446 查看
翻译的初衷以及为什么选择《Entity Framework 6 Recipes》来学习,请看本系列开篇
问题
你想在ASP.NET MVC4中使用实体框架构建一搜索页面。
解决方案
假设你有如图4-14所示的模型,在这个解决方案中,我们打算使用三个基本的部分来构建搜索页:
1、一张用于构造查询参数的表;
2、一个用于在Razor视图中呈现结果的WebGrid;
3、一个包含视图逻辑的Cotroller;
在数据库中,你有一张Customer表,它存储所有客户的Name,City和State信息。Customer表的数据模型(架构)如图4-14所示。
图4-14 一个包含Customer 实体的模型
在Customer视图模型被创建之后,我们需要使用Razor来编写视图。在这个视图中,我们使用WebGrid控件来显示Customer记录。如代码清单4-5所示。
代码清单4-5. 在MVC Razor视图中使用WebGrid
一旦视图编写好,我就开始在Controller中编写支持Get和Post方式的查询功能。我们打算将从数据库中获取的Customer数据放到 view modle中,实现如代码清单4-6所示.
代码清单4-6. 获取数据代搜索页测试
你在你的浏览器中,页面呈现如图4-15所示:
图4-15 浏览器中呈现的视图
原理
在页面的第一小节中(请看代码清单4-5),我们使用table来格式化查询字段,这里没有花俏的技术,我们只是提供了获取三个查询字段:Name,City和State的结构。他们的值(或者没有),将用于查询按钮被点击了之后Controller的查询(Search)动作方法.因此,这些参数会成为查询的过虑条件。
接下来,我们使用HtmlHelper在WebGrid控件中显示结果集。数据源使用view model。这里需要注意,我们创建了两个模型,一个用于从数据库中获取数据,一个用于视图页收集查询参数,和呈现结果集。
我们使用Linq to entities来查询数据模型中的Customer实体,where从句和参数确定了我们的查询过滤。在视图中,我们将查询参数Name,City和State映射到 HtmlHelper中的文本框。将Name属性映射到文件框Name,依次类推。
我们使用控件WebGrid来显示结果集,它被绑定到CustomerVM.Customers列表,它是专门用来获取查询结果集的。
代码清单4-6中所展示的controller代码,从数据库中获取数据,并在第一次加载视图和点击查询按钮后填充视图。我们使用了本地数据库.mdf文件并在Customer表中填充了记录。
你想使用MapRoute来简化你的URLs,同时你想凭借这位路由在Razor视图引擎中过滤结果集。
解决方案
假设你有如图4-16的模型,我们已经对产品以及它们的目录建模,用实体类型Product来表示产品。在一个典型的电商网站中,我们需要按目录对产品进行分类。我们要避免在URLs中暴露类似 "/Product/Index?Category=Tents"这样的查询字符串。虽然这样会使编程简单一些,但无益于搜索引擎优化。我们需要看起像 “/Producs/Tents"这样的URLs.
图4-6 一个包含products和它们的categories
我们能通过路由得到对搜索引擎友好的URL,路由一般在Global.asax的Application_Start()事件处理函数中创建。代码清单4-7演示了为Product控制器添加一条路由。
代码清单4-7. 在Global.asax中创建一条路由
在代码清单4-8所示的Index视图中,我们使用category name绑定到Product controller中的Inde动作方法的name参数,如代码清单4-7所示。我们使用代码清单4-9中的代码获取category name参数的值,并通过视图处理结果集。图4-17和图4-18分别展示了呈现Tents目录下产品的视图页面,和Cooking Equipment目录下产品的视图页面。
代码清单4-8. Index视图代码,它显示通过目录过滤后的产品
代码清单4-9. Controller代码,使用通过Category Name过滤后的Product数据填充模型
图4-17 使用路径“/Product/Tents",得到Tents目录类别的产品集
图4-18 使用路径“/Product/cooking Equipment"得到cooking Equipment目录类别的产品集
原理
在Global.asax中 Applicate_Start()事件处理函数中,我们为之前的"/Product/Index?name=category"映射了路由 "/Product/{name}".在Product controller中,我们使用MapRoute中的路由key,name,过滤结果集,通过给定的目录过滤产品。
至此,第四章结束,感谢你的阅读。下一篇,我们将进入第五章的学习。
实体框架交流QQ群: 458326058,欢迎有兴趣的朋友加入一起交流
谢谢大家的持续关注,我的博客地址:http://www.cnblogs.com/VolcanoCloud/
4.2. 构建一个搜索查询
搜索数据是几乎所有应用的一个基本功能。它一般是动态的,因为用户可能使用提供的任何一个条件,或者一个也不使用。所以,我们在下面讨论实现这个基本功能的一些细节。问题
你想在ASP.NET MVC4中使用实体框架构建一搜索页面。
解决方案
假设你有如图4-14所示的模型,在这个解决方案中,我们打算使用三个基本的部分来构建搜索页:
1、一张用于构造查询参数的表;
2、一个用于在Razor视图中呈现结果的WebGrid;
3、一个包含视图逻辑的Cotroller;
在数据库中,你有一张Customer表,它存储所有客户的Name,City和State信息。Customer表的数据模型(架构)如图4-14所示。
图4-14 一个包含Customer 实体的模型
在Customer视图模型被创建之后,我们需要使用Razor来编写视图。在这个视图中,我们使用WebGrid控件来显示Customer记录。如代码清单4-5所示。
代码清单4-5. 在MVC Razor视图中使用WebGrid
@model EntityFrameworkRecipe2.ViewModels.CustomerVM @{ Layout = null; } @{ ViewBag.Title = "Customer"; WebGrid grid = new WebGrid(canPage:false,canSort:false); grid.Bind(Model.Customers, autoSortAndPage: false ); } @using (Html.BeginForm()) { <table> <tr> <td> Name </td> <td> @Html.TextBoxFor(model => model.Name) </td> </tr> <tr> <td> City </td> <td> @Html.TextBoxFor(model => model.City) </td> </tr> <tr> <td> State </td> <td> @Html.TextBoxFor(model => model.State) </td> </tr> <tr> <td colspan="2"> <input type="submit" id="search" title="Search" value="Search" /> </td> </tr> </table> <div id="searchResults"> <!-- placeHolder for search results --> @grid.GetHtml( fillEmptyRows: true, alternatingRowStyle: "alternate-row", headerStyle: "grid-header", footerStyle: "grid-footer", columns: new [] { grid.Column("Name"), grid.Column("City"), grid.Column("State") }) </div> }
一旦视图编写好,我就开始在Controller中编写支持Get和Post方式的查询功能。我们打算将从数据库中获取的Customer数据放到 view modle中,实现如代码清单4-6所示.
代码清单4-6. 获取数据代搜索页测试
public class CustomerController : Controller { public ActionResult Search() { using (var db = new CustomerEntities()) { var customer = db.Customers.ToList(); var data = new CustomerVM() { Customers = customer }; return View(data); } } [HttpPost] public ActionResult Search(CustomerVM customerVmValue) { using (var db = new CustomerEntities()) { var customerSearchResults = from customerRec in db.Customers where ((customerVmValue.Name == null) || (customerRec.Name == customerVmValue.Name.Trim())) && ((customerVmValue.City == null) || (customerRec.City == customerVmValue.City.Trim())) && ((customerVmValue.State == null) || (customerRec.State == customerVmValue.State.Trim())) select new { Name = customerRec.Name , City = customerRec.City , State = customerRec.State }; List<Customer> lstCustomer = new List<Customer>(); foreach (var record in customerSearchResults) { Customer customerValue = new Customer(); customerValue.Name = record.Name; customerValue.City = record.City; customerValue.State = record.State; lstCustomer.Add(customerValue); } customerVmValue.Customers = lstCustomer; return View(customerVmValue); } } }
你在你的浏览器中,页面呈现如图4-15所示:
图4-15 浏览器中呈现的视图
原理
在页面的第一小节中(请看代码清单4-5),我们使用table来格式化查询字段,这里没有花俏的技术,我们只是提供了获取三个查询字段:Name,City和State的结构。他们的值(或者没有),将用于查询按钮被点击了之后Controller的查询(Search)动作方法.因此,这些参数会成为查询的过虑条件。
接下来,我们使用HtmlHelper在WebGrid控件中显示结果集。数据源使用view model。这里需要注意,我们创建了两个模型,一个用于从数据库中获取数据,一个用于视图页收集查询参数,和呈现结果集。
我们使用Linq to entities来查询数据模型中的Customer实体,where从句和参数确定了我们的查询过滤。在视图中,我们将查询参数Name,City和State映射到 HtmlHelper中的文本框。将Name属性映射到文件框Name,依次类推。
我们使用控件WebGrid来显示结果集,它被绑定到CustomerVM.Customers列表,它是专门用来获取查询结果集的。
代码清单4-6中所展示的controller代码,从数据库中获取数据,并在第一次加载视图和点击查询按钮后填充视图。我们使用了本地数据库.mdf文件并在Customer表中填充了记录。
4.3. 使用ASP.NET的URL路由过虑
问题你想使用MapRoute来简化你的URLs,同时你想凭借这位路由在Razor视图引擎中过滤结果集。
解决方案
假设你有如图4-16的模型,我们已经对产品以及它们的目录建模,用实体类型Product来表示产品。在一个典型的电商网站中,我们需要按目录对产品进行分类。我们要避免在URLs中暴露类似 "/Product/Index?Category=Tents"这样的查询字符串。虽然这样会使编程简单一些,但无益于搜索引擎优化。我们需要看起像 “/Producs/Tents"这样的URLs.
图4-6 一个包含products和它们的categories
我们能通过路由得到对搜索引擎友好的URL,路由一般在Global.asax的Application_Start()事件处理函数中创建。代码清单4-7演示了为Product控制器添加一条路由。
代码清单4-7. 在Global.asax中创建一条路由
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteTable.Routes.MapRoute("Product", "{controller}/{name}", new { controller = "Product", action = "Index" } ); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); AuthConfig.RegisterAuth(); }
在代码清单4-8所示的Index视图中,我们使用category name绑定到Product controller中的Inde动作方法的name参数,如代码清单4-7所示。我们使用代码清单4-9中的代码获取category name参数的值,并通过视图处理结果集。图4-17和图4-18分别展示了呈现Tents目录下产品的视图页面,和Cooking Equipment目录下产品的视图页面。
代码清单4-8. Index视图代码,它显示通过目录过滤后的产品
@model IEnumerable<EntityFrameworkRecipe3.ViewModels.ProductVM> @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Index</title> </head> <body> <table> <tr> <th> @Html.DisplayNameFor(model => model.Name) </th> <th> @Html.DisplayNameFor(model => model.CategoryName) </th> <th></th> </tr> @foreach (var item in Model) { <tr> <td> @Html.DisplayFor(modelItem => item.Name) </td> <td> @Html.DisplayFor(modelItem => item.CategoryName) </td> </tr> } </table> </body> </html>
代码清单4-9. Controller代码,使用通过Category Name过滤后的Product数据填充模型
public class ProductController : Controller { // // GET: /Product/ public ActionResult Index(string name) { using (var db = new ProductEntities()) { var query = from productRec in db.Products join categoryRec in db.Categories on productRec.CategoryId equals categoryRec.CategoryId where categoryRec.Name == name select new { Name = productRec.Name , CategoryName = categoryRec.Name }; List<ProductVM> lstProduct = new List<ProductVM>(); foreach(var record in query) { ProductVM productValue = new ProductVM(); productValue.Name = record.Name; productValue.CategoryName = record.CategoryName; lstProduct.Add(productValue); } return View(lstProduct); } } }
图4-17 使用路径“/Product/Tents",得到Tents目录类别的产品集
图4-18 使用路径“/Product/cooking Equipment"得到cooking Equipment目录类别的产品集
原理
在Global.asax中 Applicate_Start()事件处理函数中,我们为之前的"/Product/Index?name=category"映射了路由 "/Product/{name}".在Product controller中,我们使用MapRoute中的路由key,name,过滤结果集,通过给定的目录过滤产品。
至此,第四章结束,感谢你的阅读。下一篇,我们将进入第五章的学习。
实体框架交流QQ群: 458326058,欢迎有兴趣的朋友加入一起交流
谢谢大家的持续关注,我的博客地址:http://www.cnblogs.com/VolcanoCloud/
相关文章推荐
- 《Entity Framework 6 Recipes》中文翻译系列 (20) -----第四章 ASP.NET MVC中使用实体框架之在MVC中构建一个CRUD示例
- 《Entity Framework 6 Recipes》中文翻译系列 (26) ------ 第五章 加载实体和导航属性之延缓加载关联实体和在别的LINQ查询操作中使用Include()方法
- 《Entity Framework 6 Recipes》中文翻译系列 (40) ------ 第七章 使用对象服务之从跟踪器中获取实体与从命令行生成模型(想解决EF第一次查询慢的,请阅读)
- 《Entity Framework 6 Recipes》中文翻译系列 (41) ------ 第七章 使用对象服务之标识关系中使用依赖实体与异步查询保存
- ASP.NET MVC 教程 - 使用实体框架创建模型类(C#)
- [翻译]ASP.NET MVC 3 开发的20个秘诀(十二)[20 Recipes for Programming MVC 3]:缩放图片尺寸创建缩略图
- [翻译]ASP.NET MVC 3 开发的20个秘诀(十四)[20 Recipes for Programming MVC 3]:使用Ajax提交Form
- [翻译]ASP.NET MVC 3 开发的20个秘诀(十九)[20 Recipes for Programming MVC 3]:路由用户至特定的Controller或Action
- [翻译]ASP.NET MVC 3 开发的20个秘诀(二十)[20 Recipes for Programming MVC 3]:缓存结果数据加速页面载入
- [翻译]ASP.NET MVC 3 开发的20个秘诀(二十)[20 Recipes for Programming MVC 3]:缓存结果数据加速页面载入
- 如何使用 asp.net 4.0 新特性 路由功能 有助于seo优化 给一个 asp.net web项目(网站项目) 增加路由功能 ,继承,给根据路由生成的url的结尾,增加一个有利于seo优化的斜杠 /,跳转到一个路由生成的url页面
- [翻译] 在 ASP.Net 4.0 中使用 QueryExtender 控件创建高效的搜索页面
- 使用ASP.NET MVC框架创建电子商务网站
- 使用ASP.NET MVC框架创建电子商务网站
- [ASP.NET MVC2 系列] ASP.NET MVC 之如何创建自定义路由约束
- ASP.NET MVC 实践之路 之四 使用View来创建页面
- 使用实体框架和 ASP.NET MVC 3 进行服务器端分
- WebCast《实战ASP.NET AJAX系列课程(2):使用客户端框架创建“纯粹”的Ajax应用程序》相关资源
- Scott的ASP.net MVC框架系列文章之二: URL映射
- 【翻译】使用ASP.NET MVC 和 LINQ 创建一个Blog引擎实例-第一节