資料來源控制項

Microsoft提供

ASP.NET 1.x 中的 DataGrid 控制項標示了 Web 應用程式中資料存取的大幅改善。 不過,它不如使用者易記。 它仍然需要相當大量的程式碼,才能從中取得相當實用的功能。 這是 1.x 中的所有資料存取工作中的模型。

ASP.NET 1.x 中的 DataGrid 控制項標示了 Web 應用程式中資料存取的大幅改善。 不過,它不如使用者易記。 它仍然需要相當大量的程式碼,才能從中取得相當實用的功能。 這是 1.x 中的所有資料存取工作中的模型。

ASP.NET 2.0 使用資料來源控制項來解決此問題。 ASP.NET 2.0 中的資料來源控制項提供開發人員用來擷取資料、顯示資料及編輯資料的宣告式模型。 資料來源控制項的目的是為數據系結控制項提供一致的資料標記法,而不論這些資料的來源為何。 ASP.NET 2.0 中資料來源控制項的核心是 DataSourceControl 抽象類別。 DataSourceControl 類別提供 IDataSource 介面和 IListSource 介面的基底實作,後者可讓您透過稍後討論的新 DataSourceId 屬性,將資料來源控制項指派為資料繫結控制項的 DataSource, (稍後討論的新 DataSourceId 屬性) ,並將資料公開為清單。 資料來源控制項中的每個資料清單都會公開為 DataSourceView 物件。 IDataSource 介面會提供 DataSourceView 實例的存取權。 例如,GetViewNames 方法會傳回 ICollection,可讓您列舉與特定資料來源控制項相關聯的 DataSourceViews,而 GetView 方法可讓您依名稱存取特定的 DataSourceView 實例。

資料來源控制項沒有使用者介面。 它們會實作為伺服器控制項,以便支援宣告式語法,以便他們可視需要存取頁面狀態。 資料來源控制項不會將任何 HTML 標籤轉譯給用戶端。

注意

如您稍後所見,也會使用資料來源控制項取得快取優點。

儲存連接字串

在開始查看如何設定資料來源控制項之前,我們應該先說明有關連接字串的 ASP.NET 2.0 新功能。 ASP.NET 2.0 引進組態檔中的新區段,可讓您輕鬆地儲存可在執行時間動態讀取的連接字串。 <connectionStrings 區 > 段可讓您輕鬆地儲存連接字串。

下列程式碼片段會新增連接字串。

<connectionStrings> <add name="Northwind" connectionString="Data Source=localhost; Integrated Security=SSPI;Initial Catalog=Northwind;" providerName="System.Data.SqlClient" /> </connectionStrings>

注意

如同 < appSettings 區段, < connectionStrings >> 區段會出現在組態檔中的 system.web > 區段之外 < 。

若要使用此連接字串,您可以在設定伺服器控制項的 ConnectionString 屬性時使用下列語法。

ConnectionString="<%$ ConnectionStrings:Northwind%>"

<connectionStrings > 區段也可以加密,以便不會公開敏感性資訊。 稍後的課程模組將涵蓋該功能。

快取資料來源

每個 DataSourceControl 都會提供四個屬性來設定快取;EnableCaching、CacheDuration、CacheExpirationPolicy 和 CacheKeyDependency。

EnableCaching

EnableCaching 是布林值屬性,可判斷是否為數據源控制項啟用快取。

CacheDuration 屬性

CacheDuration 屬性會設定快取維持有效的秒數。 將此屬性設定為 0 會導致快取保持有效狀態,直到明確失效為止。

CacheExpirationPolicy 屬性

CacheExpirationPolicy 屬性可以設定為 AbsoluteSliding。 將它設定為 Absolute 表示快取資料的最大時間量是 CacheDuration 屬性所指定的秒數。 藉由將它設定為 [滑動],則會在執行每個作業時重設到期時間。

CacheKeyDependency 屬性

如果已為 CacheKeyDependency 屬性指定字串值,ASP.NET 將會根據該字串設定新的快取相依性。 這可讓您直接變更或移除 CacheKeyDependency 來明確使快取失效。

重要事項:如果啟用模擬並存取資料來源和/或資料的內容是以用戶端身分識別為基礎,建議藉由將 EnableCaching 設定為 False 來停用快取。 如果在此案例中啟用快取,以及原本要求資料的使用者以外的使用者發出要求,則不會強制執行資料來源的授權。 資料只會從快取提供。

SqlDataSource 控制項

SqlDataSource 控制項可讓開發人員存取任何支援 ADO.NET 關係資料庫中儲存的資料。 它可以使用 System.Data.SqlClient 提供者來存取SQL Server資料庫、System.Data.OleDb 提供者、System.Data.Odbc 提供者或 System.Data.OracleClient 提供者來存取 Oracle。 因此,SqlDataSource 當然不只用於存取SQL Server資料庫中的資料。

若要使用 SqlDataSource,您只需提供 ConnectionString 屬性的值,並指定 SQL 命令或預存程式。 SqlDataSource 控制項負責處理基礎 ADO.NET 架構。 它會開啟連線、查詢資料來源或執行預存程式、傳回資料,然後為您關閉連線。

注意

由於 DataSourceControl 類別會自動為您關閉連線,因此應該減少流失資料庫連結所產生的客戶通話數目。

下列程式碼片段會使用儲存在組態檔中的連接字串,將 DropDownList 控制項系結至 SqlDataSource 控制項,如下所示。

<asp:SqlDataSource id="SqlDataSource1" runat="server" DataSourceMode="DataReader" ConnectionString="<%$ ConnectionStrings:Northwind%>" SelectCommand="SELECT EmployeeID, LastName FROM Employees"> </asp:SqlDataSource><asp:DropDownList id="ListBox1" runat="server" DataTextField="LastName" DataValueField="EmployeeID" DataSourceID="SqlDataSource1"> </asp:DropDownList>

如上所述,SqlDataSource 的 DataSourceMode 屬性會指定資料來源的模式。 在上述範例中,DataSourceMode 會設定為 DataReader。 在此情況下,SqlDataSource 會使用順向和唯讀資料指標傳回 IDataReader 物件。 所傳回的指定物件類型是由所使用的提供者所控制。 在此情況下,我使用 system.Data.SqlClient 提供者,如web.config檔案的 connectionStrings > 區段中所指定 < 。 因此,傳回的物件類型為 SqlDataReader。 藉由指定 DataSet 的 DataSourceMode 值,資料可以儲存在伺服器上的 DataSet 中。 此模式可讓您新增排序、分頁等功能。如果我已經將資料系結 SqlDataSource 至 GridView 控制項,我就會選擇 DataSet 模式。 不過,在 DropDownList 的情況下,DataReader 模式是正確的選擇。

注意

快取 SqlDataSource 或 AccessDataSource 時,DataSourceMode 屬性必須設定為 DataSet。 如果您使用 DataReader 的 DataSourceMode 啟用快取,就會發生例外狀況。

SqlDataSource 屬性

以下是 SqlDataSource 控制項的一些屬性。

CancelSelectOnNullParameter

布林值,指定如果其中一個參數為 Null,是否取消 select 命令。 預設為 true。

ConflictDetection

在多個使用者可能同時更新資料來源的情況下,ConflictDetection 屬性會決定 SqlDataSource 控制項的行為。 這個屬性會評估為 ConflictOptions 列舉的其中一個值。 這些值為 CompareAllValuesOverwriteChanges。 如果設定為 OverwriteChanges,則將資料寫入資料來源的最後一個人會覆寫任何先前的變更。 不過,如果 ConflictDetection 屬性設定為 CompareAllValues,則會針對 SelectCommand 傳回的資料行建立參數,而且也會建立參數,以保存每一個資料行中的原始值,讓 SqlDataSource 判斷值在執行 SelectCommand 之後是否已變更。

DeleteCommand

設定或取得從資料庫刪除資料列時所使用的 SQL 字串。 這可以是 SQL 查詢或預存程式名稱。

DeleteCommandType

設定或取得 delete 命令的類型、SQL 查詢 (文字) 或預存程式 (StoredProcedure) 。

DeleteParameters

傳回與 SqlDataSource 控制項相關聯之 SqlDataSourceView 物件的 DeleteCommand 所使用的參數。

OldValuesParameterFormatString

如果 ConflictDetection 屬性設定為 CompareAllValues,這個屬性是用來指定原始值參數的格式。 預設值表示 {0} 原始值參數會採用與原始參數相同的名稱。 換句話說,如果功能變數名稱是 EmployeeID,則原始值參數會是 @EmployeeID 。

SelectCommand

設定或取得用來從資料庫擷取資料的 SQL 字串。 這可以是 SQL 查詢或預存程式名稱。

SelectCommandType

設定或取得 select 命令的類型、SQL 查詢 (Text) 或預存程式 (StoredProcedure) 。

SelectParameters

傳回與 SqlDataSource 控制項相關聯之 SqlDataSourceView 物件的 SelectCommand 所使用的參數。

SortParameterName

取得或設定在排序資料來源控制項所擷取之資料時所使用的預存程式參數名稱。 只有在 SelectCommandType 設定為 StoredProcedure 時才有效。

SqlCacheDependency

以分號分隔的字串,指定SQL Server快取相依性中使用的資料庫和資料表。 (SQL 快取相依性將在稍後的課程模組中討論。)

UpdateCommand

設定或取得更新資料庫中資料時所使用的 SQL 字串。 這可以是 SQL 查詢或預存程式名稱。

UpdateCommandType

會設定或取得更新命令的類型、SQL 查詢 (Text) 或預存程式 (StoredProcedure) 。

UpdateParameters

傳回與 SqlDataSource 控制項相關聯之 SqlDataSourceView 物件的 UpdateCommand 所使用的參數。

AccessDataSource 控制項

AccessDataSource 控制項衍生自 SqlDataSource 類別,可用來將資料系結至 Microsoft Access 資料庫。 AccessDataSource 控制項的 ConnectionString 屬性是唯讀屬性。 DataFile 屬性會用來指向 Access 資料庫,而不是使用 ConnectionString 屬性,如下所示。

<asp:AccessDataSource id="AccessDataSource1" runat="server" DataFile="~/App_Data/Northwind.mdb"> </asp:AccessDataSource>

AccessDataSource 一律會將基底 SqlDataSource 的 ProviderName 設定為 System.Data.OleDb,並使用 Microsoft.Jet.OLEDB.4.0 OLE DB 提供者連接到資料庫。 您無法使用 AccessDataSource 控制項連線到受密碼保護的 Access 資料庫。 如果您必須連線到受密碼保護的資料庫,您應該使用 SqlDataSource 控制項。

注意

儲存在網站中的存取資料庫應該放在App_Data目錄中。 ASP.NET 不允許流覽此目錄中的檔案。 使用 Access 資料庫時,您必須將進程帳戶讀取和寫入權限授與App_Data目錄。

XmlDataSource 控制項

XmlDataSource 可用來將資料系結 XML 資料系結至資料繫結控制項。 您可以使用 DataFile 屬性系結至 XML 檔案,也可以使用 Data 屬性系結至 XML 字串。 XmlDataSource 會將 XML 屬性公開為可系結欄位。 如果您需要系結至未表示為屬性的值,您必須使用 XSL 轉換。 您也可以使用 XPath 運算式來篩選 XML 資料。

請考慮下列 XML 檔案:

<?xml version="1.0" encoding="utf-8" ?> <People> <Person FirstName="Jake" LastName="Stone"> <Address> <Street>345 Maple St.</Street> <City>Redmond</City> <Region>WA</Region> <ZipCode>01434</ZipCode> </Address> <Job> <Title>CEO</Title> <Description>Develops company strategies.</Description> </Job> </Person> <Person FirstName="Jacob" LastName="Ladder"> <Address> <Street>123 Elm St.</Street> <City>Seattle</City> <Region>WA</Region> <ZipCode>11223</ZipCode> </Address> <Job> <Title>Attorney</Title> <Description>Reviews legal issues.</Description> </Job> </Person> <Person FirstName="Angela" LastName="Hound"> <Address> <Street>34 Palm Avenue</Street> <City>Renton</City> <Region>WA</Region> <ZipCode>63910</ZipCode> </Address> <Job> <Title>IT Director</Title> <Description>In charge of corporate network.</Description> </Job> </Person> </People>

請注意,XmlDataSource 會使用人員/Person的 XPath 屬性,只篩選 Person <> 節點。 DropDownList 接著會使用 DataTextField 屬性將資料系結至 LastName 屬性。

雖然 XmlDataSource 控制項主要用於資料系結至唯讀 XML 資料,但可以編輯 XML 資料檔案。 請注意,在這種情況下,XML 檔案中資訊的自動插入、更新和刪除不會自動發生,就像其他資料來源控制項一樣。 相反地,您必須撰寫程式碼,以使用 XmlDataSource 控制項的下列方法來手動編輯資料。

GetXmlDocument

擷取 XmlDocument 物件,其中包含 XmlDataSource 所擷取的 XML 程式碼。

儲存

將記憶體內部 XmlDocument 儲存回資料來源。

請務必瞭解,只有在符合下列兩個條件時,Save 方法才能運作:

  1. XmlDataSource 使用 DataFile 屬性系結至 XML 檔案,而不是 Data 屬性以系結至記憶體內部 XML 資料。
  2. 未透過 Transform 或 TransformFile 屬性指定任何轉換。

另請注意,當多個使用者同時呼叫 Save 方法時,可能會產生非預期的結果。

ObjectDataSource 控制項

我們目前涵蓋的資料來源控制項是兩層式應用程式的絕佳選擇,其中資料來源控制項會直接與資料存放區通訊。 不過,許多真實世界的應用程式是多層式應用程式,其中資料來源控制可能需要與商務物件通訊,進而與資料層通訊。 在這些情況下,ObjectDataSource 會妥善填滿帳單。 ObjectDataSource 可與來源物件搭配運作。 如果物件具有實例 (方法,而不是在 Visual) Basic 中共用的靜態方法,則 ObjectDataSource 控制項會建立來源物件的實例、呼叫指定的方法,以及處置物件實例的所有物件實例。 因此,您的物件必須是無狀態的。 也就是說,您的物件應該在單一要求的範圍內取得和釋放所有必要的資源。 您可以藉由處理 ObjectDataSource 控制項的 ObjectCreating 事件來控制來源物件的建立方式。 您可以建立來源物件的實例,然後將 ObjectDataSourceEventArgs 類別的 ObjectInstance 屬性設定為該實例。 ObjectDataSource 控制項會使用在 ObjectCreating 事件中建立的實例,而不是自行建立實例。

如果 ObjectDataSource 控制項的來源物件公開公用靜態方法 (Visual Basic 中共用) 可以呼叫以擷取和修改資料,則 ObjectDataSource 控制項會直接呼叫這些方法。 如果 ObjectDataSource 控制項必須建立來源物件的實例,才能進行方法呼叫,則物件必須包含不採用任何參數的公用建構函式。 ObjectDataSource 控制項會在建立來源物件的新實例時呼叫這個建構函式。

如果來源物件不包含不含參數的公用建構函式,您可以建立 ObjectCreating 事件中 ObjectDataSource 控制項將使用之來源物件的實例。

指定物件方法

ObjectDataSource 控制項的來源物件可以包含用來選取、插入、更新或刪除資料的任何數目方法。 這些方法是由 ObjectDataSource 控制項根據方法的名稱呼叫,如使用 ObjectDataSource 控制項的 SelectMethod、InsertMethod、UpdateMethod 或 DeleteMethod 屬性所識別。 來源物件也可以包含選擇性的 SelectCount 方法,這個方法是由 ObjectDataSource 控制項使用 SelectCountMethod 屬性來識別,這個方法會傳回資料來源中物件的總數計數。 呼叫 Select 方法之後,ObjectDataSource 控制項會呼叫 SelectCount 方法,以擷取資料來源的記錄總數,以供分頁使用。

使用資料來源控制項的實驗室

練習 1 - 使用 SqlDataSource 控制項顯示資料

下列練習會使用 SqlDataSource 控制項來連線到 Northwind 資料庫。 假設您可以在 SQL Server 2000 實例上存取 Northwind 資料庫。

  1. 建立新的 ASP.NET 網站。

  2. 新增web.config檔案。

    1. 以滑鼠右鍵按一下方案總管中的專案,然後按一下 [新增專案]。
    2. 從範本清單中選擇 [Web 組態檔],然後按一下 [新增]。
  3. <編輯 connectionStrings 區 > 段,如下所示:

    <asp:SqlDataSource ID="SqlDataSource1" runat="server"
        ConnectionString="<%$ConnectionStrings:Northwind%>"
        SelectCommand="SELECT * FROM Products">
    </asp:SqlDataSource>
    
  4. 切換至 [程式碼] 檢視,並將 ConnectionString 屬性和 SelectCommand 屬性新增至 < asp:SqlDataSource > 控制項,如下所示:

    <asp:SqlDataSource ID="SqlDataSource1" runat="server"
        ConnectionString="<%$ConnectionStrings:Northwind%>"
        SelectCommand="SELECT * FROM Products">
    </asp:SqlDataSource>
    
  5. 從 [設計檢視] 中,新增 GridView 控制項。

  6. 從 [GridView 工作] 功能表中的 [選擇資料來源] 下拉式清單中,選擇 [SqlDataSource1]。

  7. 以滑鼠右鍵按一下 Default.aspx,然後從功能表中選擇 [在瀏覽器中檢視]。 當系統提示您儲存時,按一下 [是]。

  8. GridView 會顯示 Products 資料表中的資料。

練習 2 - 使用 SqlDataSource 控制項編輯資料

下列練習示範如何使用宣告式語法來系結 DropDownList 控制項,並可讓您編輯 DropDownList 控制項中顯示的資料。

  1. 在 [設計檢視] 中,從 Default.aspx 刪除 GridView 控制項。

    重要事項:將 SqlDataSource 控制項保留在頁面上。

  2. 將 DropDownList 控制項新增至 Default.aspx。

  3. 切換至 [來源] 檢視。

  4. 將 DataSourceId、DataTextField 和 DataValueField 屬性新增至 < asp:DropDownList > 控制項,如下所示:

    <asp:DropDownList ID="ddlProducts" runat="server"
         DataSourceId="SqlDataSource1" DataTextField="ProductName"
         DataValueField="ProductID">
    </asp:DropDownList>
    
  5. 儲存 Default.aspx 並在瀏覽器中檢視它。 請注意,DropDownList 包含 Northwind 資料庫中的所有產品。

  6. 關閉瀏覽器。

  7. 在 Default.aspx 的來源檢視中,于 DropDownList 控制項下方新增 TextBox 控制項。 將 TextBox 的 ID 屬性變更為 txtProductName。

  8. 在 TextBox 控制項下,新增按鈕控制項。 將 Button 的 ID 屬性變更為 btnUpdate,並將 Text 屬性變更為 [更新產品名稱]。

  9. 在 Default.aspx 的來源檢視中,將 UpdateCommand 屬性和兩個新的 UpdateParameters 新增至 SqlDataSource 標籤,如下所示:

    <asp:SqlDataSource ID="SqlDataSource1" runat="server"
        ConnectionString="<%$ConnectionStrings:Northwind%>"
        SelectCommand="SELECT * FROM Products"
        UpdateCommand="UPDATE Products SET ProductName=@ProductName WHERE ProductID=@ProductID">
          <UpdateParameters>
          <asp:ControlParameter Name="ProductName" 
            ControlID="txtProductName" PropertyName="Text" />
          <asp:ControlParameter Name="ProductID" 
            ControlID="ddlProducts" PropertyName="SelectedValue" />
    </asp:SqlDataSource>
    

    注意

    請注意,有兩個更新參數 (ProductName 和 ProductID) 在此程式碼中新增。 這些參數會對應至 txtProductName TextBox 的 Text 屬性,以及 ddlProducts DropDownList 的 SelectedValue 屬性。

  10. 切換至 [設計] 檢視,然後按兩下 [按鈕] 控制項以新增事件處理常式。

  11. 將下列程式碼新增至btnUpdate_Click程式碼:

    SqlDataSource1.Update();
    
  12. 以滑鼠右鍵按一下 Default.aspx,然後選擇在瀏覽器中檢視它。 出現提示以儲存所有變更時,按一下 [是]。

  13. ASP.NET 2.0 部分類別可在執行時間進行編譯。 不需要建置應用程式,才能看到程式碼變更生效。

  14. 從 DropDownList 選取產品。

  15. 在 TextBox 中輸入所選產品的新名稱,然後按一下 [更新] 按鈕。

  16. 產品名稱會在資料庫中更新。

使用 ObjectDataSource 控制項的練習 3

本練習將示範如何使用 ObjectDataSource 控制項和來源物件來與 Northwind 資料庫互動。

  1. 以滑鼠右鍵按一下 方案總管 中的專案,然後按一下 [新增專案]。

  2. 在範本清單中選取 [Web 表單]。 將名稱變更為 object.aspx,然後按一下 [新增]。

  3. 以滑鼠右鍵按一下 方案總管 中的專案,然後按一下 [新增專案]。

  4. 在範本清單中選取 [類別]。 將類別的名稱變更為 NorthwindData.cs,然後按一下 [新增]。

  5. 出現提示時,按一下 [是] 將 類別新增至 App_Code 資料夾。

  6. 將下列程式碼新增至 NorthwindData.cs 檔案:

    using System;
    using System.Data;
    using System.Configuration;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;
    using System.Data.SqlClient;
    public class NorthwindData {
        private string _connectionString;
        public NorthwindData() {
            Initialize();
        }
    
        private void Initialize() {
            if (ConfigurationManager.ConnectionStrings["Northwind"] == null ||
                ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString.Trim() == "") {
                    throw new Exception("A connection string named 'Northwind' with " +
                    "a valid connection string must exist in the <connectionStrings> " +
                    "configuration section for the application.");
            }
            _connectionString = ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString;
        }
    
        public DataTable GetAllEmployees(string sortColumns, int startRecord, int maxRecords) {
            VerifySortColumns(sortColumns);
            string sqlCmd = "SELECT EmployeeID, LastName, FirstName, Address, " +
                "City, Region, PostalCode FROM Employees ";
            if (sortColumns.Trim() == "")
                sqlCmd += "ORDER BY EmployeeID";
            else
                sqlCmd += "ORDER BY " + sortColumns;
    
            SqlConnection conn = new SqlConnection(_connectionString);
            SqlDataAdapter da = new SqlDataAdapter(sqlCmd, conn);
            DataSet ds = new DataSet();
            try {
                conn.Open();
                da.Fill(ds, startRecord, maxRecords, "Employees");
            } catch (SqlException e) {
                // Handle exception.
            } finally {
                conn.Close();
            }
            return ds.Tables["Employees"];
        }
    
        public int SelectCount() {
            SqlConnection conn = new SqlConnection(_connectionString);
            SqlCommand cmd = new SqlCommand("SELECT COUNT(*) FROM Employees", conn);
            int result = 0;
    
            try {
                conn.Open();
                result = (int)cmd.ExecuteScalar();
            } catch (SqlException e) {
                // Handle exception.
            } finally {
                conn.Close();
            }
            return result;
        }
    
        //////////
        // Verify that only valid columns are specified in the sort expression to
        // avoid a SQL Injection attack.
        private void VerifySortColumns(string sortColumns) {
            if (sortColumns.ToLowerInvariant().EndsWith(" desc"))
                sortColumns = sortColumns.Substring(0, sortColumns.Length - 5);
            string[] columnNames = sortColumns.Split(',');
            foreach (string columnName in columnNames) {
                switch (columnName.Trim().ToLowerInvariant()) {
                    case "employeeid":
                        break;
                    case "lastname":
                        break;
                    case "firstname":
                        break;
                    case "":
                        break;
                    default:
                        throw new ArgumentException("SortColumns contains an " +
                            "invalid column name.");
                        break;
                }
            }
        }
    
        // Select an employee.
        public DataTable GetEmployee(int EmployeeID) {
            SqlConnection conn = new SqlConnection(_connectionString);
            SqlDataAdapter da =
                new SqlDataAdapter("SELECT EmployeeID, LastName, FirstName, " +
                "Address, City, Region, PostalCode " +
                " FROM Employees WHERE EmployeeID = @EmployeeID", conn);
            da.SelectCommand.Parameters.Add("@EmployeeID", SqlDbType.Int).Value = EmployeeID;
            DataSet ds = new DataSet();
            try {
                conn.Open();
                da.Fill(ds, "Employees");
            } catch (SqlException e) {
                // Handle exception.
            } finally {
                conn.Close();
            }
    
            return ds.Tables["Employees"];
        }
    
        // Delete the Employee by ID.
        public int DeleteEmployee(int EmployeeID) {
             SqlConnection conn = new SqlConnection(_connectionString);
             SqlCommand cmd = new SqlCommand("DELETE FROM Employees WHERE " +
                 "EmployeeID = @EmployeeID", conn);
             cmd.Parameters.Add("@EmployeeID", SqlDbType.Int).Value = EmployeeID;
             int result = 0;
             try {
                 conn.Open();
                 result = cmd.ExecuteNonQuery();
             } catch (SqlException e) {
                 // Handle exception.
             } finally {
                 conn.Close();
             }
    
             return result;
         }
    
         // Update the Employee by original ID.
         public int UpdateEmployee(int EmployeeID, string LastName, string FirstName,
             string Address, string City, string Region,
             string PostalCode) {
             if (String.IsNullOrEmpty(FirstName))
                 throw new ArgumentException("FirstName cannot be null or an empty string.");
             if (String.IsNullOrEmpty(LastName))
                 throw new ArgumentException("LastName cannot be null or an empty string.");
             if (Address == null) { Address = String.Empty; }
             if (City == null) { City = String.Empty; }
             if (Region == null) { Region = String.Empty; }
             if (PostalCode == null) { PostalCode = String.Empty; }
    
             SqlConnection conn = new SqlConnection(_connectionString);
             SqlCommand cmd = new SqlCommand("UPDATE Employees " +
                 " SET FirstName=@FirstName, " +
                 "LastName=@LastName, " +
                 "Address=@Address, City=@City, " +
                 "Region=@Region, " +
                 "PostalCode=@PostalCode " +
                 "WHERE EmployeeID=@EmployeeID", conn);
             cmd.Parameters.Add("@FirstName", SqlDbType.VarChar, 10).Value = FirstName;
             cmd.Parameters.Add("@LastName", SqlDbType.VarChar, 20).Value = LastName;
             cmd.Parameters.Add("@Address", SqlDbType.VarChar, 60).Value = Address;
             cmd.Parameters.Add("@City", SqlDbType.VarChar, 15).Value = City;
             cmd.Parameters.Add("@Region", SqlDbType.VarChar, 15).Value = Region;
             cmd.Parameters.Add("@PostalCode", SqlDbType.VarChar, 10).Value = PostalCode;
             cmd.Parameters.Add("@EmployeeID", SqlDbType.Int).Value = EmployeeID;
    
             int result = 0;
             try {
                 conn.Open();
                 result = cmd.ExecuteNonQuery();
             } catch (SqlException e) {
                 // Handle exception.
             } finally {
                 conn.Close();
             }
    
             return result;
        }
    
        // Insert an Employee.
        public int InsertEmployee(string LastName, string FirstName,
            string Address, string City, string Region,
            string PostalCode) {
            if (String.IsNullOrEmpty(FirstName))
                throw new ArgumentException("FirstName cannot be null or an empty string.");
            if (String.IsNullOrEmpty(LastName))
                throw new ArgumentException("LastName cannot be null or an empty string.");
            if (Address == null) { Address = String.Empty; }
            if (City == null) { City = String.Empty; }
            if (Region == null) { Region = String.Empty; }
            if (PostalCode == null) { PostalCode = String.Empty; }
    
            SqlConnection conn = new SqlConnection(_connectionString);
            SqlCommand cmd = new SqlCommand("INSERT INTO Employees " +
                " (FirstName, LastName, Address, " +
                " City, Region, PostalCode) " +
                " Values(@FirstName, @LastName, " +
                "@Address, @City, @Region, @PostalCode); " +
                "SELECT @EmployeeID = SCOPE_IDENTITY()", conn);
    
            cmd.Parameters.Add("@FirstName", SqlDbType.VarChar, 10).Value = FirstName;
            cmd.Parameters.Add("@LastName", SqlDbType.VarChar, 20).Value = LastName;
            cmd.Parameters.Add("@Address", SqlDbType.VarChar, 60).Value = Address;
            cmd.Parameters.Add("@City", SqlDbType.VarChar, 15).Value = City;
            cmd.Parameters.Add("@Region", SqlDbType.VarChar, 15).Value = Region;
            cmd.Parameters.Add("@PostalCode", SqlDbType.VarChar, 10).Value = PostalCode;
            SqlParameter p = cmd.Parameters.Add("@EmployeeID", SqlDbType.Int);
                p.Direction = ParameterDirection.Output;
            int newEmployeeID = 0;
            try {
                conn.Open();
                cmd.ExecuteNonQuery();
                newEmployeeID = (int)p.Value;
            } catch (SqlException e) {
                // Handle exception.
            } finally {
                conn.Close();
            }
    
            return newEmployeeID;
        }
    
        //
        // Methods that support Optimistic Concurrency checks.
        //
        // Delete the Employee by ID.
        public int DeleteEmployee(int original_EmployeeID, string original_LastName,
            string original_FirstName, string original_Address,
            string original_City, string original_Region,
            string original_PostalCode) {
    
            if (String.IsNullOrEmpty(original_FirstName))
                throw new ArgumentException("FirstName cannot be null or an empty string.");
            if (String.IsNullOrEmpty(original_LastName))
                throw new ArgumentException("LastName cannot be null or an empty string.");
            if (original_Address == null) { original_Address = String.Empty; }
            if (original_City == null) { original_City = String.Empty; }
            if (original_Region == null) { original_Region = String.Empty; }
            if (original_PostalCode == null) { original_PostalCode = String.Empty; }
            string sqlCmd = "DELETE FROM Employees WHERE EmployeeID = " + @original_EmployeeID
    
            SqlConnection conn = new SqlConnection(_connectionString);
            SqlCommand cmd = new SqlCommand(sqlCmd, conn);
            cmd.Parameters.Add("@original_EmployeeID",
                SqlDbType.Int).Value = original_EmployeeID;
            cmd.Parameters.Add("@original_FirstName",
                SqlDbType.VarChar, 10).Value = original_FirstName;
            cmd.Parameters.Add("@original_LastName",
                SqlDbType.VarChar, 20).Value = original_LastName;
            cmd.Parameters.Add("@original_Address",
                SqlDbType.VarChar, 60).Value = original_Address;
            cmd.Parameters.Add("@original_City",
                SqlDbType.VarChar, 15).Value = original_City;
            cmd.Parameters.Add("@original_Region",
                SqlDbType.VarChar, 15).Value = original_Region;
            cmd.Parameters.Add("@original_PostalCode",
                SqlDbType.VarChar, 10).Value = original_PostalCode;
    
            int result = 0;
            try {
                conn.Open();
                result = cmd.ExecuteNonQuery();
            } catch (SqlException e) {
                // Handle exception.
            } finally {
                conn.Close();
            }
    
            return result;
        }
    
        // Update the Employee by original ID.
        public int UpdateEmployee(string LastName, string FirstName,
            string Address, string City, string Region,
            string PostalCode, int original_EmployeeID,
            string original_LastName, string original_FirstName,
            string original_Address, string original_City,
            string original_Region, string original_PostalCode) {
    
            if (String.IsNullOrEmpty(FirstName))
                throw new ArgumentException("FirstName cannot be null or an empty string.");
            if (String.IsNullOrEmpty(LastName))
                throw new ArgumentException("LastName cannot be null or an empty string.");
            if (Address == null) { Address = String.Empty; }
            if (City == null) { City = String.Empty; }
            if (Region == null) { Region = String.Empty; }
            if (PostalCode == null) { PostalCode = String.Empty; }
            if (original_Address == null) { original_Address = String.Empty; }
            if (original_City == null) { original_City = String.Empty; }
            if (original_Region == null) { original_Region = String.Empty; }
            if (original_PostalCode == null) { original_PostalCode = String.Empty; }
    
            string sqlCmd = "UPDATE Employees " +
                " SET FirstName = @FirstName, LastName = @LastName, " +
                " Address = @Address, City = @City, Region = @Region, " +
                " PostalCode = @PostalCode " +
                " WHERE EmployeeID = @original_EmployeeID";
    
            SqlConnection conn = new SqlConnection(_connectionString);
            SqlCommand cmd = new SqlCommand(sqlCmd, conn);
            cmd.Parameters.Add("@FirstName", SqlDbType.VarChar, 10).Value = FirstName;
            cmd.Parameters.Add("@LastName", SqlDbType.VarChar, 20).Value = LastName;
            cmd.Parameters.Add("@Address", SqlDbType.VarChar, 60).Value = Address;
            cmd.Parameters.Add("@City", SqlDbType.VarChar, 15).Value = City;
            cmd.Parameters.Add("@Region", SqlDbType.VarChar, 15).Value = Region;
            cmd.Parameters.Add("@PostalCode", SqlDbType.VarChar, 10).Value = PostalCode;
            cmd.Parameters.Add("@original_EmployeeID",
                SqlDbType.Int).Value = original_EmployeeID;
            cmd.Parameters.Add("@original_FirstName",
                SqlDbType.VarChar, 10).Value = original_FirstName;
            cmd.Parameters.Add("@original_LastName",
                SqlDbType.VarChar, 20).Value = original_LastName;
            cmd.Parameters.Add("@original_Address",
                SqlDbType.VarChar, 60).Value = original_Address;
            cmd.Parameters.Add("@original_City",
                SqlDbType.VarChar, 15).Value = original_City;
            cmd.Parameters.Add("@original_Region",
                SqlDbType.VarChar, 15).Value = original_Region;
            cmd.Parameters.Add("@original_PostalCode",
                SqlDbType.VarChar, 10).Value = original_PostalCode;
    
            int result = 0;
    
            try {
                conn.Open();
                result = cmd.ExecuteNonQuery();
            } catch (SqlException e) {
                // Handle exception.
            } finally {
                conn.Close();
            }
            return result;
        }
    }
    
  7. 將下列程式碼新增至 object.aspx 的來源檢視:

    <%@ Page language="C#" %>
    <script RunAt="server">
    void EmployeesDetailsView_ItemInserted(Object sender, DetailsViewInsertedEventArgs e) {
        EmployeesGridView.DataBind();
    }
    
    void EmployeesDetailsView_ItemUpdated(Object sender, DetailsViewUpdatedEventArgs e) {
        EmployeesGridView.DataBind();
    }
    
    void EmployeesDetailsView_ItemDeleted(Object sender, DetailsViewDeletedEventArgs e) {
        EmployeesGridView.DataBind();
    }
    void EmployeesGridView_OnSelectedIndexChanged(object sender, EventArgs e) {
        EmployeeDetailsObjectDataSource.SelectParameters["EmployeeID"].DefaultValue =
            EmployeesGridView.SelectedDataKey.Value.ToString();
        EmployeesDetailsView.DataBind();
    }
    void EmployeeDetailsObjectDataSource_OnInserted(object sender,
        ObjectDataSourceStatusEventArgs e) {
    
        EmployeeDetailsObjectDataSource.SelectParameters["EmployeeID"].DefaultValue =
            e.ReturnValue.ToString();
        EmployeesDetailsView.DataBind();
    }
    void EmployeeDetailsObjectDataSource_OnUpdated(object sender,
        ObjectDataSourceStatusEventArgs e) {
    
        if ((int)e.ReturnValue == 0)
            Msg.Text = "Employee was not updated. Please try again.";
    }
    void EmployeeDetailsObjectDataSource_OnDeleted(object sender,
        ObjectDataSourceStatusEventArgs e) {
    
        if ((int)e.ReturnValue == 0)
            Msg.Text = "Employee was not deleted. Please try again.";
    }
    void Page_Load() {
        Msg.Text = "";
    }
    </script>
    <html>
      <body>
        <form id="Form1" runat="server">
          <h3>ObjectDataSource Example</h3>
          <asp:Label id="Msg" runat="server" ForeColor="Red" />
          <asp:ObjectDataSource
              ID="EmployeesObjectDataSource"
              runat="server"
              TypeName="NorthwindData"
              SortParameterName="SortColumns"
              EnablePaging="true"
              SelectCountMethod="SelectCount"
              StartRowIndexParameterName="StartRecord"
              MaximumRowsParameterName="MaxRecords"
              SelectMethod="GetAllEmployees" >
          </asp:ObjectDataSource>
          <asp:ObjectDataSource
              ID="EmployeeDetailsObjectDataSource"
              runat="server"
              TypeName="NorthwindData"
              ConflictDetection="CompareAllValues"
              OldValuesParameterFormatString="{0}"
              SelectMethod="GetEmployee"
              InsertMethod="InsertEmployee"
              UpdateMethod="UpdateEmployee"
              DeleteMethod="DeleteEmployee"
              OnInserted="EmployeeDetailsObjectDataSource_OnInserted"
              OnUpdated="EmployeeDetailsObjectDataSource_OnUpdated"
              OnDeleted="EmployeeDetailsObjectDataSource_OnDeleted">
              <SelectParameters>
                  <asp:Parameter Name="EmployeeID" Type="Int32" />
              </SelectParameters>
          </asp:ObjectDataSource>
          <table cellspacing="10">
            <tr>
              <td valign="top">
                <asp:GridView ID="EmployeesGridView"
                    DataSourceID="EmployeesObjectDataSource"
                    AutoGenerateColumns="false"
                    AllowSorting="true"
                    AllowPaging="true"
                    PageSize="5"
                    DataKeyNames="EmployeeID"
                    OnSelectedIndexChanged="EmployeesGridView_OnSelectedIndexChanged"
                    RunAt="server">
                    <HeaderStyle backcolor="lightblue" forecolor="black"/>
                    <Columns>
                    <asp:ButtonField Text="Details..."
                    HeaderText="Show Details"
                    CommandName="Select"/>
    
                    <asp:BoundField DataField="EmployeeID" HeaderText="Employee ID"
                    SortExpression="EmployeeID" />
                    <asp:BoundField DataField="FirstName" HeaderText="First Name"
                    SortExpression="FirstName" />
                    <asp:BoundField DataField="LastName" HeaderText="Last Name"
                    SortExpression="LastName, FirstName" />
                    </Columns>
                </asp:GridView>
              </td>
              <td valign="top">
                <asp:DetailsView ID="EmployeesDetailsView"
                    DataSourceID="EmployeeDetailsObjectDataSource"
                    AutoGenerateRows="false"
                    EmptyDataText="No records."
                    DataKeyNames="EmployeeID"
                    Gridlines="Both"
                    AutoGenerateInsertButton="true"
                    AutoGenerateEditButton="true"
                    AutoGenerateDeleteButton="true"
                    OnItemInserted="EmployeesDetailsView_ItemInserted"
                    OnItemUpdated="EmployeesDetailsView_ItemUpdated"
                    OnItemDeleted="EmployeesDetailsView_ItemDeleted"
                    RunAt="server">
                    <HeaderStyle backcolor="Navy" forecolor="White"/>
                    <RowStyle backcolor="White"/>
                    <AlternatingRowStyle backcolor="LightGray"/>
                    <EditRowStyle backcolor="LightCyan"/>
                    <Fields>
                        <asp:BoundField DataField="EmployeeID" HeaderText="Employee ID"
                            InsertVisible="False" ReadOnly="true"/>
                        <asp:BoundField DataField="FirstName" HeaderText="First Name"/>
                        <asp:BoundField DataField="LastName" HeaderText="Last Name"/>
                        <asp:BoundField DataField="Address" HeaderText="Address"/>
                        <asp:BoundField DataField="City" HeaderText="City"/>
                        <asp:BoundField DataField="Region" HeaderText="Region"/>
                        <asp:BoundField DataField="PostalCode" HeaderText="Postal Code"/>
                    </Fields>
                  </asp:DetailsView>
                </td>
              </tr>
            </table>
          </form>
        </body>
      </html>
    
  8. 儲存所有檔案並流覽 object.aspx。

  9. 藉由檢視詳細資料、編輯員工、新增員工和刪除員工,與介面互動。