翻译的初衷以及为什么选择《Entity Framework 6 Recipes》来学习,请看本系列开篇

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

  1. @model EntityFrameworkRecipe2.ViewModels.CustomerVM
  2.  
  3. @{
  4. Layout = null;
  5. }
  6.  
  7. @{
  8. ViewBag.Title = "Customer";
  9. WebGrid grid = new WebGrid(canPage:false,canSort:false);
  10. grid.Bind(Model.Customers,
  11. autoSortAndPage: false
  12. );
  13. }
  14.  
  15. @using (Html.BeginForm())
  16. {
  17. <table>
  18. <tr>
  19. <td>
  20. Name
  21. </td>
  22. <td>
  23. @Html.TextBoxFor(model => model.Name)
  24. </td>
  25. </tr>
  26. <tr>
  27. <td>
  28. City
  29. </td>
  30. <td>
  31. @Html.TextBoxFor(model => model.City)
  32. </td>
  33. </tr>
  34. <tr>
  35. <td>
  36. State
  37. </td>
  38. <td>
  39. @Html.TextBoxFor(model => model.State)
  40. </td>
  41. </tr>
  42. <tr>
  43. <td colspan="2">
  44. <input type="submit" id="search" title="Search" value="Search" />
  45. </td>
  46. </tr>
  47. </table>
  48. <div id="searchResults">
  49. <!-- placeHolder for search results -->
  50. @grid.GetHtml(
  51. fillEmptyRows: true,
  52. alternatingRowStyle: "alternate-row",
  53. headerStyle: "grid-header",
  54. footerStyle: "grid-footer",
  55. columns: new [] {
  56. grid.Column("Name"),
  57. grid.Column("City"),
  58. grid.Column("State")
  59. })
  60. </div>
  61. }

  一旦视图编写好,我就开始在Controller中编写支持Get和Post方式的查询功能。我们打算将从数据库中获取的Customer数据放到 view modle中,实现如代码清单4-6所示.

代码清单4-6. 获取数据代搜索页测试

  1. public class CustomerController : Controller
  2. {
  3. public ActionResult Search()
  4. {
  5. using (var db = new CustomerEntities())
  6. {
  7. var customer = db.Customers.ToList();
  8. var data = new CustomerVM()
  9. {
  10. Customers = customer
  11. };
  12. return View(data);
  13. }
  14. }
  15. [HttpPost]
  16. public ActionResult Search(CustomerVM customerVmValue)
  17. {
  18. using (var db = new CustomerEntities())
  19. {
  20. var customerSearchResults = from customerRec in db.Customers
  21. where ((customerVmValue.Name == null) || (customerRec.Name == customerVmValue.Name.Trim()))
  22. && ((customerVmValue.City == null) || (customerRec.City == customerVmValue.City.Trim()))
  23. && ((customerVmValue.State == null) || (customerRec.State == customerVmValue.State.Trim()))
  24. select new
  25. {
  26. Name = customerRec.Name
  27. ,
  28. City = customerRec.City
  29. ,
  30. State = customerRec.State
  31. };
  32. List<Customer> lstCustomer = new List<Customer>();
  33. foreach (var record in customerSearchResults)
  34. {
  35. Customer customerValue = new Customer();
  36. customerValue.Name = record.Name;
  37. customerValue.City = record.City;
  38. customerValue.State = record.State;
  39. lstCustomer.Add(customerValue);
  40. }
  41. customerVmValue.Customers = lstCustomer;
  42. return View(customerVmValue);
  43. }
  44. }
  45. }

  你在你的浏览器中,页面呈现如图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中创建一条路由

  1. protected void Application_Start()
  2. {
  3. AreaRegistration.RegisterAllAreas();
  4.  
  5. WebApiConfig.Register(GlobalConfiguration.Configuration);
  6. FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
  7. RouteTable.Routes.MapRoute("Product", "{controller}/{name}",
  8. new { controller = "Product", action = "Index" }
  9. );
  10. RouteConfig.RegisterRoutes(RouteTable.Routes);
  11. BundleConfig.RegisterBundles(BundleTable.Bundles);
  12. AuthConfig.RegisterAuth();
  13. }

  在代码清单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视图代码,它显示通过目录过滤后的产品

  1. @model IEnumerable<EntityFrameworkRecipe3.ViewModels.ProductVM>
  2.  
  3. @{
  4. Layout = null;
  5. }
  6.  
  7. <!DOCTYPE html>
  8.  
  9. <html>
  10. <head>
  11. <meta name="viewport" content="width=device-width" />
  12. <title>Index</title>
  13. </head>
  14. <body>
  15. <table>
  16. <tr>
  17. <th>
  18. @Html.DisplayNameFor(model => model.Name)
  19. </th>
  20. <th>
  21. @Html.DisplayNameFor(model => model.CategoryName)
  22. </th>
  23. <th></th>
  24. </tr>
  25.  
  26. @foreach (var item in Model) {
  27. <tr>
  28. <td>
  29. @Html.DisplayFor(modelItem => item.Name)
  30. </td>
  31. <td>
  32. @Html.DisplayFor(modelItem => item.CategoryName)
  33. </td>
  34. </tr>
  35. }
  36.  
  37. </table>
  38. </body>
  39. </html>

代码清单4-9. Controller代码,使用通过Category Name过滤后的Product数据填充模型

  1. public class ProductController : Controller
  2. {
  3. //
  4. // GET: /Product/
  5.  
  6. public ActionResult Index(string name)
  7. {
  8. using (var db = new ProductEntities())
  9. {
  10. var query = from productRec in db.Products
  11. join categoryRec in db.Categories
  12. on productRec.CategoryId
  13. equals categoryRec.CategoryId
  14. where categoryRec.Name == name
  15. select new
  16. {
  17. Name = productRec.Name
  18. ,
  19. CategoryName = categoryRec.Name
  20. };
  21. List<ProductVM> lstProduct = new List<ProductVM>();
  22. foreach(var record in query)
  23. {
  24. ProductVM productValue = new ProductVM();
  25. productValue.Name = record.Name;
  26. productValue.CategoryName = record.CategoryName;
  27. lstProduct.Add(productValue);
  28. }
  29. return View(lstProduct);
  30. }
  31. }
  32.  
  33. }

图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》中文翻译系列 (21) -----第四章 ASP.NET MVC中使用实体框架之在页面中创建查询和使用ASP.NET URL路由过虑的更多相关文章

  1. 《Entity Framework 6 Recipes》中文翻译系列 (20) -----第四章 ASP.NET MVC中使用实体框架之在MVC中构建一个CRUD示例

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第四章  ASP.NET MVC中使用实体框架 ASP.NET是一个免费的Web框架 ...

  2. 《Entity Framework 6 Recipes》翻译系列 (1) -----第一章 开始使用实体框架之历史和框架简述

    微软的Entity Framework 受到越来越多人的关注和使用,Entity Framework7.0版本也即将发行.虽然已经开源,可遗憾的是,国内没有关于它的书籍,更不用说好书了,可能是因为EF ...

  3. 《Entity Framework 6 Recipes》翻译系列 (3) -----第二章 实体数据建模基础之创建一个简单的模型

    第二章 实体数据建模基础 很有可能,你才开始探索实体框架,你可能会问“我们怎么开始?”,如果你真是这样的话,那么本章就是一个很好的开始.如果不是,你已经建模,并在实体分裂和继承方面感觉良好,那么你可以 ...

  4. 《Entity Framework 6 Recipes》翻译系列(2) -----第一章 开始使用实体框架之使用介绍

    Visual Studio 我们在Windows平台上开发应用程序使用的工具主要是Visual Studio.这个集成开发环境已经演化了很多年,从一个简单的C++编辑器和编译器到一个高度集成.支持软件 ...

  5. 《Entity Framework 6 Recipes》翻译系列 (4) -----第二章 实体数据建模基础之从已存在的数据库创建模型

    不知道对EF感兴趣的并不多,还是我翻译有问题(如果是,恳请你指正),通过前几篇的反馈,阅读这个系列的人不多.不要这事到最后成了吃不讨好的事就麻烦了,废话就到这里,直奔主题. 2-2 从已存在的数据库创 ...

  6. 《Entity Framework 6 Recipes》翻译系列 (5) -----第二章 实体数据建模基础之有载荷和无载荷的多对多关系建模

    2-3 无载荷(with NO Payload)的多对多关系建模 问题 在数据库中,存在通过一张链接表来关联两张表的情况.链接表仅包含连接两张表形成多对多关系的外键,你需要把这两张多对多关系的表导入到 ...

  7. 《Entity Framework 6 Recipes》中文翻译系列 (28) ------ 第五章 加载实体和导航属性之测试实体是否加载与显式加载关联实体

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 5-11  测试实体引用或实体集合是否加载 问题 你想测试关联实体或实体集合是否已经 ...

  8. 《Entity Framework 6 Recipes》中文翻译系列 (41) ------ 第七章 使用对象服务之标识关系中使用依赖实体与异步查询保存

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 7-7  标识关系中使用依赖实体 问题 你想在标识关系中插入,更新和删除一个依赖实体 ...

  9. 《Entity Framework 6 Recipes》中文翻译系列 (11) -----第三章 查询之异步查询

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第三章 查询 前一章,我们展示了常见数据库场景的建模方式,本章将向你展示如何查询实体 ...

随机推荐

  1. js获取css中的样式

    众所周知,obj.style只能够获取 <div id="a" style="width:100px;"></div> 结构上的样式 如 ...

  2. HTML5开发笔记:图片上传预览

    我们知道通过<input type="file">可以用来进行一个图片或者文件的上传,然而浏览器自带的一个缩略图预览的功能其实是相当不美观的,很多时候我们希望可以在上传 ...

  3. 二分+DP+Trie HDOJ 5715 XOR 游戏

    题目链接 XOR 游戏 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total ...

  4. byobu相关操作

    http://lingbjxm.iteye.com/blog/2155833 重命名窗口:Fn F8

  5. 我的前端故事----优美的编辑器GitHub Atom

    很多前端的同学都在用sublime text,我之前也在使用,但是后来接触到了Atom,就被它的高颜值深深的吸引了~~不愧是GitHub的工程师哦~审美就是高  Atom 作为一个跨平台的编辑软件,安 ...

  6. JS获取当前时间戳的方法

    JavaScript 获取当前时间戳:第一种方法: var timestamp = Date.parse(new Date()); 结果:1280977330000第二种方法: var timesta ...

  7. 利用浏览器LocalStorage缓存图片,视频文件

    文章路径:https://hacks.mozilla.org/2012/02/saving-images-and-files-in-localstorage/

  8. sass

    本文来自阮一峰http://www.ruanyifeng.com/blog/2012/06/sass.html 学过CSS的人都知道,它不是一种编程语言. 你可以用它开发网页样式,但是没法用它编程.也 ...

  9. AJax登录。。转

    AJAX即“Asynchronous Javascript And XML”(异步JavaScript和XML),是指一种创建交互式网页应用的网页开发技术.        AJAX 是一种用于创建快速 ...

  10. (学)解决诡异的 Exception type: SocketException 127.0.0.1:80

    许久不发博了,老杨听完故事让我持续写一下“十万个为什么” 一.背景:  昨天我们亲密的战友HH刘老板亲临现场,指出我们协用的一个项目,客户方面反馈手持终端系统不定期“卡死”,要我们安排人飞到广州驻场解 ...