[修練營 ASP.NET]使用IList當作GridView資料來源,且T型別的屬性裡有自訂型別
原發問網址:http://social.msdn.microsoft.com/Forums/zh-TW/236/thread/85cda68d-e97b-49a1-9ddb-665eaf17e022
前言
之前使用Spring.NET的Adotemplate來處理DAO的操作時,
會實作Spring.Data.IRowMapper來達到ORM的效果,
通常RowMapper裡return的都是Domain object或Domain object的集合,
也就是Spring.Data.Core.AdoDaoSupport.QueryWithRowMapper()會return IList型別的資料集合。
但是我們的Domain Object或ORM的結果,可能會出現物件的屬性型別又是另外一個物件,
例如以NorthWind為例子,我的Orders object可能是像這樣:
{
int? OrderID { get; set; }
ICustomers Customer { get; set; }
string EmployeeID { get; set; }
DateTime? OrderDate { get; set; }
DateTime? RequiredDate{ get; set; }
int? ShipVia { get; set; }
decimal? Freight{ get; set; }
string ShipName{ get; set; }
string ShipAddress{ get; set; }
string ShipCity{ get; set; }
string ShipRegion{ get; set; }
string ShipPostalCode{ get; set; }
string ShipCountry{ get; set; }
}
而我的IOrders.Customer的定義如下:
{
string CustomerID{get;set;}
string CompanyName { get; set; }
string ContactName { get; set; }
string Address { get; set; }
string City { get; set; }
string Region { get; set; }
string Country { get; set; }
string Phone { get; set; }
string Fax { get; set; }
string ContactTitle { get; set; }
string PostalCode { get; set; }
}
這樣才有ORM與domain object的抽象意義,但是問題來了…
面對這樣有階層式物件的IList時,GridView是看不懂第二層物件以下的屬性。
例如:
當GridView希望從IList<Orders>裡面,
希望bind完column的資料有OrderID, CustomerID, City。
其中的CustomerID與City是在Customer物件底下的屬性,寫成下面的code,會出現錯誤。
<Columns>
<asp:BoundField DataField="OrderID" HeaderText="OrderID" />
<asp:BoundField DataField="CustomerID" HeaderText="CustomerID" />
</Columns>
</asp:GridView>
其實在上個案子(ASP.NET 2.0)就有遇到這問題了,
當時的解法是將IList在攤平塞到DataTable裡面,水瓶大也提供了他一篇頗完整的方式,這邊列上來給大家參考:Convert IEnumerable to a DataTable
不過因為我這邊是為了ORM才轉成IList,如果為了GridView又要把IList轉成DataTable,感覺好像有點脫褲子放屁,
也頗納悶GridView是不是有其他塞值的方式,可以看的懂多階層的IList<T>。
幾位前輩提供了幾個方式,都可以解決我的問題,這邊也整理給大家當個參考。
Solution
- 第一種解法很快,資料來源不用改,只需要使用Eval("Customer.City")這樣的方式即可。
ASP.NET 2.0與3.5都可以這樣使用,不過programlin有提醒了一點要注意:Eval只能套用在顯示,像排序無法使用。<Columns> <asp:BoundField DataField="OrderID" HeaderText="OrderID" /> <asp:TemplateField> <ItemTemplate> <%# Eval("Customer.City") %> </ItemTemplate> </asp:TemplateField> </Columns> </asp:GridView>
- 在ASP.NET 3.5裡,當然IList這種東西,就是要交給Linq來展現一下魅力,這也是我後來採用的方式,透過Linq把IList攤平成GridView看的懂的匿名型別。
select new { OrderID = o.OrderID, CustomerID = o.Customer.CustomerID, City = o.Customer.City }).ToList(); this.GridView1.DataSource = gridOrders; this.GridView1.DataBind();
- Lolota大提供的解法,使用ObjectDataSource,http://forums.asp.net/p/977366/1361197.aspx#1361197
.aspx
TypeName="ParentComponent"></asp:ObjectDataSource> <asp:GridView ID="GridView1" runat="server" AllowPaging="True" AutoGenerateColumns="False" CellPadding="4" DataSourceID="ObjectDataSource1" ForeColor="#333333" GridLines="None"> <RowStyle BackColor="#EFF3FB" /> <Columns> <asp:CommandField ShowSelectButton="True" /> <asp:BoundField DataField="ParentID" HeaderText="ParentID" SortExpression="ParentID" /> <asp:BoundField DataField="ParentName" HeaderText="ParentName" SortExpression="ParentName" /> </Columns> <FooterStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" /> <PagerStyle BackColor="#2461BF" ForeColor="White" HorizontalAlign="Center" /> <SelectedRowStyle BackColor="#D1DDF1" Font-Bold="True" ForeColor="#333333" /> <HeaderStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" /> <EditRowStyle BackColor="#2461BF" /> <AlternatingRowStyle BackColor="White" /> </asp:GridView>
.cs
using System.Collections.Generic; using System.Linq; using System.Web; using System.Collections; [Serializable()] public class Parent { private int mParentID; private string mParentName; public int ParentID { get { return mParentID; } set { mParentID = value; } } public string ParentName { get { return mParentName; } set { mParentName = value; } } public Parent() { } public Parent(int parentID, string parentName) { mParentID = parentID; mParentName = parentName; } } public class ParentComponent { public static IList<Parent> GetParents() { IList<Parent> mParentList = new List<Parent>(); mParentList.Add(new Parent(10,"XXX")); mParentList.Add(new Parent(11, "YYY")); mParentList.Add(new Parent(12, "XXX")); return mParentList; } }
以上謝謝各位前輩的指導,解決了困擾我頗久的問題,(我實在對aspx上的<%# %>很不熟啊...)
後記
現在又遇到一個Sort的問題....
用Linq的寫法,雖然要排序只要加個orderby 「物件.屬性」 在from跟select中間,
可是要怎麼寫成抓e.sortExpression塞到order o.OrderID或o.Customer.CustomerID,我又卡關了....
(這個時候就覺得DataTable轉DataView好用多了 )
不曉得有沒前輩可以幫忙解決我這個疑問的,小弟在這邊不勝感激...
blog 與課程更新內容,請前往新站位置:http://tdd.best/