在程序中,往往会遇到一些小情况,就是数据库取出来的时候为了方便直接将数据通过存储在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(@"XMLStudents")); var list= dt.ToEntities<Student>();
调试会发现。StudentID在实体中是Int32类型。而反序列化出来的是String类型。关于此处的完美解决方案,希望大家能够指点。此处美中不足。