Share via


ID 또는 Autonumber 값 검색(ADO.NET)

관계형 데이터베이스에서 기본 키는 항상 고유한 값이 들어 있는 열 또는 열의 조합입니다. 기본 키 값을 알면 해당 값이 있는 행을 찾을 수 있습니다. SQL Server, Oracle 및 Microsoft Access/Jet 등과 같은 관계형 데이터베이스 엔진은 기본 키로 지정할 수 있는 자동 증분 열의 작성을 지원합니다. 이러한 값은 서버에 의해 행으로 생성되어 테이블에 추가됩니다. 이를 위해서는 SQL Server에서는 열의 identity 속성을 설정하고, Oracle에서는 시퀀스를 만들고, Microsoft Access에서는 AutoNumber 열을 만듭니다.

또한 DataColumn을 사용하고 AutoIncrement 속성을 true로 설정하면 자동으로 증분하는 값을 생성할 수도 있습니다. 하지만 여러 클라이언트 응용 프로그램이 개별적으로 자동 증분 값을 생성하면 DataTable의 개별 인스턴스에서 중복되는 값이 생길 수 있습니다. 따라서 서버가 자동 증분 값을 생성하도록 하면 삽입된 각 행에 대해 생성되는 값을 각 사용자가 검색할 수 있도록 할 때 발생할 수 있는 충돌을 방지할 수 있습니다.

DataAdapter의 Update 메서드 호출 도중 데이터베이스는 데이터를 출력 매개 변수로, 또는 INSERT 문과 동일한 배치에서 실행되는 SELECT 문의 결과 집합 중 첫 번째 반환되는 레코드로 ADO.NET 응용 프로그램에 다시 보낼 수 있습니다. ADO.NET에서는 이러한 값을 검색하여 업데이트되는 DataRow의 해당 열을 업데이트할 수 있습니다.

Microsoft Access Jet 데이터베이스 엔진과 같은 일부 데이터베이스에서는 출력 매개 변수를 지원하지 않으며 하나의 배치에서 여러 문을 처리할 수 없습니다. Jet 데이터베이스 엔진으로 작업하는 경우 DataAdapter의 RowUpdated 이벤트에 대한 이벤트 처리기에서 별도의 SELECT 명령을 실행하여 삽입된 행에 대해 생성되는 새 AutoNumber 값을 검색할 수 있습니다.

참고참고

자동 증분 값 대신 사용할 수 있는 방법은 Guid 개체의 NewGuid 메서드를 사용하여 새로운 행이 삽입될 때마다 서버로 복사될 수 있는 GUID(Globally Unique Identifier)를 클라이언트 컴퓨터에 생성하는 것입니다.NewGuid 메서드는 값이 복제되지 않을 확률이 높은 알고리즘을 사용하여 16바이트 이진 값을 생성합니다.SQL Server 데이터베이스에서 GUID는 SQL Server가 Transact-SQL NEWID() 함수를 사용하여 자동으로 생성할 수 있는 uniqueidentifier 열에 저장됩니다.GUID를 기본 키로 사용하면 성능에 부정적 영향을 미칠 수 있습니다.SQL Server 2005에서는 전역적으로 고유하지 않을 수도 있지만 더 효율적으로 인덱싱할 수 있는 순차적 GUID를 생성하는 NEWSEQUENTIALID() 함수를 지원합니다.

SQL Server ID 열 값 검색

Microsoft SQL Server로 작업하는 경우에는 출력 매개 변수를 사용하는 저장 프로시저를 만들어서 삽입된 행에 대한 ID 값을 반환할 수 있습니다. 다음 표에서는 ID 열 값을 검색하는 데 사용할 수 있는 SQL Server의 세 가지 Transact-SQL 함수를 설명합니다.

함수

설명

SCOPE_IDENTITY

현재 실행 범위 내의 마지막 ID 값을 반환합니다. SCOPE_IDENTITY는 대부분의 시나리오에 권장됩니다.

@@IDENTITY

현재 세션의 모든 테이블에서 생성된 마지막 ID 값을 포함합니다. @@IDENTITY는 트리거의 영향을 받을 수 있으며 예상한 ID 값을 반환하지 않을 수도 있습니다.

IDENT_CURRENT

모든 세션 및 모든 범위의 특정 테이블에 대해 생성된 마지막 ID 값을 반환합니다.

다음 저장 프로시저는 Categories 테이블에 행을 삽입하고 출력 매개 변수를 사용하여 Transact-SQL SCOPE_IDENTITY() 함수에서 생성된 새 ID 값을 반환하는 방법을 보여 줍니다.

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로 설정해야 합니다. ID 출력은 ParameterDirectionOutputSqlParameter를 만들어서 검색합니다. InsertCommand가 처리될 때 자동 증분된 ID 값이 반환되고, 삽입 명령의 UpdatedRowSource 속성을 UpdateRowSource.OutputParameters 또는 UpdateRowSource.Both로 설정한 경우 이 값이 현재 행의 CategoryID 열에 추가됩니다.

삽입 명령이 새 ID 값을 반환하는 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]);
            }
        }
    }
}

새 ID 값 병합

일반적인 시나리오는 DataTable의 GetChanges 메서드를 호출하여 변경된 행만 포함된 사본을 만들고 DataAdapter의 Update 메서드를 호출할 때 새 사본을 사용하는 것입니다. 이 방법은 변경된 행을 업데이트를 수행하는 별도의 구성 요소로 마샬링해야 할 때 특히 유용합니다. 업데이트 후 사본에는 원래 DataTable로 다시 병합되어야 하는 새 ID 값이 포함될 수 있습니다. 새 ID 값은 DataTable의 원래 값과 다를 가능성이 큽니다. 병합을 수행하려면 사본에 AutoIncrement 열의 원래 값이 유지되어야 합니다. 그래야 새 ID 값이 포함된 새 행을 추가하지 않고 원래 DataTable의 기존 행을 찾아 업데이트할 수 있습니다. 하지만 AcceptChanges는 업데이트된 각 DataRow에 대해 암시적으로 호출되기 때문에 기본적으로 원래 값은 DataAdapter의 Update 메서드에 대한 호출 후에 손실됩니다.

DataAdapter 업데이트 동안 DataRow에서 DataColumn의 원래 값을 유지하는 방법에는 두 가지가 있습니다.

  • 원래 값을 유지하는 첫 번째 방법은 DataAdapter의 AcceptChangesDuringUpdate 속성을 false로 설정하는 것입니다. 이 설정은 업데이트되는 DataTable의 모든 DataRow에 영향을 줍니다. 자세한 내용과 코드 예제를 보려면 AcceptChangesDuringUpdate를 참조하십시오.

  • 두 번째 방법은 DataAdapter의 RowUpdated 이벤트 처리기에서 코드를 작성하여 StatusSkipCurrentRow로 설정하는 것입니다. DataRow가 업데이트되지만 각 DataColumn의 원래 값은 유지됩니다. 이 방법을 사용하면 원하는 행의 원래 값만 유지할 수 있습니다. 예를 들어 StatementType을 검사한 다음 StatementType이 Insert인 행의 StatusSkipCurrentRow로 설정하여 추가된 행의 원래 값은 유지하고 편집 또는 삭제된 행은 원래 값을 유지하지 않도록 코드를 작성할 수 있습니다.

이 방법 중 하나를 사용하여 DataAdapter 업데이트 동안 DataRow의 원래 값을 유지하는 경우, ADO.NET에서는 각 DataColumn의 원래 값을 유지하면서 DataRow의 현재 값을 출력 매개 변수 또는 결과 집합의 첫 번째 반환 행을 통해 반환되는 새 값으로 설정하기 위한 일련의 작업을 수행합니다. 먼저 현재 값을 원래 값으로 유지하기 위해 DataRow의 AcceptChanges 메서드를 호출한 다음 새 값을 할당합니다. 그런 다음 RowState 속성이 Added로 설정된 DataRows의 RowState 속성을 Modified로 설정합니다. 이는 예상하지 않은 동작일 수 있습니다.

업데이트되는 각 DataRow에 명령 결과가 적용되는 방법은 각 DbCommandUpdatedRowSource 속성에 따라 결정됩니다. 이 속성은 UpdateRowSource 열거형의 값으로 설정됩니다.

다음 표에서는 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를 사용하여 데이터 소스를 업데이트하고 새 ID 열 값을 검색하는 방법을 보여 줍니다. InsertCommand는 두 개의 Transact-SQL 문을 실행합니다. 첫 번째는 INSERT 문이고, 두 번째는 SCOPE_IDENTITY 함수를 사용하여 ID 값을 검색하는 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로 추출되고, DataTable이 DataAdapter로 전달되고 나면 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 메서드가 호출되어 새 ID 값을 원래 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 데이터베이스 엔진은 출력 매개 변수를 사용하거나 배치로 여러 개의 문을 실행하는 것을 지원하지 않으므로, 위에 설명한 기술을 사용하여 삽입된 행에 할당된 새 Autonumber 값을 반환할 수 없습니다. 그러나 별도의 SELECT @@IDENTITY 문을 실행하여 새 Autonumber 값을 검색하는 RowUpdated 이벤트 처리기에 코드를 추가할 수 있습니다.

예제

이 예제에서는 MissingSchemaAction.AddWithKey를 사용하여 스키마 정보를 추가하는 대신 먼저 DataTable을 올바른 스키마로 구성한 다음 OleDbDataAdapter를 호출하여 DataTable을 채웁니다. 이 경우 AutoIncrement를 true로, AutoIncrementSeed를 0으로, 그리고 AutoIncrementStep을 -1로 설정하여 삽입된 각 행에 할당되는 값이 0부터 시작하여 감소되도록 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 이벤트 처리기에서는 동일한 열려 있는 OleDbConnection을 OleDbDataAdapter의 Update 문으로 사용합니다. 또한, 삽입된 행에 대한 OleDbRowUpdatedEventArgs의 StatementType을 검사합니다. 삽입된 각 행에 대해 새 OleDbCommand가 생성되어 연결에 대해 SELECT @@IDENTITY 문을 실행하고 새 Autonumber 값을 반환합니다. 이 값은 DataRow의 CategoryID 열에 추가됩니다. 그런 다음 AcceptChanges에 대한 숨겨진 호출을 방지하기 위해 Status 속성이 UpdateStatus.SkipCurrentRow로 설정됩니다. 프로시저의 본문에서 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)

DataAdapters를 사용하여 데이터 소스 업데이트(ADO.NET)

기타 리소스

ADO.NET에서 데이터 검색 및 수정

DataAdapters 및 DataReaders(ADO.NET)