背景近期寫了個module係去食user一個upload的Excel,再將D data process過後放入DB。
基於flexibility及re-usability,我就寫了個C# function將個Excel transform 落 System.Data.DataSet入面,個logic大概係咁:
- 用OleDB開個connection落個Excel到
- 用GetSchema("Tables")去食個Excel個list of available worksheet
- 憑Step 2 return回來的list去用 SELECT * FROM "worksheet name" 去將每張worksheet的全部data放入dataset入面
本來試就好地地,到個system上了production,user真係用的時候(又一個缺乏user合作UAT的結果),就發現無法process 個uploaded excel。
GetSchema("Tables")請求user提供那個excel後,行debug mode看,才發現當我用GetSchema("Tables")去get個list of worksheet時,有很多很多不知名table走了出來,Google後發現該是一些user於excel行filter後留下來的working temp worksheet。不過,基於MSDN並無提及到對個Excel 用GetSchema("Tables") return 回來的data有任何詳細的解釋,結果唯有在各forum的提示下,用一個不大安全的方法去做個workaround。
Solution首先,經GetSchema("Tables")而穫得的table 名是在worksheet 名加上"$",在各Forum提示下,這類working temp worksheet個table name的pattern是 worksheet name + "$" + others (like GUID),因此,我就假設,逢table name最尾一個"$" 後有其他字串的話,就會ignore有關table,因此就即是:
// Get list of available worksheets by using GetSchema
DataTable dtSchemaInfo = conn.GetSchema("Tables");
foreach (DataRow drSchemaInfo in dtSchemaInfo.Rows)
{
if (drSchemaInfo["TABLE_NAME"] is string && Convert.ToString(drSchemaInfo["TABLE_NAME"]) != null && Convert.ToString(drSchemaInfo["TABLE_NAME"]) != string.Empty)
{
// Only handle table ended with $ or $'
string tableName = Convert.ToString(drSchemaInfo["TABLE_NAME"]);
if(!(tableName.LastIndexOf("$'") > 0 && tableName.Substring(tableName.LastIndexOf("$'") + 2) == string.Empty) &&
!(tableName.LastIndexOf("$") > 0 && tableName.Substring(tableName.LastIndexOf("$") + 1) == string.Empty))
continue;
// Select all data from the worksheet
DbDataAdapter adapter = factory.CreateDataAdapter();
adapter.SelectCommand = conn.CreateCommand();
adapter.SelectCommand.CommandText = string.Format(TEMPLATE_SQL_GET_ALL_DATA, tableName);
try
{
adapter.Fill(_dsExcel, tableName);
}
catch
{
;
}
finally
{
adapter.Dispose();
}
}
}
最後,本人coding經驗尚未算深,如有錯漏,敬請指正~