/// <summary> /// Convert the "DataTable" object to the "Entity List" with target Type /// </summary> /// <typeparam name="T">target type</typeparam> /// <param name="dt">DateTable object</param> /// <returns>a list of result</returns> public static IList <T> ToList <T>(this DataTable dt) where T : class { var list = new List <T>(); //check is it NULL if (dt == null) { return(list); } //get Properties var plist = new List <PropertyInfo>(typeof(T).GetProperties()); //get dic<Propertie,ColumnAttribute> var pdic_col_raw = LinqSearchAlternate.Select(plist, (o => new InformationForPropertyInfo { Properties = o, ColumnAttribute = Attribute.GetCustomAttribute(o, typeof(ColumnAttribute)) as ColumnAttribute })); var pdic_col = LinqSearchAlternate.ToDictionary(pdic_col_raw, (o => o.Properties)); //get dic<Propertie,IgnoreAttribute> var pdic_Ign_raw = LinqSearchAlternate.Select(plist, (o => new { Properties = o, IgnoreAttribute = Attribute.GetCustomAttribute(o, typeof(IgnoreAttribute)) as IgnoreAttribute })); var pdic_Ign = LinqSearchAlternate.ToDictionary(pdic_Ign_raw, (o => o.Properties)); //loop to convert Properties and Values foreach (DataRow item in dt.Rows) { try { T current = Activator.CreateInstance <T>(); for (int i = 0; i < dt.Columns.Count; i++) { PropertyInfo info = null; #region Get Target Property /* You can overwrite this folded code, in order to simply combine your logic. * For example, just use: * info = plist.Find(p => p.Name == dt.Columns[i].ColumnName); */ //Richer logic : info = LinqSearchAlternate.FirstOrDefault(plist, (o => { var colAtt = pdic_col[o].ColumnAttribute; if (colAtt != null) { /* own ColumnAttribute, then use the rule from ColumnAttribute */ bool ignoreCase = !colAtt.CaseSensitiveToMatchedName; return(String.Compare(dt.Columns[i].ColumnName, colAtt.MatchedName, ignoreCase) == 0); } else { /* Not own ColumnAttribute, then check "CaseSensitive" rule from EntityConversionDefaultSettings and "MatchedName" from "Same as DataColumn::ColumnName" */ bool ignoreCase = !EntityConversionDefaultSettings.CaseSensitiveToColumnName; return(String.Compare(dt.Columns[i].ColumnName, o.Name, ignoreCase) == 0); } })); #endregion try { if (info != null && info.CanWrite) { #region Ignore this column Or Not if (pdic_Ign[info].IgnoreAttribute != null) { continue; } #endregion object rawValue = item[i]; //Set Value if (rawValue != null && !Convert.IsDBNull(rawValue)) { //Support Nullable Type Type safeType = Nullable.GetUnderlyingType(info.PropertyType) ?? info.PropertyType; //Support Enum: if (safeType.IsEnum) { info.SetValue(current, Enum.Parse(safeType, rawValue.ToString()), null); continue; } //Normal: info.SetValue(current, Convert.ChangeType(rawValue, safeType), null); } } } catch (Exception ex) { System.Diagnostics.Trace.WriteLine(String.Format("## [MicroDBHelperExpansionPack.EntityConversion] System.Data.ADOExtensions::ToList<T> found an exception when convert [{0}] property, message is {1} ", info.Name, ex.Message)); continue; } } list.Add(current); } catch (Exception) { continue; } } //return all result return(list); }
/// <summary> /// Convert the "Entity List" to the "DataTable" object /// </summary> /// <typeparam name="T">target type</typeparam> /// <param name="list">Entity List</param> /// <returns>a DataTable Object</returns> public static DataTable ToDatatable <T>(this IEnumerable <T> list) where T : class { //get Properties var plist = new List <PropertyInfo>(typeof(T).GetProperties()); //get dic<Propertie,ColumnAttribute> var pdic_col_raw = LinqSearchAlternate.Select(plist, (o => new InformationForPropertyInfo { Properties = o, ColumnAttribute = Attribute.GetCustomAttribute(o, typeof(ColumnAttribute)) as ColumnAttribute })); var pdic_col = LinqSearchAlternate.ToDictionary(pdic_col_raw, (o => o.Properties)); //get dic<Propertie,IgnoreAttribute> var pdic_Ign_raw = LinqSearchAlternate.Select(plist, (o => new { Properties = o, IgnoreAttribute = Attribute.GetCustomAttribute(o, typeof(IgnoreAttribute)) as IgnoreAttribute })); var pdic_Ign = LinqSearchAlternate.ToDictionary(pdic_Ign_raw, (o => o.Properties)); var dt = new DataTable(); dt.CaseSensitive = true; #region deal Columns var dic_colNames = new Dictionary <PropertyInfo, string>(); { var colNamesCache = new List <string>(); foreach (var prop in plist) { #region Get Target Property /* You can overwrite this folded code, in order to simply combine your logic. * For example, just use: * dt.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType); */ //Richer logic : #region Ignore this column Or Not if (pdic_Ign[prop].IgnoreAttribute != null) { continue; } #endregion string currentColumnName; bool ignoreCase; { var colAtt = pdic_col[prop].ColumnAttribute; if (colAtt != null) { /* own ColumnAttribute, then use the rule from ColumnAttribute */ ignoreCase = !colAtt.CaseSensitiveToMatchedName; currentColumnName = colAtt.MatchedName; } else { /* Not own ColumnAttribute, then check "CaseSensitive" rule from EntityConversionDefaultSettings and "MatchedName" from "Property" */ ignoreCase = !EntityConversionDefaultSettings.CaseSensitiveToColumnName; currentColumnName = prop.Name; } } //##Add new Column to Datatable when it's not already exist #if NET20 || NET35 || NET40 bool isMatch; if (ignoreCase) { isMatch = colNamesCache.Contains(currentColumnName); } else { isMatch = colNamesCache.FindIndex(x => x.Equals(currentColumnName, StringComparison.OrdinalIgnoreCase)) != -1; } if (isMatch == false) #else if (colNamesCache.Contains(currentColumnName, ignoreCase ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal) == false) #endif { colNamesCache.Add(currentColumnName); dic_colNames[prop] = currentColumnName; dt.Columns.Add(currentColumnName, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType); } #endregion } } #endregion #region deal Rows //#check is it NULL if (list == null) { return(dt); } foreach (T item in list) { List <object> values = new List <object>(); foreach (var prop in dic_colNames.Keys) { //Set Value values.Add(prop.GetValue(item, null) ?? DBNull.Value); } dt.Rows.Add(values.ToArray()); } #endregion //#return all result return(dt); }