摘要

在 ASP.NET 中,ObjectDataSoruce 控制項是實現三層式的重要關鍵,我們可以透過 ObjectDataSoruce 控制項使用的自訂中間層商務物件。不過一般找到的範例都是直接繫結中間層商務物件,雖然範例通常寫得相當符合物件導向,可是在實際運用上有下列幾個問題。

問題一:維護性不佳

例如 Employee 商務物件的 Update 方法,可能有下列二種寫法

[寫法一] Update 方法中,每個欄位皆為引數

Public Function UpdateEmployee(EmployeeID As Integer, LastName As String, FirstName As String, _
                                   Address As String, City As String, Region As String, _
                                   PostalCode As String) As Integer

參考:http://msdn.microsoft.com/zh-tw/library/ms178538(VS.80).aspx

 

[寫法二] Update 方法使用強型別,每個欄位對應到類別的屬性

Public Function UpdateEmployee(employee As NorthwindEmployee) As Integer

參考:http://msdn.microsoft.com/zh-tw/library/ms227562(VS.80).aspx

 

可是實際上真能這樣用嗎?以[方法一]為例,若異動欄位非常多,Update 方法的引數不就多到嚇死人;[方法二]使用強型別可以解決欄位多的問題,不過欄位增減時,都需要同時維護 NorthwindEmployee 類別不是很麻煩嗎?當你的系統非常龐大時,例如有上千個表單,當這些表單若需同時新增一個欄位時,那就需要同時更新上千個對應的類別,可能會搞到你瘋掉。

 

問題二:批次異動問題

當 GridView 繫結 ObjectDataSource 在編輯一筆記錄時儲存時,有時我們並不希望該筆資料馬上異動回資料庫,也就是執行 ObjectDataSoruce 的 Update 方法,但資料不要真正寫回資料庫;而是所有編輯的資料先被暫存,最後執行一個方法(例如 Save),才將這些多筆資料的異動同時寫回資料。而 ObjectDataSource 在處理這部分的問題,也很難完成。

 

問題三:Mater-Detail 問題

有些表單具 Mater-Detail 的關係(如訂單),可是 ObjectDataSource 很難描述這種關係,因為 ObjectDataSource 的角色相當於 DataTable,而 Mater-Detal 是多個 DataTable 的集合,相當於 DataSet。也就是說需要有多個 ObjectDataSource 才能描述 Master-Detal 的關係,而這些 ObjectDataSource 的異動不能馬上寫回資料庫,表單的編輯動作都需要被暫存,當按下儲存時才能將整個 DataSet 的異動同時寫回資料庫。

 

TBBusinessObject 及 TBObjectDataSource 控制項

針對以上的問題,在此使用另一種方式來處理,讓 ObjectDataSource 繫結 BusinessObject 控制項,而 BusinessObject 控制項提供 DataSet 屬性,來暫存 ObjectDataSource 產生的異動。而呼叫真正的中間層商務物件時,再將 BusinessObject 控制項的 DataSet 屬性傳入,由中間層商務物件去異動資料庫。

以下範例以 GridView 繫結 ObjectDataSource,當 GridView 進行修改、刪除的動作時,會透過 ObjectDataSource 來呼叫 BusinessObject 控制項來進行異動,而這此異動並不會被寫回資料庫,而是異動 BusinessObject 控制項的 DataSet 屬性。

一般的作法為

GridView --> ObjectDataSoruce --> 中間層 BusinessObject

而這邊的作法為

GridView --> ObjectDataSoruce --> BusinessObject 控制項 --> 中間層 BusinessObject

 

image

在頁面上放置 TBBusinessObject 控制項及 TBObjectDataSource 控制項,在 TBObjectDataSource 控制項設定 BusinessObjectID="TBBusinessObject1" 繫結至 TBBusinessObject 控制項。

            <bee:TBBusinessObject ID="TBBusinessObject1" runat="server">
            </bee:TBBusinessObject>
            <bee:TBObjectDataSource ID="TBObjectDataSource1" runat="server" 
                OldValuesParameterFormatString="original_{0}" RowIndex="-1"
                TypeName="Bee.Web.WebControls.TBBusinessObject"
                BusinessObjectID="TBBusinessObject1"
                TableName="Employee">
            </bee:TBObjectDataSource>

當 Page Load 時產生的一個 Employee 的 DataTable,並將 DataTable 加入 TBBusinessObject.DataSet.Tables。在 GridView 執行 Update 及 Delete 時,要去設定 TBObjectDataSource 的 RowIndex,使用可以異動到對應的 DataRow。

Partial Class _Default
    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        If Not Me.IsPostBack Then
            Dim oTable As Data.DataTable
            Dim oColumn As Data.DataColumn
            Dim oRow As Data.DataRow

            oTable = New Data.DataTable("Employee")

            oColumn = New Data.DataColumn("ID", GetType(String))
            oTable.Columns.Add(oColumn)
            oColumn = New Data.DataColumn("Name", GetType(String))
            oTable.Columns.Add(oColumn)
            oColumn = New Data.DataColumn("Tel", GetType(String))
            oTable.Columns.Add(oColumn)

            oRow = oTable.NewRow()
            oRow("ID") = "001"
            oRow("Name") = "張三"
            oRow("Tel") = "02-11111111"
            oTable.Rows.Add(oRow)

            oRow = oTable.NewRow()
            oRow("ID") = "002"
            oRow("Name") = "李四"
            oRow("Tel") = "02-22222222"
            oTable.Rows.Add(oRow)

            oRow = oTable.NewRow()
            oRow("ID") = "003"
            oRow("Name") = "王五"
            oRow("Tel") = "02-33333333"
            oTable.Rows.Add(oRow)

            TBBusinessObject1.DataSet.Tables.Add(oTable)
            GridView1.DataBind()
        End If
    End Sub

    Protected Sub GridView1_RowCommand(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewCommandEventArgs) Handles GridView1.RowCommand
        Select Case e.CommandName
            Case "Update"
                TBObjectDataSource1.RowIndex = CInt(e.CommandArgument)
            Case "Delete"
                TBObjectDataSource1.RowIndex = CInt(e.CommandArgument)
        End Select
    End Sub
End Class

執行程式,GridView 會透過 TBObjectDataSource 的來取得 TBBusinessObject 中的 Employee DataTable 並顯示在 GridView 中。

image

按下編輯鈕,針對資料列進行編輯

image

按下更新鈕,異動就會被寫回 TBBusinessObject 中的 Employee DataTable。

image

當按下刪除鈕時,TBBusinessObject 中的 Employee DataTable 的該筆 DataRow 也會被刪除。

image

 

範例程式下程:BusinessObjectControl.rar

ASP.NET 魔法學院


DotBlogs Tags: BusinessObject ObjectDataSoruce ServerControl

Feedback

  • topcat 2008/6/6 下午 02:39 回覆

    # re: ObjectDataSoruce 繫結 BusinessObject 控制項

    小喵好奇請教一下

    TBBusinessObject 控制項與【TBObjectDataSource】是自己做的控制項,還是3 Part的控制項??

     

  • jeff377 2008/6/6 下午 03:44 回覆

    # re: ObjectDataSoruce 繫結 BusinessObject 控制項

    自己寫的控制項,它是提供 ObjectDataSource 及 真正的中間層溝通使用。

  • jeff377 2008/6/6 下午 04:09 回覆

    # re: ObjectDataSoruce 繫結 BusinessObject 控制項

    這個東東是二年多前我接觸 ASP.NET 2.0 時寫的一個概念雛形,當初是為了在無程式碼的情形下,方便連結現有的商務邏輯中間層使用,現在已經改版很多了;例如自訂 Toolbar 控制項繫結 BusinessObject 控制項,可以在無程式碼的情形下達行新增、刪除、修改、查詢...等動作。

  • Allen 2008/6/6 下午 05:16 回覆

    # re: ObjectDataSoruce 繫結 BusinessObject 控制項

    請問Jeff,由於SqlDataSource是asp.net 2.0才有的, 那麼貴公司在ASP.NET 1.x時開發時,一定早就有另外一套做法

    到了 2.0 您應該有思考過要沿用以前的架構,或引用2.0的新方法, 不知道您是如何評估要不要引進新技術的? 可否分享一下您的判斷依據或想法

    以我為例, 我可能初學GridView,FormView時,就覺得我的舊方法比較好,就放棄了新東西,不會再深入研究它(但solution卻往往就miss掉了)

  • jeff377 2008/6/6 下午 06:29 回覆

    # re: ObjectDataSoruce 繫結 BusinessObject 控制項

    我們沒有用 SqlDataSource,它一開始就被我排除掉了,因為 UI 層含 SQL 語法是不好的作法,真正比較好的 UI 層是看不到 SQL 語法。
    因為這樣以後有新的 UI 層(例如改用 WPF 做 UI 層),只要想辨法做一層資料交換的連結層,就能接進相同的中間層。

    我們公司是區分架構及系統開發二個 Team,一般新的技術都是由架構的 Team 負責去評估及測試再決定是否使用。而一般開發工具預設的控制項是不會直接使用,一定是封裝一層再交給開發人員使用。
    就算該控制項沒有更改任何東西,一定會先繼承下來再說,因為這樣以後才有修改的彈性。

    雖然架構設定不見得的自行開發控制項,不過自行開發控制項才能真正做到牽一髮而動全身,透過控制項才會讓架構更具彈性。

  • nite 2008/10/6 下午 01:46 回覆

    # re: ObjectDataSoruce 繫結 BusinessObject 控制項

    Dear jeff:
    小弟不才,初學ASP.NET中,看到您的範例,覺得和一般傳統性的做法不一樣,十分有彈性,弟適才親身實作一下,發現,要新增時,找不到方法可用
    在此,請教一下

    若是"新增(Insert)"時,您是如何完成的呢?

  • jeff377 2008/10/6 下午 03:16 回覆

    # re: ObjectDataSoruce 繫結 BusinessObject 控制項

    to nite :
    GridView 預設不支援新增(不過我有改寫支援新增 GridView),不過 ObjectDataSource 是支援新增的,TBObjectDataSource 沒有去處理新增的部分,這部分需要在 TBObjectDataSource 的 Inserting 事件中加上新增的程式碼即可。

  • nite 2008/10/6 下午 04:46 回覆

    # re: ObjectDataSoruce 繫結 BusinessObject 控制項

    Dear jeff:
    請恕小弟資質不佳,在GridView確實是沒有Insert hyperlink ,再次請教一下,我要如何改寫GridView使其有Insert hyperlink & Event的行為

    再次感謝您的指導

  • jeff377 2008/10/6 下午 05:03 回覆

    # re: ObjectDataSoruce 繫結 BusinessObject 控制項

    to nite :
    我另一篇文章有提供,可以參考看看。
    擴展 CommandField 類別 - Header 加入新增鈕
    http://www.dotblogs.com.tw/jeff377/archive/2008/05/13/3969.aspx

  • nite 2008/10/8 上午 11:26 回覆

    # re: ObjectDataSoruce 繫結 BusinessObject 控制項

    Dear jeff:
    不好意思,又來打擾
    在TBObjectDataSource內已加上Private Sub InsertingEventHandler(ByVal sender As Object, ByVal e As ObjectDataSourceMethodEventArgs) Handles Me.Inserting,
    也在TBBusinessObject內加入(我用猜的)Public Sub Insert(ByVal TableName As String, ByVal RowIndex As Integer, ByVal InputParameters As OrderedDictionary)
    我經過一整天的測試,當我按下Grid內的"新增"時,它沒有Event到TBObjectDataSource這裡

    請問一下,是我哪邊做錯了嗎??

  • jeff 2008/10/8 下午 12:13 回覆

    # re: ObjectDataSoruce 繫結 BusinessObject 控制項

    to nite :
    你要自行在 GridView 的 RowCommand 中處理新增動作,呼叫 DataSource 的控制項的 Insert 方法。

  • nite 2008/10/8 下午 01:33 回覆

    # re: ObjectDataSoruce 繫結 BusinessObject 控制項

    Dear jeff:
    小弟資質實在是太差了
    我目前還是無法領悟到如何在DataSource 使用Insert

    目前我的做法,在OnRowCommand(Insert)中製造一筆空的DataRow(新增前防呆,判斷DataTable最後一筆是否全空白or DBNull)
    使其GridView針對最後一筆,有"編輯"的效果,後續再去點選"編輯",以達到新增目的

    我這種做法,說白點,就是在亂搞,我本來預期的想法是
    按下"新增",Grid會新增一列 + 編輯的狀態
    無奈,功力不好,只會亂搞...

    謝謝您的指導

  • jeff 2008/10/8 下午 01:39 回覆

    # re: ObjectDataSoruce 繫結 BusinessObject 控制項

    to nite :
    你的作法的方向是對的,只是你把它寫在 Page 頁面的程式碼;其實你只要把那些程式碼想辨法搬到自訂的 GridView 控制項中就可以達到你的需求了,這樣 GridView 新增時就無需寫任何程式碼。

  • nick 2008/11/26 上午 09:46 回覆

    # re: ObjectDataSoruce 繫結 BusinessObject 控制項

    配合MasterPage 無法使用BusinessObject 會重複有問題

  • fet 2009/3/17 上午 09:10 回覆

    # re: ObjectDataSoruce 繫結 BusinessObject 控制項

    當我按下"刪除"後
    Ex:
    刪除 王五

    再按 "F5" 重新整理畫面
    發現它會一直刪除

    有沒有什麼方法,將前一次的 Command 清除
    謝謝

  • fet 2009/3/26 下午 12:35 回覆

    # re: ObjectDataSoruce 繫結 BusinessObject 控制項

    當我按下"刪除"後
    Ex:
    刪除 王五

    再按 "F5" 重新整理畫面
    發現它會一直刪除

    有沒有什麼方法,將前一次的 Command 清除
    謝謝

  • jeff 2009/3/27 上午 10:03 回覆

    # re: ObjectDataSoruce 繫結 BusinessObject 控制項

    to fet :

    這個問題很難解決,因為伺服端判斷不出來用戶端是真得按下刪除鈕或使用重新整理。

    有一個解決方法,不過比較麻煩,就是在刪除鈕前先設定一個 HiddenField 的值為 true,而伺服端判斷這個 HiddenField 的值是否為 true 才真處理刪除作業,當作業完成後再將此 HiddenField 設為 false;這樣按重新整理時,就不會重覆執行刪除動作。

標題 *
名稱 *
Email (將不會被顯示)
Url
回應
登入後使用進階評論
Please add 2 and 5 and type the answer here: