擷取識別或 Autonumber 值 (ADO.NET)

更新: November 2007

關聯式資料庫中的主索引鍵是永遠包含唯一值的資料行或資料行組合。瞭解主索引鍵值可讓您找出包含此值的資料列。關聯式 Database Engine (例如 SQL Server、Oracle 和 Microsoft Access/Jet) 支援建立可指定為主索引鍵的自動遞增資料行。上述的值會在資料列加入至資料表時由伺服器產生。在 SQL Server 中,您可以設定資料行的識別屬性。在 Oracle 中,您可以建立序列 (Sequence)。在 Microsoft Access 中,您可以建立 AutoNumber 資料行。

您也可以將 AutoIncrement 屬性設定為 true,讓 DataColumn 用來產生自動遞增的值。不過,如果多個用戶端應用程式都獨立產生自動遞增的值,您可能會造成 DataTable 的個別執行個體 (Instance) 具有重複的值。讓伺服器產生自動遞增的值會透過允許每位使用者針對每個插入的資料列擷取產生的值,排除可能發生的衝突。

在呼叫 DataAdapter 的 Update 方法期間,資料庫可以傳送資料回 ADO.NET 應用程式當做輸出參數,或當做與 INSERT 陳述式在相同批次中執行之 SELECT 陳述式結果集的第一個傳回資料錄。ADO.NET 可以擷取這些值並在正在更新的 DataRow 中更新對應的資料行。

某些 Database Engine (例如 Microsoft Access Jet Database Engine) 不支援輸出參數而且無法在單一批次中處理多個陳述式。使用 Jet Database Engine 時,您可以透過在 DataAdapter 之 RowUpdated 事件的事件處理常式中執行個別的 SELECT 命令,擷取針對插入資料列所產生的新 AutoNumber 值。

注意事項:

使用自動遞增值的替代方式是使用 GuidNewGuid 方法,在用戶端電腦上產生插入每個新資料列時可複製到伺服器的 GUID (全域唯一識別項)。NewGuid 方法會產生 16 個位元組的二進位值,而此值是使用盡可能確保沒有任何值會重複的演算法所建立的。在 SQL Server 資料庫中,GUID 會儲存在 SQL Server 可以使用 Transact-SQL NEWID() 函式來自動產生的 uniqueidentifier 資料行中。使用 GUID 當做主索引鍵可能會對效能造成不良影響。SQL Server 2005 引進了 NEWSEQUENTIALID() 函式的支援,而此函式會產生循序 GUID (雖然不保證是全域唯一的,但是可更有效地進行索引)。

擷取 SQL Server Identity 資料行值

使用 Microsoft SQL Server 時,您可以建立含有輸出參數的預存程序,以便傳回插入資料列的識別值。下表將描述 SQL Server 中三個可用來擷取識別資料行值的 Transact-SQL 函式。

函式

描述

SCOPE_IDENTITY

傳回目前執行範圍內的最後一個識別值。建議您針對大部分案例使用 SCOPE_IDENTITY。

@@IDENTITY

包含目前工作階段 (Session) 中於任何資料表內產生的最後一個識別值。@@IDENTITY 可能會受到觸發程序 (Trigger) 的影響,而且可能無法傳回您所預期的識別值。

IDENT_CURRENT

傳回在任何工作階段和任何範圍中針對特定資料表所產生的最後一個識別值。

下列預存程序將示範如何將資料列插入 Categories 資料表,以及使用輸出參數來傳回 Transact-SQL SCOPE_IDENTITY() 函式所產生的新識別值。

CREATE PROCEDURE dbo.InsertCategory
  @CategoryName nvarchar(15),
  @Identity int OUT
AS
INSERT INTO Categories (CategoryName) VALUES(@CategoryName)
SET @Identity = SCOPE_IDENTITY()

然後,您可以將此預存程序指定為 SqlDataAdapter 物件之 InsertCommand 的來源。InsertCommandCommandType 屬性必須設定為 StoredProcedure。識別輸出的擷取方式是建立 ParameterDirectionOutputSqlParameter。如果您將插入命令的 UpdatedRowSource 屬性設定為 UpdateRowSource.OutputParameters 或 UpdateRowSource.Both,當 InsertCommand 經過處理之後,系統就會傳回自動遞增的識別值並將它放置於目前資料列的 CategoryID 資料行中。

如果您的插入命令執行了同時包含 INSERT 陳述式和 SELECT 陳述式而且傳回新識別值的批次,您就可以將插入命令的 UpdatedRowSource 屬性設定為 UpdateRowSource.FirstReturnedRecord,藉以擷取新的值。

Private Sub RetrieveIdentity(ByVal connectionString As String)
    Using connection As SqlConnection = New SqlConnection( _
       connectionString)

        ' Create a SqlDataAdapter based on a SELECT query.
        Dim adapter As SqlDataAdapter = New SqlDataAdapter( _
           "SELECT CategoryID, CategoryName FROM dbo.Categories", _
           connection)

        ' Create the SqlCommand to execute the stored procedure. 
        adapter.InsertCommand = New SqlCommand("dbo.InsertCategory", _
           connection)
        adapter.InsertCommand.CommandType = CommandType.StoredProcedure

        ' Add the parameter for the CategoryName. Specifying the
        ' ParameterDirection for an input parameter is not required.
        adapter.InsertCommand.Parameters.Add( _
          "@CategoryName", SqlDbType.NVarChar, 15, "CategoryName")

        ' Add the SqlParameter to retrieve the new identity value.
        ' Specify the ParameterDirection as Output.
        Dim parameter As SqlParameter = _
           adapter.InsertCommand.Parameters.Add( _
          "@Identity", SqlDbType.Int, 0, "CategoryID")
        parameter.Direction = ParameterDirection.Output

        ' Create a DataTable and fill it.
        Dim categories As DataTable = New DataTable
        adapter.Fill(categories)

        ' Add a new row.
        Dim newRow As DataRow = categories.NewRow()
        newRow("CategoryName") = "New Category"
        categories.Rows.Add(newRow)

        ' Update the database.
        adapter.Update(categories)

        Console.WriteLine("List All Rows:")
        Dim row As DataRow
        For Each row In categories.Rows
            Console.WriteLine("{0}: {1}", row(0), row(1))
        Next
    End Using
End Sub
private static void RetrieveIdentity(string connectionString)
{
    using (SqlConnection connection =
               new SqlConnection(connectionString))
    {
        // Create a SqlDataAdapter based on a SELECT query.
        SqlDataAdapter adapter =
            new SqlDataAdapter(
            "SELECT CategoryID, CategoryName FROM dbo.Categories",
            connection);

        //Create the SqlCommand to execute the stored procedure.
        adapter.InsertCommand = new SqlCommand("dbo.InsertCategory", 
            connection);
        adapter.InsertCommand.CommandType = CommandType.StoredProcedure;

        // Add the parameter for the CategoryName. Specifying the
        // ParameterDirection for an input parameter is not required.
        adapter.InsertCommand.Parameters.Add(
           new SqlParameter("@CategoryName", SqlDbType.NVarChar, 15,
           "CategoryName"));

        // Add the SqlParameter to retrieve the new identity value.
        // Specify the ParameterDirection as Output.
        SqlParameter parameter = 
            adapter.InsertCommand.Parameters.Add(
            "@Identity", SqlDbType.Int, 0, "CategoryID");
        parameter.Direction = ParameterDirection.Output;

        // Create a DataTable and fill it.
        DataTable categories = new DataTable();
        adapter.Fill(categories);

        // Add a new row. 
        DataRow newRow = categories.NewRow();
        newRow["CategoryName"] = "New Category";
        categories.Rows.Add(newRow);

        adapter.Update(categories);

        Console.WriteLine("List All Rows:");
        foreach (DataRow row in categories.Rows)
        {
            {
                Console.WriteLine("{0}: {1}", row[0], row[1]);
            }
        }
    }
}

合併新的識別值

常見的案例是呼叫 DataTable 的 GetChanges 方法來建立僅包含變更資料列的複本,以及在呼叫 DataAdapter 的 Update 方法時使用新的複本。當您必須將變更的資料列封送處理至執行更新的個別元件時,這種做法特別有用。更新之後,該複本可以包含新的識別值,而這些值之後必須合併回原始的 DataTable 中。新的識別值可能會與 DataTable 中的原始值不同。若要完成合併,您必須保留複本中 AutoIncrement 資料行的原始值,才能找出並更新原始 DataTable 中的現有資料列,而非附加包含新識別值的新資料列。不過,根據預設,這些原始值在呼叫 DataAdapter 的 Update 方法之後都會遺失,因為系統會針對每個更新的 DataRow 隱含地呼叫 AcceptChanges。

目前有兩種方式可以在 DataAdapter 更新期間保留 DataRow 中 DataColumn 的原始值。

  • 第一種保留原始值的方法是將 DataAdapter 的 AcceptChangesDuringUpdate 屬性設定為 false。這樣做會影響正在更新之 DataTable 中的每個 DataRow。如需詳細資訊和程式碼範例,請參閱 AcceptChangesDuringUpdate

  • 第二種方法是在 DataAdapter 的 RowUpdated 事件處理常式中撰寫程式碼,以便將 Status 設定為 SkipCurrentRow。如此一來,雖然系統會更新 DataRow,卻會保留每個 DataColumn 的原始值。這種方法可讓您保留某些資料列的原始值,而不保留其他資料列的原始值。例如,您的程式碼可以先檢查 StatementType 並僅針對 StatementType 為 Insert 的資料列將 Status 設定為 SkipCurrentRow,藉以保留已加入資料列的原始值,而不保留已編輯或刪除資料列的原始值。

當您使用上述任何一種方法在 DataAdapter 更新期間保留 DataRow 中的原始值時,ADO.NET 會執行一系列動作,將 DataRow 的目前值設定為輸出參數或結果集之第一個傳回資料列所傳回的新值,同時仍然保留每個 DataColumn 中的原始值。首先,系統會呼叫 DataRow 的 AcceptChanges 方法來保留目前的值當做原始值,然後指派新的值。進行這些動作之後,已將 RowState 屬性設定為 Added 的 DataRows 會將其 RowState 屬性設定為 Modified (可能無法預期)。

命令結果套用至正在更新之每個 DataRow 的方式是由每個 DbCommandUpdatedRowSource 屬性所決定。這個屬性會設定為 UpdateRowSource 列舉型別 (Enumeration) 中的值。

下表將描述 UpdateRowSource 列舉值如何影響已更新資料列的 RowState 屬性。

成員名稱

描述

Both

系統會呼叫 AcceptChanges,而且輸出參數值和 (或) 任何傳回之結果集中第一個資料列的值都會放置於正在更新的 DataRow 中。如果沒有任何要套用的值,RowState 將成為 Unchanged

FirstReturnedRecord

如果傳回了一個資料列,系統就會呼叫 AcceptChanges,而且該資料列會對應至 DataTable 中的已變更資料列,並將 RowState 設定為 Modified。如果沒有傳回任何資料列,系統就不會呼叫 AcceptChanges 而且 RowState 會維持 Added。

None

系統會忽略任何傳回的參數或資料列。系統不會呼叫 AcceptChanges 而且 RowState 會維持 Added。

OutputParameters

系統會呼叫 AcceptChanges,而且任何輸出參數都會對應至 DataTable 中的已變更資料列,並將 RowState 設定為 Modified。如果沒有任何輸出參數,RowState 將成為 Unchanged。

範例

這則範例會示範如何從 DataTable 中擷取已變更的資料列,以及使用 SqlDataAdapter 來更新資料來源並擷取新的識別資料行值。InsertCommand 會執行兩個 Transact-SQL 陳述式:第一個陳述式是 INSERT 陳述式,而第二個陳述式是使用 SCOPE_IDENTITY 函式來擷取識別值的 SELECT 陳述式。

INSERT INTO dbo.Shippers (CompanyName) 
VALUES (@CompanyName);
SELECT ShipperID, CompanyName FROM dbo.Shippers 
WHERE ShipperID = SCOPE_IDENTITY();

插入命令的 UpdatedRowSource 屬性會設定為 UpdateRowSource.FirstReturnedRow 而 DataAdapter 的 MissingSchemaAction 屬性會設定為 MissingSchemaAction.AddWithKey。此時,DataTable 已填入內容而且程式碼會將新的資料列加入至 DataTable。然後,系統會將已變更的資料列擷取至新的 DataTable 中,然後再傳遞給更新伺服器的 DataAdapter。

Private Sub MergeIdentityColumns(ByVal connectionString As String)

    Using connection As SqlConnection = New SqlConnection( _
       connectionString)

        ' Create the DataAdapter
        Dim adapter As SqlDataAdapter = New SqlDataAdapter( _
          "SELECT ShipperID, CompanyName FROM dbo.Shippers", connection)

        ' Add the InsertCommand to retrieve new identity value.
        adapter.InsertCommand = New SqlCommand( _
            "INSERT INTO dbo.Shippers (CompanyName) " & _
            "VALUES (@CompanyName); " & _
            "SELECT ShipperID, CompanyName FROM dbo.Shippers " & _
            "WHERE ShipperID = SCOPE_IDENTITY();", _
            connection)

        ' Add the parameter for the inserted value.
        adapter.InsertCommand.Parameters.Add( _
           New SqlParameter("@CompanyName", SqlDbType.NVarChar, 40, _
           "CompanyName"))
        adapter.InsertCommand.UpdatedRowSource = UpdateRowSource.Both

        ' MissingSchemaAction adds any missing schema to 
        ' the DataTable, including identity columns
        adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey

        ' Fill the DataTable.
        Dim shipper As New DataTable
        adapter.Fill(shipper)

        ' Add a new shipper. 
        Dim newRow As DataRow = shipper.NewRow()
        newRow("CompanyName") = "New Shipper"
        shipper.Rows.Add(newRow)

        ' Add changed rows to a new DataTable. This
        ' DataTable will be used by the DataAdapter.
        Dim dataChanges As DataTable = shipper.GetChanges()

        ' Add the event handler. 
        AddHandler adapter.RowUpdated, New _
           SqlRowUpdatedEventHandler(AddressOf OnRowUpdated)

        ' Update the datasource with the modified records.
        adapter.Update(dataChanges)

        ' Merge the two DataTables.
        shipper.Merge(dataChanges)

        ' Commit the changes.
        shipper.AcceptChanges()

        Console.WriteLine("Rows after merge.")
        Dim row As DataRow
        For Each row In shipper.Rows
            Console.WriteLine("{0}: {1}", row(0), row(1))
        Next
    End Using
End Sub
private static void MergeIdentityColumns(string connectionString)
{
    using (SqlConnection connection =
               new SqlConnection(connectionString))
    {
        // Create the DataAdapter
        SqlDataAdapter adapter =
            new SqlDataAdapter(
            "SELECT ShipperID, CompanyName FROM dbo.Shippers",
            connection);

        //Add the InsertCommand to retrieve new identity value.
        adapter.InsertCommand = new SqlCommand(
            "INSERT INTO dbo.Shippers (CompanyName) " +
            "VALUES (@CompanyName); " +
            "SELECT ShipperID, CompanyName FROM dbo.Shippers " +
            "WHERE ShipperID = SCOPE_IDENTITY();", connection);

        // Add the parameter for the inserted value.
        adapter.InsertCommand.Parameters.Add(
           new SqlParameter("@CompanyName", SqlDbType.NVarChar, 40,
           "CompanyName"));
        adapter.InsertCommand.UpdatedRowSource = UpdateRowSource.Both;

        // MissingSchemaAction adds any missing schema to 
        // the DataTable, including identity columns
        adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey;

        // Fill the DataTable.
        DataTable shipper = new DataTable();
        adapter.Fill(shipper);

        // Add a new shipper. 
        DataRow newRow = shipper.NewRow();
        newRow["CompanyName"] = "New Shipper";
        shipper.Rows.Add(newRow);

        // Add changed rows to a new DataTable. This
        // DataTable will be used by the DataAdapter.
        DataTable dataChanges = shipper.GetChanges();

        // Add the event handler. 
        adapter.RowUpdated +=
            new SqlRowUpdatedEventHandler(OnRowUpdated);

        adapter.Update(dataChanges);
        connection.Close();

        // Merge the updates.
        shipper.Merge(dataChanges);

        // Commit the changes.
        shipper.AcceptChanges();

        Console.WriteLine("Rows after merge.");
        foreach (DataRow row in shipper.Rows)
        {
            {
                Console.WriteLine("{0}: {1}", row[0], row[1]);
            }
        }
    }
}

OnRowUpdated 事件處理常式會檢查 SqlRowUpdatedEventArgsStatementType 來判斷資料列是否為插入項目。如果是的話,Status 屬性就會設定為 SkipCurrentRow。如此一來,雖然資料列會更新,卻會保留資料列中的原始值。在此程序的主要本文中,系統會呼叫 Merge 方法,將新的識別值合併至原始的 DataTable 中,最後再呼叫 AcceptChanges。

Private Sub OnRowUpdated( _
    ByVal sender As Object, ByVal e As SqlRowUpdatedEventArgs)
    ' If this is an insert, then skip this row.
    If e.StatementType = StatementType.Insert Then
        e.Status = UpdateStatus.SkipCurrentRow
    End If
End Sub
protected static void OnRowUpdated(
    object sender, SqlRowUpdatedEventArgs e)
{
    // If this is an insert, then skip this row.
    if (e.StatementType == StatementType.Insert)
    {
        e.Status = UpdateStatus.SkipCurrentRow;
    }
}

擷取 Microsoft Access Autonumber 值

本節包含一則說明如何從 Jet 4.0 資料庫中擷取 Autonumber 值的範例。Jet Database Engine 不支援在單一批次中執行多個陳述式或使用輸出參數,因此您無法使用其中的任何技巧來傳回指派給已插入資料列的新 Autonumber 值。不過,您可以將程式碼加入至 RowUpdated 事件處理常式,以便執行個別的 SELECT @@IDENTITY 陳述式來擷取新 Autonumber 值。

範例

這則範例會在呼叫 OleDbDataAdapter 來填入 DataTable 之前,使用正確的結構描述來設定 DataTable,而非使用 MissingSchemaAction.AddWithKey 來加入結構描述資訊。在此情況中,透過將 AutoIncrement 設定為 true、將 AutoIncrementSeed 設定為 0 以及將 AutoIncrementStep 設定為 -1,讓 CategoryID 資料行設定為遞減指派給每個已插入資料列的值 (從零開始)。接著,程式碼會加入兩個新的資料列,然後使用 GetChanges,將已變更的資料列加入至傳遞給 Update 方法的新 DataTable。

Shared connection As OleDbConnection = Nothing

Private Shared Sub MergeIdentityColumns(ByVal connection As OleDbConnection)
    Using connection

        ' Create a DataAdapter based on a SELECT query.
        Dim adapter As OleDbDataAdapter = New OleDbDataAdapter( _
          "SELECT CategoryID, CategoryName FROM Categories", _
          connection)

        ' Create the INSERT command for the new category.
        adapter.InsertCommand = New OleDbCommand( _
          "INSERT INTO Categories (CategoryName) Values(?)", connection)
        adapter.InsertCommand.CommandType = CommandType.Text

        ' Add the parameter for the CategoryName.
        adapter.InsertCommand.Parameters.Add( _
          "@CategoryName", OleDbType.VarWChar, 15, "CategoryName")
        adapter.InsertCommand.UpdatedRowSource = UpdateRowSource.Both

        ' Create a DataTable.
        Dim categories As DataTable = New DataTable

        ' Create the CategoryID column and set its auto
        ' incrementing properties to decrement from zero.
        Dim column As New DataColumn()
        column.DataType = System.Type.GetType("System.Int32")
        column.ColumnName = "CategoryID"
        column.AutoIncrement = True
        column.AutoIncrementSeed = 0
        column.AutoIncrementStep = -1
        categories.Columns.Add(column)

        ' Create the CategoryName column.
        column = New DataColumn()
        column.DataType = System.Type.GetType("System.String")
        column.ColumnName = "CategoryName"
        categories.Columns.Add(column)

        ' Set the primary key on CategoryID.
        Dim pKey(1) As DataColumn
        pKey(0) = categories.Columns("CategoryID")
        categories.PrimaryKey = pKey

        ' Fetch the data and fill the DataTable.
        adapter.Fill(categories)

        ' Add a new row.
        Dim newRow As DataRow = categories.NewRow()
        newRow("CategoryName") = "New Category"
        categories.Rows.Add(newRow)

        ' Add another new row.
        Dim newRow2 As DataRow = categories.NewRow()
        newRow2("CategoryName") = "Another New Category"
        categories.Rows.Add(newRow2)

        ' Add changed rows to a new DataTable that will be
        ' used to post the inserts to the database.
        Dim dataChanges As DataTable = categories.GetChanges()

        ' Include an event to fill in the Autonumber value.
        AddHandler adapter.RowUpdated, _
          New OleDbRowUpdatedEventHandler(AddressOf OnRowUpdated)

        ' Update the database, inserting the new rows.
        adapter.Update(dataChanges)

        Console.WriteLine("Rows before merge:")
        Dim row1 As DataRow
        For Each row1 In categories.Rows
            Console.WriteLine("  {0}: {1}", row1(0), row1(1))
        Next

        ' Merge the two DataTables.
        categories.Merge(dataChanges)

        ' Commit the changes.
        categories.AcceptChanges()

        Console.WriteLine("Rows after merge:")
        Dim row As DataRow
        For Each row In categories.Rows
            Console.WriteLine("  {0}: {1}", row(0), row(1))
        Next
    End Using
End Sub
private static OleDbConnection connection = null;

private static void MergeIdentityColumns(OleDbConnection connection)
{
    using (connection)
    {
        // Create a DataAdapter based on a SELECT query.
        OleDbDataAdapter adapter = new OleDbDataAdapter(
         "SELECT CategoryID, CategoryName FROM Categories",
         connection);

        // Create the INSERT command for the new category.
        adapter.InsertCommand = new OleDbCommand(
          "INSERT INTO Categories (CategoryName) Values(?)", connection);
        adapter.InsertCommand.CommandType = CommandType.Text;

        // Add the parameter for the CategoryName.
        adapter.InsertCommand.Parameters.Add(
          "@CategoryName", OleDbType.VarWChar, 15, "CategoryName");
        adapter.InsertCommand.UpdatedRowSource = UpdateRowSource.Both;

        // Create a DataTable
        DataTable categories = new DataTable();

        // Create the CategoryID column and set its auto 
        // incrementing properties to decrement from zero. 
        DataColumn column = new DataColumn();
        column.DataType = System.Type.GetType("System.Int32");
        column.ColumnName = "CategoryID";
        column.AutoIncrement = true;
        column.AutoIncrementSeed = 0;
        column.AutoIncrementStep = -1;
        categories.Columns.Add(column);

        // Create the CategoryName column.
        column = new DataColumn();
        column.DataType = System.Type.GetType("System.String");
        column.ColumnName = "CategoryName";
        categories.Columns.Add(column);

        // Set the primary key on CategoryID.
        DataColumn[] pKey = new DataColumn[1];
        pKey[0] = categories.Columns["CategoryID"];
        categories.PrimaryKey = pKey;

        // Fetch the data and fill the DataTable
        adapter.Fill(categories);

        // Add a new row.
        DataRow newRow = categories.NewRow();
        newRow["CategoryName"] = "New Category";
        categories.Rows.Add(newRow);

        // Add another new row.
        DataRow newRow2 = categories.NewRow();
        newRow2["CategoryName"] = "Another New Category";
        categories.Rows.Add(newRow2);

        // Add changed rows to a new DataTable that will be
        // used to post the inserts to the database.
        DataTable dataChanges = categories.GetChanges();

        // Include an event to fill in the Autonumber value.
        adapter.RowUpdated +=
            new OleDbRowUpdatedEventHandler(OnRowUpdated);

        // Update the database, inserting the new rows. 
        adapter.Update(dataChanges);

        Console.WriteLine("Rows before merge:");
        foreach (DataRow row in categories.Rows)
        {
            {
                Console.WriteLine("  {0}: {1}", row[0], row[1]);
            }
        }

        // Merge the two DataTables.
        categories.Merge(dataChanges);

        // Commit the changes.
        categories.AcceptChanges();

        Console.WriteLine("Rows after merge:");
        foreach (DataRow row in categories.Rows)
        {
            {
                Console.WriteLine("  {0}: {1}", row[0], row[1]);
            }
        }
    }
}

RowUpdated 事件處理常式與 OleDbDataAdapter 的 Update 陳述式都會使用相同的已開啟 OleDbConnection。它會檢查 OleDbRowUpdatedEventArgs 的 StatementType 是否有插入的資料列。系統會針對每個插入的資料列建立新的 OleDbCommand,以便在連接上執行 SELECT @@IDENTITY 陳述式,並傳回新的 Autonumber 值 (放置於 DataRow 的 CategoryID 資料行中)。然後,Status 屬性會設定為 UpdateStatus.SkipCurrentRow,以便抑制 AcceptChanges 的隱藏呼叫。在此程序的主要本文中,系統會呼叫 Merge 方法來合併兩個 DataTable 物件,最後再呼叫 AcceptChanges。

Private Shared Sub OnRowUpdated( _
    ByVal sender As Object, ByVal e As OleDbRowUpdatedEventArgs)
    ' Conditionally execute this code block on inserts only.
    If e.StatementType = StatementType.Insert Then
        ' Retrieve the Autonumber and store it in the CategoryID column.
        Dim cmdNewID As New OleDbCommand("SELECT @@IDENTITY", _
           connection)
        e.Row("CategoryID") = CInt(cmdNewID.ExecuteScalar)
        e.Status = UpdateStatus.SkipCurrentRow
    End If
End Sub
private static void OnRowUpdated(
  object sender, OleDbRowUpdatedEventArgs e)
{
    // Conditionally execute this code block on inserts only.
    if (e.StatementType == StatementType.Insert)
    {
        OleDbCommand cmdNewID = new OleDbCommand("SELECT @@IDENTITY",
            connection);
        // Retrieve the Autonumber and store it in the CategoryID column.
        e.Row["CategoryID"] = (int)cmdNewID.ExecuteScalar();
        e.Status = UpdateStatus.SkipCurrentRow;
    }
}

請參閱

概念

資料列狀態和資料列版本

AcceptChanges 和 RejectChanges

合併 DataSet 內容 (ADO.NET)

以 DataAdapter 更新資料來源 (ADO.NET)

其他資源

擷取和修改 ADO.NET 中的資料

DataAdapter 和 DataReader (ADO.NET)