다음을 통해 공유


DataSet 내용 병합(ADO.NET)

Merge 메서드를 사용하여 DataSet, DataTable 또는 DataRow 배열의 내용을 기존 DataSet으로 병합할 수 있습니다. 새 데이터가 기존 DataSet으로 병합되는 방법은 몇 가지 요소 및 옵션에 따라 달라집니다.

기본 키

병합을 통해 새 데이터와 스키마를 받는 테이블에 기본 키가 있는 경우 들어오는 데이터의 새 행은 들어오는 데이터의 행과 동일한 Original 기본 키 값을 가진 기존 행이 있는지 비교됩니다. 들어오는 스키마의 열이 기존 스키마의 열과 일치하면 기존 행의 데이터가 수정됩니다. 기존 스키마와 일치하지 않는 열은 MissingSchemaAction 매개 변수에 따라 무시되거나 추가됩니다. 기존 행과 일치하지 않는 기본 키 값을 가진 새 행은 기존 테이블에 추가됩니다.

들어오는 행 또는 기존 행의 상태가 Added이면 Original 행 버전이 없으므로 해당 기본 키 값은 Added 행의 Current 기본 키 값을 사용하여 비교됩니다.

들어오는 테이블과 기존 테이블에 이름은 같지만 데이터 형식이 다른 열이 있으면 예외가 throw되고 DataSet의 MergeFailed 이벤트가 발생합니다. 들어오는 테이블과 기존 테이블에 모두 키가 정의되어 있지만 각 열의 기본 키가 서로 다르면 예외가 throw되고 DataSet의 MergeFailed 이벤트가 발생합니다.

병합을 통해 새 데이터를 받는 테이블에 기본 키가 없으면 들어오는 데이터의 새 행이 테이블의 기존 행과 일치할 수는 없고, 대신 기존 테이블에 추가됩니다.

테이블 이름 및 네임스페이스

DataTable 개체에는 선택적으로 Namespace 속성 값을 할당할 수 있습니다. Namespace 값이 할당된 경우 DataSet에는 TableName 값이 같은 여러 DataTable 개체가 있을 수 있습니다. 병합 작업 도중 TableNameNamespace를 사용하여 병합의 대상을 식별합니다. Namespace가 할당되지 않은 경우에는 TableName만 사용하여 병합의 대상을 식별합니다.

참고참고

이는 .NET Framework의 버전 2.0에서 변경된 동작입니다.버전 1.1에서는 네임스페이스가 지원되었지만 병합 작업 도중 무시되었습니다.이러한 이유로 Namespace 속성 값을 사용하는 DataSet은 실행 중인 .NET Framework의 버전에 따라 다르게 동작합니다.예를 들어 TableName 속성 값은 같지만 Namespace 속성 값이 다른 DataTables가 있는 두 개의 DataSets가 있다고 가정합니다..NET Framework의 버전 1.1에서는 두 DataSet 개체를 병합할 때 서로 다른 Namespace 이름은 무시됩니다.하지만 버전 2.0부터는 병합할 경우 두 개의 새로운 DataTables가 대상 DataSet에 생성됩니다.원래의 DataTables는 병합의 영향을 받지 않습니다.

PreserveChanges

DataSet, DataTable 또는 DataRow 배열을 Merge 메서드로 전달할 때는 기존 DataSet의 변경 내용을 유지할 것인지 여부와 들어오는 데이터에서 발견되는 새 스키마 요소를 처리하는 방법을 지정하는 선택적 매개 변수를 포함할 수 있습니다. 들어오는 데이터 다음에 나오는 이러한 매개 변수 중 첫 번째는 부울 플래그인 PreserveChanges이며, 이 플래그는 기존 DataSet의 변경 내용을 유지할지 여부를 지정합니다. PreserveChanges 플래그가 true로 설정되어 있으면 들어오는 값은 기존 행의 Current 행 버전에 있는 기존 값을 덮어쓰지 않습니다. PreserveChanges 플래그가 false로 설정되어 있으면 들어오는 값은 기존 행의 Current 행 버전에 있는 기존 값을 덮어씁니다. PreserveChanges 플래그를 지정하지 않으면 false가 기본값으로 설정됩니다. 행 버전에 대한 자세한 내용은 행 상태 및 행 버전을 참조하십시오.

PreserveChanges가 true이면 기존 행의 데이터는 기존 행의 Current 행 버전에 유지되지만 기존 행의 Original 행 버전에 있는 데이터는 들어오는 행의 Original 행 버전에 있는 데이터로 덮어쓰여집니다. 기존 행의 RowStateModified로 설정됩니다. 다음과 같은 예외가 있습니다.

  • 기존 행의 RowState가 Deleted인 경우 이 RowState는 Deleted로 유지되며 Modified로 설정되지 않습니다. 이 경우, 들어오는 행의 데이터는 기존 행의 Original 행 버전에 계속 저장되어 기존 행의 Original 행 버전을 덮어씁니다. 단, 들어오는 행의 RowState가 Added인 경우는 예외입니다.

  • 들어오는 행의 RowState가 Added이면 들어오는 행에 Original 행 버전이 없으므로 기존 행의 Original 행 버전 데이터가 들어오는 행의 데이터로 덮어쓰여지지 않습니다.

PreserveChanges가 false이면 기존 행의 Current 및 Original 행 버전이 들어오는 행의 데이터로 덮어쓰여지며 기존 행의 RowState는 들어오는 행의 RowState로 설정됩니다. 다음과 같은 예외가 있습니다.

  • 들어오는 행의 RowState가 Unchanged이고 기존 행의 RowState가 Modified, Deleted 또는 Added이면 기존 행의 RowState가 Modified로 설정됩니다.

  • 들어오는 행의 RowState가 Added이고 기존 행의 RowState가 Unchanged, Modified 또는 Deleted이면 기존 행의 RowState가 Modified로 설정됩니다. 또한, 들어오는 행에 Original 행 버전이 없으므로 기존 행의 Original 행 버전 데이터는 들어오는 행의 데이터로 덮어쓰여지지 않습니다.

MissingSchemaAction

Merge 메서드의 선택적 MissingSchemaAction 매개 변수를 사용하면 기존 DataSet에 포함되어 있지 않은 들어오는 데이터의 스키마 요소를 Merge에서 어떻게 처리할지 지정할 수 있습니다.

다음 표에서는 MissingSchemaAction의 옵션을 설명합니다.

MissingSchemaAction 옵션

설명

Add

DataSet에 새 스키마 정보를 추가한 다음 새 열을 들어오는 값으로 채웁니다. 기본값입니다.

AddWithKey

DataSet에 새 스키마와 기본 키 정보를 추가한 다음 새 열을 들어오는 값으로 채웁니다.

Error

일치하지 않는 스키마 정보가 발견되면 예외가 throw됩니다.

Ignore

새 스키마 정보를 무시합니다.

제약 조건

Merge 메서드를 사용하면 새 데이터가 기존 DataSet에 모두 추가되기 전까지 제약 조건이 검사되지 않습니다. 데이터가 추가되고 나면 DataSet의 현재 값에 제약 조건이 적용됩니다. 제약 조건 위반으로 인해 throw되는 모든 예외를 처리하도록 코드를 작성해야 합니다.

DataSet의 기존 행이 기본 키 값이 1인 Unchanged 행인 경우를 살펴보십시오. Original 기본 키 값이 2이고 Current 기본 키 값이 1인 Modified 들어오는 행에 대해 병합 작업을 수행할 경우 Original 기본 키 값이 다르기 때문에 기존 행과 들어오는 행은 일치하지 않는 것으로 간주됩니다. 그러나 병합을 완료하고 제약 조건을 검사하면 Current 기본 키 값이 기본 키 열의 UNIQUE 제약 조건을 위반하므로 예외가 throw됩니다.

참고참고

ID 열과 같은 자동 증분 열이 있는 데이터베이스 테이블에 행이 삽입되는 경우에는 삽입을 통해 반환되는 ID 열 값이 DataSet의 값과 일치하지 않을 수 있으므로 반환되는 행이 병합되는 대신 추가됩니다.자세한 내용은 ID 또는 Autonumber 값 검색(ADO.NET)을 참조하십시오.

다음 코드 예제에서는 스키마가 서로 다른 두 개의 DataSet 개체를 들어오는 두 DataSet 개체의 스키마가 결합된 하나의 DataSet으로 병합합니다.

Using connection As SqlConnection = New SqlConnection( _
   connectionString)

    Dim adapter As SqlDataAdapter = New SqlDataAdapter( _
      "SELECT CustomerID, CompanyName FROM Customers", connection)

    connection.Open()

    Dim customers As DataSet = New DataSet()
    adapter.FillSchema(customers, SchemaType.Source, "Customers")
    adapter.Fill(customers, "Customers")

    Dim orders As DataSet = New DataSet()
    orders.ReadXml("Orders.xml", XmlReadMode.ReadSchema)
    orders.AcceptChanges()

    customers.Merge(orders, True, MissingSchemaAction.AddWithKey)
End Using
using (SqlConnection connection =
           new SqlConnection(connectionString))
{
    SqlDataAdapter adapter = 
        new SqlDataAdapter(
        "SELECT CustomerID, CompanyName FROM dbo.Customers", 
        connection);

    connection.Open();

    DataSet customers = new DataSet();
    adapter.FillSchema(customers, SchemaType.Source, "Customers");
    adapter.Fill(customers, "Customers");

    DataSet orders = new DataSet();
    orders.ReadXml("Orders.xml", XmlReadMode.ReadSchema);
    orders.AcceptChanges();

    customers.Merge(orders, true, MissingSchemaAction.AddWithKey);

다음 코드 예제에서는 업데이트 사항이 있는 기존 DataSet을 사용하여 해당 업데이트를 DataAdapter로 전달하여 데이터 소스에서 처리되도록 합니다. 그러면 결과가 원래 DataSet에 병합됩니다. 오류를 발생시킨 변경 내용이 거부된 후에는 병합된 변경 내용이 AcceptChanges를 사용하여 커밋됩니다.

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

            ' Make modifications to the Customers table.

            ' Get changes to the DataSet.
            Dim dataSetChanges As DataSet = dataSet.GetChanges()

            ' Add an event handler to handle the errors during Update.
            AddHandler adapter.RowUpdated, New SqlRowUpdatedEventHandler( _
              AddressOf OnRowUpdated)

            connection.Open()
            adapter.Update(dataSetChanges, "Customers")
            connection.Close()

            ' Merge the updates.
            dataSet.Merge(dataSetChanges, True, MissingSchemaAction.Add)

            ' Reject changes on rows with errors and clear the error.
            Dim errRows() As DataRow = dataSet.Tables("Customers").GetErrors()
            Dim errRow As DataRow
            For Each errRow In errRows
                errRow.RejectChanges()
                errRow.RowError = Nothing
            Next

            ' Commit the changes.
            dataSet.AcceptChanges()

            DataTable customers = dataSet.Tables["Customers"];

            // Make modifications to the Customers table.

            // Get changes to the DataSet.
            DataSet dataSetChanges = dataSet.GetChanges();

            // Add an event handler to handle the errors during Update.
            adapter.RowUpdated += new SqlRowUpdatedEventHandler(OnRowUpdated);

            connection.Open();
            adapter.Update(dataSetChanges, "Customers");
            connection.Close();

            // Merge the updates.
            dataSet.Merge(dataSetChanges, true, MissingSchemaAction.Add);

            // Reject changes on rows with errors and clear the error.
            DataRow[] errRows = dataSet.Tables["Customers"].GetErrors();
            foreach (DataRow errRow in errRows)
            {
                errRow.RejectChanges();
                errRow.RowError = null;
            }

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

Private Sub OnRowUpdated( _
    ByVal sender As Object, ByVal args As SqlRowUpdatedEventArgs)
    If args.Status = UpdateStatus.ErrorsOccurred Then
        args.Row.RowError = args.Errors.Message
        args.Status = UpdateStatus.SkipCurrentRow
    End If
End Sub
protected static void OnRowUpdated(
    object sender, SqlRowUpdatedEventArgs args)
{
    if (args.Status == UpdateStatus.ErrorsOccurred)
    {
        args.Row.RowError = args.Errors.Message;
        args.Status = UpdateStatus.SkipCurrentRow;
    }
}

참고 항목

개념

행 상태 및 행 버전

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

기타 리소스

DataSets, DataTables 및 DataViews(ADO.NET)

DataAdapters 및 DataReaders(ADO.NET)

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