Architect's Log

I'm a Cloud Architect. I'm highly motivated to reduce toils with driving DevOps.

【.NET】DataTableの内容を比較する

QA@ITに投稿してみました。

以下のDataTable1とDataTable2を比較して不一致分を表示したいのですが
グルグルとループさせて1つずつ比較するぐらいしか方法を思いつきませんでした。
何かもっとスマートな方法はないでしょうか?

・DataTable1 … Oracleからの抽出結果を格納
・DataTable2 … system iからの抽出結果を格納
・不一致分をdatagridに表示
・.net FrameWork 2.0以上

よろしくお願いいたします。


C#6.0でLinqを使って書いてみました。

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;

namespace LinqExcept {
    class Program {
        static void Main(string[] args) {
            using (DataTable dt1 = new DataTable())
            using (DataTable dt2 = new DataTable()) {
                dt1.Columns.Add("ID", typeof(int));
                dt1.Columns.Add("Name", typeof(string));

                dt1.Rows.Add(1, "佐藤");
                dt1.Rows.Add(2, "鈴木");
                dt1.Rows.Add(3, "渡辺");
                dt1.Rows.Add(4, "田中");

                dt2.Columns.Add("ID", typeof(int));
                dt2.Columns.Add("Name", typeof(string));

                dt2.Rows.Add(1, "鈴木");
                dt2.Rows.Add(2, "佐藤");
                dt2.Rows.Add(3, "渡部");
                dt2.Rows.Add(4, "田中");

                var query = dt1.AsEnumerable().Except(dt2.AsEnumerable(), new DataRowComparer());

                // ID=1 Name=佐藤
                // ID=2 Name=鈴木
                // ID=3 Name=渡辺
                query.ToList().ForEach(
                    r => Console.WriteLine(string.Format("ID={0} Name={1}", r["ID"], r["Name"])));
            }

            Console.ReadKey();
        }
    }

    class DataRowComparer : IEqualityComparer<DataRow> {
        public bool Equals(DataRow x, DataRow y) {
            if (object.ReferenceEquals(x, y))
                return true;

            if (x == null)
                return false;

            if (y == null)
                return false;

            bool equal = ((int) x["ID"] == (int) y["ID"]) && (x["Name"] == y["Name"]);
            return equal;
        }

        public int GetHashCode(DataRow obj) {
            if (obj == null)
                return 0;

            // C#5.0以前
            // int idHashCode = obj["ID"] == null ? 0 : obj["ID"].GetHashCode();
            // int nameHashCode = obj["Name"] == null ? 0 : obj["Name"].GetHashCode();
            int idHashCode = obj["ID"]?.GetHashCode() ?? 0;
            int nameHashCode = obj["Name"]?.GetHashCode() ?? 0;
            return idHashCode ^ nameHashCode;        
        }
    }
}