[修練營 ASP.NET]使用IList<T>當作GridView資料來源,且T型別的屬性裡有自訂型別

  • 11754
  • 0

[修練營 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>

error

其實在上個案子(ASP.NET 2.0)就有遇到這問題了,
當時的解法是將IList在攤平塞到DataTable裡面,水瓶大也提供了他一篇頗完整的方式,這邊列上來給大家參考:Convert IEnumerable to a DataTable

不過因為我這邊是為了ORM才轉成IList,如果為了GridView又要把IList轉成DataTable,感覺好像有點脫褲子放屁,
也頗納悶GridView是不是有其他塞值的方式,可以看的懂多階層的IList<T>。

幾位前輩提供了幾個方式,都可以解決我的問題,這邊也整理給大家當個參考。

 

Solution

  1. 第一種解法很快,資料來源不用改,只需要使用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>
  2. 在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();
  3. 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/