我正在开发一个可以识别两个文件之间差异的应用程序。输入文件可以是excel,delimitted或固定宽度,因此我构建应用程序以将源文件转换为可以通过LINQ查询的标准数据表。应用程序的一部分需要根据提供的ID列识别重复记录,以检查其他字段中的更改。出于某种原因,我的LINQ语句不喜欢我的Delimited ToDataTable()函数提供的数据,并且需要将近15分钟才能完成。如果我将Delimited文件保存为Excel并通过Excel ToDataTable()运行它,一切都会在大约10秒内完成。
Excel ToDataTable():
public override DataTable ToDataTable()
{
DataTable dt = new DataTable();
using (OleDbConnection con = new OleDbConnection(ConnectionString))
{
con.Open();
DataTable dtSchema = con.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
OleDbDataAdapter adapter = new OleDbDataAdapter("SELECT * FROM [" + Sheets[0].SheetName + "]", con);
adapter.Fill(dt);
}
return dt;
}
分隔ToDataTable():
public override DataTable ToDataTable()
{
DataTable dt = new DataTable();
if (HasHeaders)
{
string[] headers = Parser.ReadFields();
for (int i = 0; i < headers.Length; i++)
dt.Columns.Add(headers[i]);
}
while (!Parser.EndOfData)
dt.Rows.Add(Parser.ReadFields());
return dt;
}
因此,该过程读入两个文件(当前和历史),将它们转换为DataTable,然后运行下面的LINQ查询:
var duplicateIDs = from ht in HistoryTable.AsEnumerable()
join ct in CurrentTable.AsEnumerable() on ht.Field<object>(IndexName) equals ct.Field<object>(IndexName)
select new { MatchedID = ht[IndexName] };
var duplicateRecords = (from dups in duplicateIDs
join currentFields in CurrentTable.AsEnumerable() on dups.MatchedID equals currentFields.Field<object>(IndexName)
select new { Fields = currentFields, SortOrder = 1 })
.Union
(from dups in duplicateIDs
join historyFields in HistoryTable.AsEnumerable() on dups.MatchedID equals historyFields.Field<object>(IndexName)
select new { Fields = historyFields, SortOrder = 2 })
.OrderBy(o => o.Fields.Field<object>(IndexName))
.ThenBy(o => o.SortOrder);
我可以在没有任何问题的情况下迭代我的duplicateID,但是当我在duplicateRecords上为每个循环打开一个时,所有内容都会挂起来进行更大的分隔文件。两种类型的文件都对它们的表进行索引,因此它们之间的唯一区别就是它们的初始化方式。
更新#1 感谢NetMage指出我的一些低效率。我没有意识到我在第二个语句中有效地运行了第一个语句。你建议远离匿名类型,但我发现我可以巧妙地将两个记录封装在一个匿名对象中并完全摆脱第二个语句:
var duplicates = from ht in HistoryTable.AsEnumerable()
join ct in CurrentTable.AsEnumerable() on ht.Field<object>(IndexName) equals ct.Field<object>(IndexName)
select new { History = ht.ItemArray, Current = ct.ItemArray};
这可以在一两秒内运行!