[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
});
留言
張貼留言