经常有对两个DataTable进行比较的需求,比如通过C# winform或者 asp.net 将Excel导入到数据库的过程中,
可能需要将现有数据从数据库里拿出来缓存到DataTable(清表重新插入不在此讨论范围),同时将需要导入的Excel的数据解析成DataTable,然后进行一下比对,确认是添加还是修改。
比较的过程中,可能只比较一个字段,也可能比较多个,甚至能比较不同的字段
(多字段比较时,是AND的关系,同时满足认为是相同记录)
在要导入的Excel生成的DataTable里增加一个Flag字段,保存比较的结果(表示是否存在此记录)。
class Program
{
//相同的字段名生成比较委托列表
static List<Func<DataRow, DataRow, bool>> GenerateCheck(List<string> checkColumns)
{
var checkConditons = new List<Func<DataRow, DataRow, bool>>();
foreach (string column in checkColumns)
{
checkConditons.Add((s, t) => s[column].ToString().Equals(t[column].ToString()));
}
return checkConditons;
}
//不同的字段名生成比较委托列表,用Tuple映射不同的字段名
static List<Func<DataRow, DataRow, bool>> GenerateCheck(List<Tuple<string, string>> checkColumns)
{
var checkConditons = new List<Func<DataRow, DataRow, bool>>();
foreach (var column in checkColumns)
{
checkConditons.Add((s, t) => s[column.Item1].ToString().Equals(t[column.Item2].ToString()));
}
return checkConditons;
}
//要导入的数据
static DataTable GetSource()
{
DataTable target = new DataTable();
target.Columns.Add("ID", typeof(Int32));
target.Columns.Add("Name", typeof(String));
target.Columns.Add("Age", typeof(Int32));
target.Columns.Add("Flag", typeof(Int32)); //增加一个Flag字段保存结果
target.Rows.Add(new object[] { 1, "张三", 20, 0 });
target.Rows.Add(new object[] { 2, "李四", 45, 0 });
target.Rows.Add(new object[] { 3, "王五", 40, 0 });
target.Rows.Add(new object[] { 4, "马六", 21, 0 });
target.Rows.Add(new object[] { 20, "张三", 1, 0 });
target.Rows.Add(new object[] { 25, "李四", 2, 0 });
return target;
}
//原数据库数据
static DataTable GetTarget()
{
DataTable source = new DataTable();
source.Columns.Add("ID", typeof(Int32));
source.Columns.Add("Name", typeof(String));
source.Columns.Add("Age", typeof(Int32));
source.Rows.Add(new object[] { 1, "张三", 20 });
source.Rows.Add(new object[] { 2, "李四", 25 });
source.Rows.Add(new object[] { 3, "王五", 21 });
source.Rows.Add(new object[] { 4, "马六", 21 });
return source;
}
//相同的字段名
static void SameColumnName()
{
DataTable source = GetSource();
DataTable target = GetTarget();
var checkColumns = new List<string> { "ID", "Name", "Age" };
var checkCondtions = GenerateCheck(checkColumns);
foreach (DataRow s in source.Rows)
{
var result = target.AsEnumerable().Where(t => checkCondtions.All(check => check(s, t)));
if (result.Any())
{
s["Flag"] = 1;
}
}
source.AsEnumerable().Where(item => item["Flag"].ToString() == "1").ToList().ForEach(item => Console.WriteLine(" " + item["Name"].ToString()));
}
//不同的字段名
static void DiffrentColumnName()
{
DataTable source = GetSource();
DataTable target = GetTarget();
var checkColumns = new List<Tuple<string, string>>();
checkColumns.Add(Tuple.Create("ID", "Age"));
checkColumns.Add(Tuple.Create("Name", "Name"));
var checkCondtions = GenerateCheck(checkColumns);
foreach (DataRow s in source.Rows)
{
var result = target.AsEnumerable().Where(t => checkCondtions.All(check => check(s, t)));
if (result.Any())
{
s["Flag"] = 1;
}
}
source.AsEnumerable().Where(item => item["Flag"].ToString() == "1").ToList().ForEach(item => Console.WriteLine(" " + item["Name"].ToString()));
}
static void Main(string[] args)
{
Console.WriteLine(" ");
SameColumnName(); //"ID", "Name", "Age" 同时满足的只有 张三 马六 两条记录
Console.WriteLine("==========================");
DiffrentColumnName();//"Name"相同,源数据的ID和目标数据的Age相等的只有 张三 李四 两条记录
Console.ReadLine();
}
}
网友评论