Reputation: 22715
I have a datatable like this
Name| Value
----|------
NA | VA
NB | VB
NC | VC1
NC | VC2
ND | VD1
ND | VD2
and a class like this
Class NVMapping {
List<string> NC { get; set; }
List<string> ND { get; set; }
string NA { get; set; }
string NB { get; set; }
}
How to use linq or other way to transfer the datatable to this type ?
I think I need to emphasize one thing here. This kinda mapping will be a lot in my application.
Somehow I think using reflection can make this function be generic to handle all these kinda mapping.
So if possible, I would prefer a generic function like using reflection to achieve this.
If possible, it will even better just transfering datatable into an object like above transformation.
Thanks !
Upvotes: 0
Views: 3626
Reputation: 3390
May I suggest writing a generic method that uses reflection. The following method uses reflection to populate a class's public properties from a DataRow in a DataTable (or a List<> of classes, one from each DataRow in the DataTable) where the ColumnName matches the name of the public property in the class exactly (case-sensitive). If the DataTable has extra columns that don't match up to a property in the class, they are ignored. If the DataTable is missing columns to match a class property, that property is ignored and left at the default value for that type (since it is a property).
public static IList<T> DatatableToClass<T>(DataTable Table) where T : class, new() { if (!Helper.IsValidDatatable(Table)) return new List<T>(); Type classType = typeof(T); IList<PropertyInfo> propertyList = classType.GetProperties(); // Parameter class has no public properties. if (propertyList.Count == 0) return new List<T>(); List<string> columnNames = Table.Columns.Cast<DataColumn>().Select(column => column.ColumnName).ToList(); List<T> result = new List<T>(); try { foreach (DataRow row in Table.Rows) { T classObject = new T(); foreach (PropertyInfo property in propertyList) { if (property != null && property.CanWrite) // Make sure property isn't read only { if (columnNames.Contains(property.Name)) // If property is a column name { if (row[property.Name] != System.DBNull.Value) // Don't copy over DBNull { object propertyValue = System.Convert.ChangeType( row[property.Name], property.PropertyType ); property.SetValue(classObject, propertyValue, null); } } } } result.Add(classObject); } return result; } catch { return new List<T>(); } }
If you interested in going the other way, and fill out a DataTable from a class's public properties, I cover that and more on my C# blog, CSharpProgramming.tips/Class-to-DataTable
Upvotes: 9
Reputation: 460158
Here it is:
IEnumerable<DataRow> rows = table.AsEnumerable();
string naValue = null;
var naRow = rows.FirstOrDefault(r => r.Field<string>("Name") == "NA");
if(naRow != null)
naValue = naRow.Field<string>("Value");
string nbValue = null;
var nbRow = rows.FirstOrDefault(r => r.Field<string>("Name") == "NB");
if(nbRow != null)
nbValue = nbRow.Field<string>("Value");
NVMapping map = new NVMapping {
NC = rows.Where(r => r.Field<string>("Name") == "NC")
.Select(r => r.Field<string>("Value")).ToList(),
ND = rows.Where(r => r.Field<string>("Name") == "ND")
.Select(r => r.Field<string>("Value")).ToList(),
NA = naValue,
NB = nbValue
};
Upvotes: 3