在程序中,往往會遇到一些小情況,就是數據庫取出來的時候為了方便直接將數據通過存儲在DataSet或DataTable中,這樣做的一個后果是在日后的的對數據進行”細“操作時,就發現它可能沒有List<T>那么方便,而另外一些時候(比如使用SqlBulkCopy的時候)使用DataTable會比較方便。於是我們就會想寫一個專門的它們之間的互操作來使我們在操作它們的時候變得不那么復雜。網上關於它們之間的互操作的解決方法蠻多。這里參考了下它們,結合自己實際應用,寫了一個它們之間互操,代碼如下:
public static class DataTableEntityInteroperate
{ /// <summary> /// List<T> to DataTable /// </summary> /// <typeparam name="T">Entity</typeparam> /// <param name="entities">Entities</param> /// <returns>DataTable</returns> internal static DataTable ToDataTable<T>(this List<T> entities) where T : class,new() { //IsNull return if (null == entities || entities.Count == 0) return null; //Initial Columns DataTable dt = new DataTable(); PropertyInfo[] pArray = typeof(T).GetProperties(); try { Array.ForEach<PropertyInfo>(pArray, p => { dt.Columns.Add(p.Name); }); entities.ForEach(t => {
//Initial Rows
DataRow dr=dt.NewRow(); int i = 0; Array.ForEach<PropertyInfo>(pArray, p => { if (dt.Columns.Contains(p.Name)) dr[i] = p.GetValue(t); //Assigned to each column }); i++;
dt.Rows.Add(dr);//備忘,測試不仔細。 }); return dt; } catch (Exception) { throw; } } /// <summary> /// DataTable to Entities /// </summary> /// <typeparam name="T">Entity</typeparam> /// <param name="dt">DataTable</param> /// <returns>List<T</returns> internal static List<T> ToEntities<T>(this DataTable dt)/*必須來在於數據庫來自於文件可能存在問題*/ where T : class,new() { //IsNullable if (null == dt || dt.Rows.Count == 0) return null; //Initial Entities List<T> entities = new List<T>(); try { foreach (DataRow row in dt.Rows) { PropertyInfo[] pArray = typeof(T).GetProperties(); T entity = new T(); Array.ForEach<PropertyInfo>(pArray, p => {
if(row[p.Name]!=DBNull.Value) p.SetValue(entity, row[p.Name], null); }); entities.Add(entity); } return entities; } catch (Exception) { throw; } } }
關乎ToEntities擴展方法的備注:這個方法適合的是DataTable是由數據庫直接返回的情況。如果DataTable數據是由Xml文件直接反序列化而來。就要在初始化DataTable時候,對DaTable的列對應在數據實體中的類型進行指定。
關於DataTable數據是直接從文件而來的備注:
public class XmlHelper { /// <summary> /// 將XML轉換為DATATABLE /// </summary> /// <param name="FileURL"></param> /// <returns></returns> public static DataTable XmlAnalysisArray(string filepath) { try { DataSet ds = new DataSet(); ds.ReadXml(filepath); return ds.Tables[0]; } catch (Exception ex) { throw ex; } } /// <summary> /// 將DATASET 轉換為 XML /// </summary> /// <param name="FileURL"></param> /// <returns></returns> public static void DatasetConversionXML(DataSet ds, string FileURL) { try { ds.WriteXml(FileURL); } catch (Exception ex) { throw ex; } } /// <summary> /// Xml序列化 /// </summary> /// <typeparam name="T">對象的類型</typeparam> /// <param name="t">序列化對象實例</param> /// <param name="filePath">文件路徑</param> public static void XmlSerializer<T>(List<T> t, string filePath) { XmlSerializer xmlSerializer = new XmlSerializer(typeof(List<T>)); StreamWriter writer = new StreamWriter(filePath); //將s對象寫入到指定的IO流文件中 try { xmlSerializer.Serialize(writer, t); } catch (Exception) { //errr message } finally { writer.Close(); } } /// <summary> /// Xml反序列化 /// </summary> /// <typeparam name="T">對象類型</typeparam> /// <param name="t">對象實例</param> public static List<T> XmlDeserialize<T>(List<T> t, string filePath) //必須是經過同樣的過程反序列化好的文件 { XmlSerializer mySerializer = new XmlSerializer(typeof(List<T>)); FileStream myFileStream = null; if (File.Exists(filePath)) //檢查文件是否存在 { try { myFileStream = new FileStream(filePath, FileMode.Open); t = (List<T>)mySerializer.Deserialize(myFileStream); } catch (FileNotFoundException) { //File not Found } catch (Exception) { //the other error message } finally { myFileStream.Close(); } } return t; } }
Xml文件是直接從DataTable序列化而成,而不是由List<T>序列化而來。
做如下調用則會拋出異常(異常處理已經加上,謝謝Mainz)
var dt = XmlHelper.XmlAnalysisArray(Server.MapPath(@"XML\Students")); var list= dt.ToEntities<Student>();
調試會發現。StudentID在實體中是Int32類型。而反序列化出來的是String類型。關於此處的完美解決方案,希望大家能夠指點。此處美中不足。

代碼下載