多個OpenAccessLinqDataSource共用一個交易

  • 1805
  • 0

多個OpenAccessLinqDataSource共用一個交易

當我們使用 OpenAccessLinqDataSource 做新增、修改時,有時會需要全部成功能才回寫資料庫,任一個作業失敗就要全部回復異動前狀況,這時我們就要讓多個 OpenAccessLinqDataSource 控制項可以共用一個交易。

----------

當我們使用 OpenAccessLinqDataSource 時,通常頁面上都會有多個 OpenAccessLinqDataSource 控制項,有時候可能會需要執行多過控制項的新增、修改、刪除作業,但這此異動作業,只要有任何一筆發生錯誤,我們就必須要還原所有資料到異動前的版本,這時候該如何處理?

有兩種方式,一種是自訂 OpenAccessLinqDataSource 的 OpenAccessDataContext,也就是在 ContextCreating 事件,自行指派 OpenAccessDataContext,但這個方式很複雜,因為要處理至少以下這些工作:

  1. 在所有 OpenAccessLinqDataSource 建立前,先建立一個 OpenAccessDataContext,而且要使用類似獨體模式的架構,至少每次 PostBack 只能有一個 DataContext。
  2. 建立好 OpenAccessDataContext 後,調用 OpenAccessDataContext .Connection.BeginTransaction()。
  3. 因為預設所有 OpenAccessLinqDataSource 在執行 CRUD 後,會把自己用到的 DataContext 給 Dispose 掉,所以要去 ContextDisposing 事件,取消 Dispose 作業。
  4. 檢查所有 OpenAccessLinqDataSource 的 CRUD 作業都沒發生錯誤,才能把交易提交,否則要還原資料。

以上還只是文字說明,真正的作業方式還會再複雜些,所以我個人不建議使用此方式,最建議的方式,就是透過 TransactionScope 處理。

我們做個案例來展示 TransactionScope:當我們新增一筆訂單時,同時寫入一個新的客戶資料,這也是常見的實際案例。

現在請在 Web 專案中,新增一個 WebForm 名為 CreateOrdersAndAddNewCustomers.aspx,放置以下控制項:

  • 一個 TextBox,名為 txtNewCustomerIdSuffix,預設會是 LEO 起頭之顧客編號的筆數。
  • 一個 TextBox,名為 txtNewCustomerCompanyName。
  • 一個 Button,名為 btnCreateOrder,為本次示範的核心。它會收集上述兩個 TextBox 的資料,並調用兩個 OpenAccessLinqDataSource 的新增函式,執行 Insert 作業,當然這裡還要掛 TransactionScope,以達成兩個控制項的新增作業,被放在同一次的交易中。
  • 一個 GridView,名為 gvNewestOrder,用來顯示最新一筆訂單資料。
  • 一個 GridView,名為 gvList,用來顯示  LEO 起頭顧客編號之顧客資料。
  • 一個 Label,名為 lblLog,用來顯示兩個控制項 Insert 的 Sql Script。
  • 一個 OpenAccessLinqDataSource,名為 oasrcOrders,設定以訂單編號逆排序(由大到小),然後再透過 Selecting 事件,指定只查第一筆資料。
  • 一個 OpenAccessLinqDataSource ,名為 oasrcCustomers,設定以顧客編號逆排序,而且透過運算式編輯器設定 Where 條件,只取顧客編號起頭為 LEO 的資料回來。

這次的範例,會應用到前面幾篇文章的內容,如果有不了解的地方,請回頭參閱,本篇文章不再贅述。

CreateOrdersAndAddNewCustomers.aspx:


<%@ Register assembly="Telerik.OpenAccess.Web.40" namespace="Telerik.OpenAccess.Web" tagprefix="telerik" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>新增訂單資料同時新增顧客資料</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>    
        新顧客編號:LEO +
        <asp:TextBox ID="txtNewCustomerIdSuffix" runat="server" MaxLength="2"></asp:TextBox>
        <br />
        新顧客公司:<asp:TextBox ID="txtNewCustomerCompanyName" runat="server"></asp:TextBox>
        <br />
        <asp:Button ID="btnCreateOrder" runat="server" Text="新增一筆訂單" />
        <br />
        最新訂單:<br />
        <asp:GridView ID="gvNewestOrder" runat="server" AutoGenerateColumns="False" DataKeyNames="ORDERID" DataSourceID="oasrcOrders">
            <Columns>
                <asp:BoundField DataField="ORDERID" HeaderText="ORDERID" ReadOnly="True" SortExpression="ORDERID" />
                <asp:BoundField DataField="CUSTOMERID" HeaderText="CUSTOMERID" SortExpression="CUSTOMERID" />
            </Columns>
        </asp:GridView>
        <br />
        最新顧客名單(LEO打頭):<br />
        <asp:GridView ID="gvList" runat="server" AutoGenerateColumns="False" DataKeyNames="CUSTOMERID" DataSourceID="oasrcCustomers" PageSize="5">
            <Columns>
                <asp:BoundField DataField="CUSTOMERID" HeaderText="CUSTOMERID" ReadOnly="True" SortExpression="CUSTOMERID" />
                <asp:BoundField DataField="COMPANYNAME" HeaderText="COMPANYNAME" SortExpression="COMPANYNAME" />
            </Columns>
        </asp:GridView>
        <asp:Label ID="lblLog" runat="server"></asp:Label>
        <telerik:OpenAccessLinqDataSource ID="oasrcOrders" Runat="server" ContextTypeName="OALinqDataSourceWeb01.NWModel" EnableInsert="True" EntityTypeName="" ResourceSetName="Orders" OrderBy="ORDERID desc" />
        <telerik:OpenAccessLinqDataSource ID="oasrcCustomers" runat="server" ContextTypeName="OALinqDataSourceWeb01.NWModel" EntityTypeName="" ResourceSetName="Customers" OrderBy="CUSTOMERID desc" EnableInsert="True" Where="CUSTOMERID.StartsWith(@CUSTOMERID)" >
            <WhereParameters>
                <asp:Parameter DefaultValue="LEO" Name="CUSTOMERID" Type="String" />
            </WhereParameters>
        </telerik:OpenAccessLinqDataSource>
        </div>
    </form>
</body>
</html>

CreateOrdersAndAddNewCustomers.aspx.vb:



Public Class CreateOrdersAndAddNewCustomers
    Inherits System.Web.UI.Page
    Private tracer As MyNorthwindTraceListener
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        If tracer Is Nothing Then
            tracer = New MyNorthwindTraceListener(New StringBuilder())
        End If
    End Sub

    Private Sub oasrcCustomers_Inserted(sender As Object, e As Telerik.OpenAccess.Web.OpenAccessLinqDataSourceStatusEventArgs) Handles oasrcCustomers.Inserted, oasrcOrders.Inserted
        lblLog.Text = tracer.GetLogString()
    End Sub

    Private Sub oasrcCustomers_Selected(sender As Object, e As Telerik.OpenAccess.Web.OpenAccessLinqDataSourceStatusEventArgs) Handles oasrcCustomers.Selected
        txtNewCustomerIdSuffix.Text = CType(e.Result, IList(Of Customers)).Count().ToString().PadLeft(2, "0")
    End Sub

    Protected Sub btnCreateOrder_Click(sender As Object, e As EventArgs) Handles btnCreateOrder.Click
        Dim customerId As String = "LEO" & txtNewCustomerIdSuffix.Text.Trim()

        Dim customerProperties As New ListDictionary()
        customerProperties.Add("CUSTOMERID", customerId)
        customerProperties.Add("COMPANYNAME", txtNewCustomerCompanyName.Text.Trim())

        Dim orderProperties As New ListDictionary()
        orderProperties.Add("CUSTOMERID", customerId)

        lblLog.Text = ""
        Try
            Using scope As New TransactionScope()
                Dim tracer = New MyNorthwindTraceListener(New StringBuilder())
                oasrcCustomers.Insert(customerProperties)
                oasrcOrders.Insert(orderProperties)
                scope.Complete()
            End Using

            lblLog.Text &= "<br />新增成功。<br />" & tracer.GetLogString()
            gvList.DataBind()
            gvNewestOrder.DataBind()
        Catch ex As Exception
            lblLog.Text &= ex.Message
            lblLog.Text &= ex.InnerException.Message
        End Try
    End Sub

    Private Sub oasrcOrders_Selecting(sender As Object, e As Telerik.OpenAccess.Web.OpenAccessLinqDataSourceSelectEventArgs) Handles oasrcOrders.Selecting
        e.Arguments.MaximumRows = 1
    End Sub

End Class

顯示效果:

CreateOrderAndAddNewCustomer

如果我們故意在控制項執行 Insert 時,擲出 Exception,則新增作業就會被倒回(RollBack):

CreateOrderAndAddNewCustomerException

--------
沒什麼特別的~
不過是一些筆記而已