翻譯的初衷以及爲何選擇《Entity Framework 6 Recipes》來學習,請看本系列開篇html
搜索數據是幾乎全部應用的一個基本功能。它通常是動態的,由於用戶可能使用提供的任何一個條件,或者一個也不使用。因此,咱們在下面討論實現這個基本功能的一些細節。數據庫
問題編程
你想在ASP.NET MVC4中使用實體框架構建一搜索頁面。瀏覽器
解決方案架構
假設你有如圖4-14所示的模型,在這個解決方案中,咱們打算使用三個基本的部分來構建搜索頁:框架
一、一張用於構造查詢參數的表;函數
二、一個用於在Razor視圖中呈現結果的WebGrid;學習
三、一個包含視圖邏輯的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表中填充了記錄。
問題
你想使用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/