擷取識別或 Autonumber 值
您可以將 DataTable 中的資料行設定為自動遞增的主索引鍵,以確保資料表中的每個資料列使用唯一的值;但是,您的應用程式可能有數個用戶端,而每個用戶端又可能使用 DataTable 的個別執行個體 (Instance)。這種情況下,可能會造成 DataTable 的個別執行個體具有重複值。由於您所有的用戶端都使用單一資料來源,您可以讓資料來源定義自動遞增值來解決這項衝突。若要完成這項作業,請使用 Microsoft SQL Server 中的 Identity 欄位,或 Microsoft Access 中的 Autonumber 欄位。
以資料來源將 DataSet 內所加入新資料列的 Identity 或 Autonumber 資料行填入時,因為 DataSet 並沒有直接連接至資料來源,所以會產生獨一無二的的情況,DataSet 因而無法得知任何由資料來源自動產生的值;相反地,若您使用的資料來源 (例如 Microsoft SQL Server) 能以輸出參數建立預存程序 (Stored Procedure),則您可以將自動產生的值 (例如新識別值) 指定為輸出參數,並使用 DataAdapter 將這個值對應回 DataSet 內的資料行。
您的資料來源可能不支援具有輸出參數的預存程序。在這種情況下,您可以使用 RowUpdated 事件來擷取自動產生值,並將值置入 DataSet 內插入或更新的資料列。這個章節的範例將示範如何使用 Microsoft Access 2000 (含) 以後版本以及 Jet 4.0 OLE DB 提供者,將程式碼加入 RowUpdated 事件以判斷是否已經發生插入動作,並擷取自動遞增值並將其儲存至目前更新的資料列。
下列預存程序和程式碼範例示範如何從 Microsoft SQL Server 資料表,將自動遞增的識別碼值對應回加入 DataSet 資料表的資料列中與識別 (Identity) 值對應的資料行。預存程序則用來將新資料列插入 Northwind 資料庫的 Categories 資料表,並將自 SCOPE_IDENTITY() 傳回的識別值當成輸出參數。
CREATE PROCEDURE InsertCategory
@CategoryName nchar(15),
@Identity int OUT
AS
INSERT INTO Categories (CategoryName) VALUES(@CategoryName)
SET @Identity = SCOPE_IDENTITY()
接下來,可以將 InsertCategory 預存程序指定為 DataAdapter.InsertCommand 的來源。這時要建立一個參數來接收識別輸出參數。這個參數的 Direction 為 ParameterDirection.Output,並且將 DataSet 中本機 Categories 資料表的 CategoryID 資料行指定為 SourceColumn。在執行 InsertCommand 新增資料列時,會將自動遞增識別值當成輸出參數傳回,並放置在目前資料列的 CategoryID 資料行。
下列程式碼範例顯示如何將自動遞增值當成輸出參數傳回,以及如何把這個值指定為 DataSet 內 CategoryID 資料行的來源值。
Dim nwindConn As SqlConnection = New SqlConnection("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind")
Dim catDA As SqlDataAdapter = New SqlDataAdapter("SELECT CategoryID, CategoryName FROM Categories", nwindConn)
catDA.InsertCommand = New SqlCommand("InsertCategory", nwindConn)
catDA.InsertCommand.CommandType = CommandType.StoredProcedure
catDA.InsertCommand.Parameters.Add("@CategoryName", SqlDbType.NChar, 15, "CategoryName")
Dim myParm As SqlParameter = catDA.InsertCommand.Parameters.Add("@Identity", SqlDbType.Int, 0, "CategoryID")
myParm.Direction = ParameterDirection.Output
nwindConn.Open()
Dim catDS As DataSet = New DataSet
catDA.Fill(catDS, "Categories")
Dim newRow As DataRow = catDS.Tables("Categories").NewRow()
newRow("CategoryName") = "New Category"
catDS.Tables("Categories").Rows.Add(newRow)
catDA.Update(catDS, "Categories")
nwindConn.Close()
[C#]
SqlConnection nwindConn = new SqlConnection("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind");
SqlDataAdapter catDA = new SqlDataAdapter("SELECT CategoryID, CategoryName FROM Categories", nwindConn);
catDA.InsertCommand = new SqlCommand("InsertCategory", nwindConn);
catDA.InsertCommand.CommandType = CommandType.StoredProcedure;
catDA.InsertCommand.Parameters.Add("@CategoryName", SqlDbType.NChar, 15, "CategoryName");
SqlParameter myParm = catDA.InsertCommand.Parameters.Add("@Identity", SqlDbType.Int, 0, "CategoryID");
myParm.Direction = ParameterDirection.Output;
nwindConn.Open();
DataSet catDS = new DataSet();
catDA.Fill(catDS, "Categories");
DataRow newRow = catDS.Tables["Categories"].NewRow();
newRow["CategoryName"] = "New Category";
catDS.Tables["Categories"].Rows.Add(newRow);
catDA.Update(catDS, "Categories");
nwindConn.Close();
Microsoft Access 不支援預存程序或批次命令處理,所以不可能像之前的範例一樣,將輸出參數對應至來源資料行;但是,Microsoft Access 2000 (含) 以後版本支援 @@IDENTITY 屬性,可擷取 INSERT 後 Autonumber 欄位的值。您可以使用 RowUpdated 事件判斷是否發生過 INSERT,可以擷取最新的 @@IDENTITY 值,也可以將這個值置入 DataSet 中區域資料表的識別資料行。
下列程式碼範例顯示如何將新值插入 Microsoft Access 2000 Northwind 資料庫的 Categories 資料表。在這個範例中,將資料錄插入 Categories 資料表時,會使用 RowUpdated 事件來填入 Jet 引擎和 Access 資料庫產生的 Autonumber 值。請注意,這種用法僅適用於 Jet 4.0 OLE DB 提供者以及 Microsoft Access 2000 (含) 以後版本。
Imports System
Imports System.Data
Imports System.Data.OleDb
Imports Microsoft.VisualBasic
Public class Sample
Shared nwindConn As OleDbConnection = New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=c:\Program Files\Microsoft Office\Office\Samples\northwind.mdb;")
Public Shared Sub Main()
' Use the DataAdapter to fill and update the DataSet.
Dim catDA As OleDbDataAdapter = New OleDbDataAdapter("SELECT CategoryID, CategoryName FROM Categories ORDER BY CategoryID", nwindConn)
catDA.InsertCommand = New OleDbCommand("INSERT INTO Categories (CategoryName) Values(?)", nwindConn)
catDA.InsertCommand.CommandType = CommandType.Text
catDA.InsertCommand.Parameters.Add("@CategoryName", OleDbType.Char, 15, "CategoryName")
nwindConn.Open()
' Fill the DataSet.
Dim catDS As DataSet = New DataSet
catDA.Fill(catDS, "Categories")
' Add a new row.
Dim newRow As DataRow = catDS.Tables("Categories").NewRow()
newRow("CategoryName") = "New Category"
catDS.Tables("Categories").Rows.Add(newRow)
' Include an event to fill in the Autonumber value.
AddHandler catDA.RowUpdated, New OleDbRowUpdatedEventHandler(AddressOf OnRowUpdated)
' Update the DataSet.
catDA.Update(catDS, "Categories")
nwindConn.Close()
End Sub
Private Shared Sub OnRowUpdated(sender As Object, args As OleDbRowUpdatedEventArgs)
' Include a variable and a command to retrieve the identity value from the Access database.
Dim newID As Integer = 0
Dim idCMD As OleDbCommand = New OleDbCommand("SELECT @@IDENTITY", nwindConn)
If args.StatementType = StatementType.Insert
' Retrieve the identity value and store it in the CategoryID column.
newID = CInt(idCMD.ExecuteScalar())
args.Row("CategoryID") = newID
End If
End Sub
End Class
[C#]
using System;
using System.Data;
using System.Data.OleDb;
public class Sample
{
static OleDbConnection nwindConn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;" +
@"Data Source=c:\Program Files\Microsoft Office\Office\Samples\northwind.mdb;");
public static void Main()
{
// Use the DataAdapter to fill and update the DataSet.
OleDbDataAdapter catDA = new OleDbDataAdapter("SELECT CategoryID, CategoryName FROM Categories ORDER BY CategoryID", nwindConn);
catDA.InsertCommand = new OleDbCommand("INSERT INTO Categories (CategoryName) Values(?)", nwindConn);
catDA.InsertCommand.CommandType = CommandType.Text;
catDA.InsertCommand.Parameters.Add("@CategoryName", OleDbType.Char, 15, "CategoryName");
nwindConn.Open();
// Fill the DataSet.
DataSet catDS = new DataSet();
catDA.Fill(catDS, "Categories");
// Add a new row.
DataRow newRow = catDS.Tables["Categories"].NewRow();
newRow["CategoryName"] = "New Category";
catDS.Tables["Categories"].Rows.Add(newRow);
// Include an event to fill in the Autonumber value.
catDA.RowUpdated += new OleDbRowUpdatedEventHandler(OnRowUpdated);
// Update the DataSet.
catDA.Update(catDS, "Categories");
nwindConn.Close();
}
protected static void OnRowUpdated(object sender, OleDbRowUpdatedEventArgs args)
{
// Include a variable and a command to retrieve the identity value from the Access database.
int newID = 0;
OleDbCommand idCMD = new OleDbCommand("SELECT @@IDENTITY", nwindConn);
if (args.StatementType == StatementType.Insert)
{
// Retrieve the identity value and store it in the CategoryID column.
newID = (int)idCMD.ExecuteScalar();
args.Row["CategoryID"] = newID;
}
}
}
請參閱
ADO.NET 案例範例 | 使用 ADO.NET 存取資料 | 使用 .NET Framework 資料提供者存取資料