2011-06-29 3 views
2

私は2つのXMLデータセットds1とds2を持っています。私はこれらのデータセットを.ReadXML(name、XmlReadMode.ReadSchema)で読みます。私は、以下に示すように、マージされたデータセットを使用して、2つの違いを持つDiffGramを取得しようとしています。DataSet DiffGramを取得するMergeとAcceptChanges

DataSet ds3 = new DataSet(); 
ds3.Merge(ds1); 
ds3.AcceptChanges(); 
ds3.Merge(ds2); 

DataSet ds4 = ds3.GetChanges(); 

ds4.WriteXml("ds4.xml", XmlWriteMode.DiffGram); 

それぞれds1およびds2には複数の要素が含まれています。私はds1ファイルをコピーし、レコードの1つを変更してds2を作成しました。

実行後にds4.xmlを見ると、ds1のすべてのレコードセットとds2のすべてのレコードが表示されます(重複したエントリが表示される)ので、ds2の更新は次のように表示されます。 diffgr:hasChanges = "inserted">これは挿入するだけで、既存のレコードは更新されないようです。

どのようにしてds4にds2で加えられた変更のみを表示させることができますか?

答えて

3

この挿入と更新の動作は、通常、定義された主キーがないために発生します。テーブルに主キーを設定しましたか?これは、マージ時に列がどのようにマッチするかを示しています。 Per MSDN(強調鉱山):

にターゲットを新たなソースデータセットをマージし、そのまま の DataRowState値を有する任意のソース行が変更、または削除は、同じプライマリと ターゲット行に一致ありますキー 値。 のDataRowState値を持つソース行は、新しいターゲット行に一致する であり、 の同じ主キー値を新しいソース行として としています。

したがって、DataTableごとにPrimaryKey propertyを設定する必要があります。私は数年前にこの詳細な例をMSDN DataTable.Mergeページに書きました。あなたはここで書いてみることができます:Merge using Primary Keys for Expected Results

このアプローチの簡単な例:

DataTable dt1 = new DataTable(); 
dt1.Columns.Add("ID", typeof(int)); 
dt1.Columns.Add("Customer", typeof(string)); 
dt1.PrimaryKey = new[] { dt1.Columns["ID"] }; 
dt1.Rows.Add(new object[] { 1, "Ahmad" }); 

DataTable dt2 = new DataTable(); 
dt2.Columns.Add("ID", typeof(int)); 
dt2.Columns.Add("Customer", typeof(string)); 
dt2.PrimaryKey = new[] { dt2.Columns["ID"] }; 
dt2.Rows.Add(new object[] { 1, "Mageed" }); 

// try without primary keys and it'll add a new record 
dt1.Merge(dt2); 

EDIT:あなたのコメントについて、あなたは本当に、以下のコードをテーブルを渡すことによって変化しなかったマージされた行の変更を拒否できます。 DataTableを受け入れるメソッドはそれほど役に立ちません。 DataTable.AcceptChanges() methodを呼び出す前にこのコードを使用することが重要です。そうしないと、行の状態は破棄されます。 LINQで

:LINQができない場合は

foreach (DataRow row in dt1.Rows) 
{ 
    if (row.RowState == DataRowState.Modified) 
    { 
     var original = dt1.Columns.Cast<DataColumn>() 
          .Select(c => row[c, DataRowVersion.Original]); 

     bool isUnchanged = row.ItemArray.SequenceEqual(original); 
     if (isUnchanged) 
     { 
      row.RejectChanges(); 
     } 
    } 
} 

foreach (DataRow row in dt1.Rows) 
{ 
    if (row.RowState == DataRowState.Modified) 
    { 
     bool isUnchanged = true; 
     foreach (DataColumn col in dt1.Columns) 
     { 
      if (!row[col.ColumnName].Equals(row[col.ColumnName, DataRowVersion.Original])) 
      { 
       isUnchanged = false; 
       break; 
      } 
     } 

     if (isUnchanged) 
     { 
      row.RejectChanges(); 
     } 
    } 
} 

これが行われた後、あなたはdt1.AcceptChanges()を呼び出すことができます。

+0

ありがとうございます、主キーが設定されるように更新しました。今、dt1とdt2がID = 100と同じエントリーを持つと仮定します。 dt2がdt1にマージされると、それは「変更済み」とマークされます。データが同じ場合、これらの "変更"を無視する方法はありますか? – John

+0

@Johnは私の編集の解決策を見ています。 –

関連する問題