다음을 통해 공유


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

DataAdapter의 Update 메서드를 호출하면 DataSet의 변경 내용이 데이터 소스에 다시 적용됩니다. Update 메서드는 Fill 메서드와 마찬가지로 DataSet의 인스턴스, 선택적 DataTable 개체 또는 DataTable 이름을 인수로 사용합니다. DataSet 인스턴스는 변경 내용을 포함하는 DataSet이며 DataTable은 변경 내용을 검색할 테이블을 식별합니다. DataTable을 지정하지 않으면 DataSet의 첫 번째 DataTable이 사용됩니다.

Update 메서드를 호출하면 DataAdapter가 변경 내용을 분석하여 INSERT, UPDATE, DELETE 등의 적절한 명령을 실행합니다. DataRow에 대한 변경 사항이 발견되면 DataAdapter는 InsertCommand, UpdateCommand 또는 DeleteCommand를 사용하여 변경 내용을 처리합니다. 이로써 가능한 경우 디자인 타임에 저장 프로시저를 사용하여 명령 구문을 지정함으로써 ADO.NET 응용 프로그램의 성능을 최대화할 수 있습니다. Update를 호출하기 전에 명령을 명시적으로 설정해야 합니다. Update를 호출했는데 삭제된 행에 대한 DeleteCommand가 없는 경우와 같이 특정 업데이트에 사용할 적절한 명령이 없으면 예외가 throw됩니다.

참고참고

SQL Server 저장 프로시저를 통해 DataAdapter로 데이터를 편집하거나 삭제하는 경우에는 저장 프로시저 정의에 SET NOCOUNT ON을 사용하면 안 됩니다.SET NOCOUNT ON을 사용하는 경우 반환되는 행 개수가 0이 되어 DataAdapter가 이를 동시성 충돌로 인식합니다.그 결과 DBConcurrencyException이 throw됩니다.

명령 매개 변수를 사용하여 DataSet의 수정된 각 행에 대해 SQL 문이나 저장 프로시저의 입력 및 출력 값을 지정할 수 있습니다. 자세한 내용은 DataAdapter 매개 변수(ADO.NET)을 참조하십시오.

참고참고

DataTable에서의 행 삭제 및 제거의 차이점을 이해하는 것이 중요합니다.Remove 또는 RemoveAt 메서드를 호출하면 행이 즉시 제거됩니다.그런 다음 DataAdapter에 DataTable 또는 DataSet을 전달하고 Update를 호출하면 백 엔드 데이터 소스에 있는 해당 행은 아무런 영향을 받지 않습니다.Delete 메서드를 사용하면 행이 DataTable에 그대로 남아 있고 삭제 표시됩니다.그런 다음 DataAdapter에 DataTable 또는 DataSet을 전달하고 Update를 호출하면 백 엔드 데이터 소스의 해당 행이 삭제됩니다.

DataTable이 단일 데이터베이스 테이블에 매핑되거나 단일 데이터베이스 테이블에서 생성된 경우에는 DbCommandBuilder 개체를 사용하여 DataAdapter의 DeleteCommand, InsertCommand 및 UpdateCommand 개체를 자동으로 생성할 수 있습니다. 자세한 내용은 CommandBuilders를 사용하여 명령 생성(ADO.NET)을 참조하십시오.

UpdatedRowSource를 사용하여 DataSet에 값 매핑

DbCommand 개체의 UpdatedRowSource 속성을 사용하면 DataAdapter의 Update 메서드를 호출한 이후 데이터 소스에서 반환된 값이 DataTable에 다시 매핑되는 방법을 제어할 수 있습니다. UpdatedRowSource 속성을 UpdateRowSource 열거형 값 중 하나로 설정하면 DataAdapter 명령에서 반환하는 출력 매개 변수를 무시할지 아니면 DataSet의 변경된 행에 적용할지 제어할 수 있습니다. 반환되는 첫 번째 행이 있는 경우 이를 DataTable의 변경된 행에 적용할지 여부도 지정할 수 있습니다.

다음 표에서는 UpdateRowSource 열거형의 여러 값과 각 값이 DataAdapter에 사용하는 명령의 동작에 미치는 영향에 대해 설명합니다.

UpdatedRowSource 열거형

설명

Both

출력 매개 변수 및 반환된 결과 집합의 첫 번째 행 모두 DataSet의 변경된 행에 매핑할 수 있습니다.

FirstReturnedRecord

반환된 결과 집합의 첫 번째 행 데이터만 DataSet의 변경된 행에 매핑할 수 있습니다.

None

출력 매개 변수 또는 반환된 결과 집합의 행이 모두 무시됩니다.

OutputParameters

출력 매개 변수만 DataSet의 변경된 행에 매핑할 수 있습니다.

Update 메서드는 변경 내용을 데이터 소스에 다시 적용하지만 사용자가 DataSet을 마지막으로 채운 이후에 다른 클라이언트에서 데이터 소스의 데이터를 수정했을 수도 있습니다. 현재 데이터로 DataSet을 새로 고치려면 DataAdapter 및 Fill 메서드를 사용합니다. 그러면 새 행이 테이블에 추가되고 업데이트된 정보가 기존 행에 통합됩니다. Fill 메서드는 DataSet에 있는 행과 SelectCommand에서 반환된 행의 기본 키 값을 검사하여 새 행을 추가할지 또는 기존 행을 업데이트할지 결정합니다. SelectCommand가 반환한 결과 행의 기본 키 값과 일치하는 DataSet 행의 기본 키 값이 발견되면 Fill 메서드는 기존 행을 SelectCommand가 반환한 행의 정보로 업데이트하고 기존 행의 RowState를 Unchanged로 설정합니다 SelectCommand가 반환한 행의 기본 키 값이 DataSet 행의 기본 키 값과 일치하지 않으면 Fill 메서드는 RowState가 Unchanged인 새 행을 추가합니다.

참고참고

SelectCommand가 OUTER JOIN의 결과를 반환하면 DataAdapter는 결과 DataTable에 대해 PrimaryKey 값을 설정하지 않습니다.행 중복 문제를 해결하려면 PrimaryKey를 직접 정의해야 합니다.자세한 내용은 기본 키 정의(ADO.NET)를 참조하십시오.

Update 메서드를 호출할 때 발생할 수 있는 예외를 처리하려면 행 업데이트 오류가 발생했을 때 RowUpdated 이벤트를 사용하여 응답하거나(DataAdapter 이벤트 처리(ADO.NET) 참조), Update를 호출하기 전에 DataAdapter.ContinueUpdateOnError를 true로 설정하고 업데이트가 완료되면 특정 행의 RowError 속성에 저장된 오류 정보에 응답합니다(행 오류 정보 참조).

참고   DataSet, DataTable 또는 DataRow에 대해 AcceptChanges를 호출하면 DataRow의 Current 값이 DataRow의 모든 Original 값을 덮어씁니다. 행을 고유하게 식별하는 필드 값을 수정한 경우 AcceptChanges를 호출하면 Original 값이 데이터 소스의 값과 더 이상 일치하지 않습니다. AcceptChanges는 DataAdapter의 Update 메서드를 호출하는 동안 각 행에 대해 자동으로 호출됩니다. 먼저 DataAdapter의 AcceptChangesDuringUpdate 속성을 false로 설정하거나 RowUpdated 이벤트에 대한 이벤트 처리기를 만들고 StatusSkipCurrentRow로 설정하면 Update 메서드를 호출할 때 원래 값을 보존할 수 있습니다. 자세한 내용은 DataSet 내용 병합(ADO.NET)DataAdapter 이벤트 처리(ADO.NET)을 참조하십시오.

예제

다음 예제에서는 DataAdapter의 UpdateCommand를 명시적으로 설정하고 Update 메서드를 호출하여 수정된 행에 대해 업데이트를 수행하는 방법을 보여 줍니다. UPDATE 문의 WHERE 절에 지정된 매개 변수는 SourceColumn의 Original 값을 사용하도록 설정되어 있습니다. Current 값이 수정되어 데이터 소스에 있는 값과 일치하지 않을 수 있기 때문에 이 설정은 매우 중요합니다. Original 값은 데이터 소스에서 DataTable을 채우는 데 사용한 값입니다.

Private Sub AdapterUpdate(ByVal connectionString As String)

    Using connection As SqlConnection = New SqlConnection( _
       connectionString)

        Dim adapter As SqlDataAdapter = New SqlDataAdapter( _
          "SELECT CategoryID, CategoryName FROM dbo.Categories", _
          connection)

        adapter.UpdateCommand = New SqlCommand( _
          "UPDATE Categories SET CategoryName = @CategoryName " & _
           "WHERE CategoryID = @CategoryID", connection)

        adapter.UpdateCommand.Parameters.Add( _
           "@CategoryName", SqlDbType.NVarChar, 15, "CategoryName")

        Dim parameter As SqlParameter = _
           adapter.UpdateCommand.Parameters.Add( _
           "@CategoryID", SqlDbType.Int)
        parameter.SourceColumn = "CategoryID"
        parameter.SourceVersion = DataRowVersion.Original

        Dim categoryTable As New DataTable
        adapter.Fill(categoryTable)

        Dim categoryRow As DataRow = categoryTable.Rows(0)
        categoryRow("CategoryName") = "New Beverages"

        adapter.Update(categoryTable)

        Console.WriteLine("Rows after update.")
        Dim row As DataRow
        For Each row In categoryTable.Rows
            Console.WriteLine("{0}: {1}", row(0), row(1))
        Next
    End Using
End Sub
private static void AdapterUpdate(string connectionString)
{
    using (SqlConnection connection =
               new SqlConnection(connectionString))
    {
        SqlDataAdapter dataAdpater = new SqlDataAdapter(
          "SELECT CategoryID, CategoryName FROM Categories",
          connection);

        dataAdpater.UpdateCommand = new SqlCommand(
           "UPDATE Categories SET CategoryName = @CategoryName " +
           "WHERE CategoryID = @CategoryID", connection);

        dataAdpater.UpdateCommand.Parameters.Add(
           "@CategoryName", SqlDbType.NVarChar, 15, "CategoryName");

        SqlParameter parameter = dataAdpater.UpdateCommand.Parameters.Add(
          "@CategoryID", SqlDbType.Int);
        parameter.SourceColumn = "CategoryID";
        parameter.SourceVersion = DataRowVersion.Original;

        DataTable categoryTable = new DataTable();
        dataAdpater.Fill(categoryTable);

        DataRow categoryRow = categoryTable.Rows[0];
        categoryRow["CategoryName"] = "New Beverages";

        dataAdpater.Update(categoryTable);

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

AutoIncrement 열

데이터 소스의 테이블에 자동 증분 열이 있으면 저장 프로시저의 출력 매개 변수로 자동 증분 값을 반환하여 테이블의 열에 매핑하거나, 저장 프로시저 또는 SQL 문에서 반환된 결과 집합의 첫 번째 행에 있는 자동 증분 값을 반환하거나, DataAdapter의 RowUpdated 이벤트를 통해 추가적인 SELECT 문을 실행하여 DataSet의 열을 채울 수 있습니다. 자세한 내용과 예제를 보려면 ID 또는 Autonumber 값 검색(ADO.NET)을 참조하십시오.

삽입, 업데이트 및 삭제 순서

대부분의 경우에는 DataSet을 통해 변경된 내용이 데이터 소스에 전송되는 순서가 매우 중요합니다. 예를 들어 기존 행의 기본 키 값을 업데이트하고 새 기본 키 값이 외래 키로 지정된 새 행을 추가하는 경우에는 삽입하기 전에 업데이트를 처리해야 합니다.

DataTable의 Select 메서드를 사용하여 특정 RowState의 행만 참조하는 DataRow 배열을 반환할 수 있습니다. 그런 다음 반환된 DataRow 배열을 DataAdapter의 Update 메서드에 전달하여 수정된 행을 처리할 수 있습니다. 업데이트될 행의 하위 집합을 지정하여 삽입, 업데이트 및 삭제가 처리되는 순서를 제어할 수 있습니다.

예제

예를 들어, 다음 코드에서는 테이블의 삭제된 행이 먼저 처리되고 업데이트된 행과 삽입된 행이 차례로 처리되도록 합니다.

Dim table As DataTable = dataSet.Tables("Customers")

' First process deletes.
dataSet.Update(table.Select(Nothing, Nothing, _
  DataViewRowState.Deleted))

' Next process updates.
adapter.Update(table.Select(Nothing, Nothing, _
  DataViewRowState.ModifiedCurrent))

' Finally, process inserts.
dataAdpater.Update(table.Select(Nothing, Nothing, _
  DataViewRowState.Added))
DataTable table = dataSet.Tables["Customers"];

// First process deletes.
adapter.Update(table.Select(null, null, DataViewRowState.Deleted));

// Next process updates.
adapter.Update(table.Select(null, null, 
  DataViewRowState.ModifiedCurrent));

// Finally, process inserts.
adapter.Update(table.Select(null, null, DataViewRowState.Added));

참고 항목

개념

행 상태 및 행 버전

AcceptChanges 및 RejectChanges

DataSet 내용 병합(ADO.NET)

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

기타 리소스

DataAdapters 및 DataReaders(ADO.NET)