[ASP.NET MVC] LINQ 查詢結果送至 View 與 Model 綁定
基礎課程裡 LINQ 查詢結果要顯示在 View 上,通常是一筆 record 或多筆成一個 List,但實務上有更多需求例如 join 和選取特定 field ,下面將網路上找來的教學做一個筆記。
- 查詢一筆資料,綁定傳給 View
- 查詢多筆資料,傳給 View
- Join 並只選取部份欄位
- Join 並只選取部份欄位 by anonymous class
- Join 並只選取部份欄位 by ViewModel
- 後記:LINQ Join 的 method syntax
查詢一筆資料,綁定傳給 View
例如有一個資料表 Orders,內有三筆資料,已建立 Entity 叫 dbtestEntities:
查主鍵 OrderId 為 102 的資料,可用 .Find() 方法,回傳為一個 Orders 物件。
Controller:using prjMVC.Models; namespace prjMVC.Controllers { public class HomeController : Controller { dbtestEntities db = new dbtestEntities(); public ActionResult QueryOneRecord() { Orders result = db.Orders.Find(102); return View(result); } } }
查到的 result 是單一 Orders 物件,直接帶去 View。
加入 QueryOneRecord 的檢視時,模型類別要選 Entity Framework 產生的 Orders 類別,或是手動在 View 最上面寫:
@model prjMVC.Models.Orders <div> <p> OrderId : @Model.OrderId </p> <p> ProductId : @Model.ProductId </p> <p> Quantity : @Model.Quantity </p> <p> Date : @Model.Date </p> </div>
結果:
查詢多筆資料,傳給 View
例如有一個資料表 Products內有七筆資料:
要查詢「Price 大於 30 的資料」,Controller:
using prjMVC.Models; namespace prjMVC.Controllers { public class HomeController : Controller { dbtestEntities db = new dbtestEntities(); public ActionResult QueryList() { IQueryable<Products> result = db.Products.Where(m => m.Price > 30); //或 IQueryable<Products> result = from prod in db.Products // where prod.Price > 30 // select prod; return View(result); } } }
新增 QueryList 的檢視,綁定的模型類別用 IQueryable<prjMVC.Models.Products>,或是如 List 範本產生的 IEnumerable<prjMVC.Models.Products>:
@model IQueryable<prjMVC.Models.Products> <table border="1"> <tr> <th>ProductId</th> <th>Name</th> <th>Price</th> </tr> @foreach(var item in Model) { <tr> <td>@item.ProductId</td> <td>@item.Name</td> <td>@item.Price</td> </tr> } </table>
結果:
Controller 傳給 View 的是集合 IQueryable<Products>,自然在 View 裡就要宣告 @model 為 IQueryable<Products> 綁定 Model 為傳入資料,始可對他使用 foreach 遍尋,也可以在 LINQ 查詢完後接 .ToList() 轉型,若有轉為 List 就要在 View 以 List<prjMVC.Models.Products> 來綁定
Join 並只選取部份欄位
一起看以上 Orders 和 Products 兩個資料表:
兩資料表以 ProductId 來 join ,若 SQL 中執行 select * from Orders as o join Products as p on o.ProductId = p.ProductId; 指令,得到的結果為:
用了 Join 會面臨一個問題,就是沒有哪個類別同時包含兩個資料表類別的屬性,所以這裡要用新的類別去接,方法又分匿名類別和 ViewModel
Join 並只選取部份欄位 by anonymous class
如果只在 Controller 之中使用查詢結果,其實用匿名類別即可,例如:using prjMVC.Models; namespace prjMVC.Controllers { public class HomeController : Controller { dbtestEntities db = new dbtestEntities(); public ActionResult JoinTwoTable() { var result = from ord in db.Orders join prod in db.Products on ord.ProductId equals prod.ProductId select new // 匿名類別 { OrderId = ord.OrderId, Name = prod.Name, Price = prod.Price, Quantity = ord.Quantity }; string output = string.Empty; foreach(var item in result) { output += $"{item.OrderId} {item.Name} : {item.Price},{item.Quantity}<br />"; } return Content(output); } } }
滑鼠移到 var result 上可看到是匿名類別
結果:
這個適合在沒有要傳到 View 的操作,例如 Ajax 來 action 取資料,用匿名類別即可。
Join 並只選取部份欄位 by ViewModel
但是要將 LINQ 查詢結果傳至 View ,顯然匿名類別就無法在 View 中做綁定(View 中不知道要 @model 什麼類別),這個解決辦法是寫一個為這個 action 打造的 ViewModel,例如新增一個 ~/ViewModels/ 資料夾,新增一個類別叫 VMJoinTwoTable:
namespace prjMVC.ViewModels { public class VMJoinTwoTable { public int OrderId { get; set; } // 這些屬性的類型是根據 Entity 中對應 public string Name { get; set; } // 的屬性的類型,完全一樣才行 public Nullable<int> Price { get; set; } public Nullable<int> Quantity { get; set; } } }
接下來 LINQ 查詢結果用這個 ViewModel 來實體化,Controller:
using prjMVC.Models; using prjMVC.ViewModels; namespace prjMVC.Controllers { public class HomeController : Controller { dbtestEntities db = new dbtestEntities(); public ActionResult JoinTwoTable() { var result = from ord in db.Orders join prod in db.Products on ord.ProductId equals prod.ProductId select new VMJoinTwoTable // 使用 ViewModel 接 { OrderId = ord.OrderId, Name = prod.Name, Price = prod.Price, Quantity = ord.Quantity }; return View(result); } } }
將滑鼠移到 var result 上會得知 result 有確定的類型 IQueryable<VMJoinTwoTable> 了,所以也可以直接宣告這個類別。
然後新增 JoinTwoTable 的檢視,可用 List 範本選 ~/ViewModels/VMJoinTwoTable 模型類別:
或自己手動在 View 中 @model 綁定 IQueryable<prjMVC.ViewModels.VMJoinTwoTable> 或如 List 範本產生的IEnumerable<prjMVC.ViewModels.VMJoinTwoTable>:
@model IEnumerable<prjMVC.ViewModels.VMJoinTwoTable> <table border="1"> <tr> <th>OrderId</th> <th>Name</th> <th>Price</th> <th>Quantity</th> </tr> @foreach(var item in Model) { <tr> <td>@item.OrderId</td> <td>@item.Name</td> <td>@item.Price</td> <td>@item.Quantity</td> </tr> } </table>
結果:
後記:LINQ Join 的 method syntax
上述的 LINQ Join 語法是 query syntax,少數比 method syntax 還好寫的,下面是 LINQ 的 Join 的 method syntax:
var result = db.Orders.Join(db.Products, ord => ord.ProductId, prod => prod.ProductId, (ord, prod) => new VMJoinTwoTable { OrderId = ord.OrderId, Name = prod.Name, Price = prod.Price, Quantity = ord.Quantity });
留言
張貼留言