Reputation: 3028
I have created one function for converting List to Datatble. But I need to customize this function so that method will have additional parameter of List properties(eg:Name,Age) that are only to be considered while converting to datatble. Also I want to maintain the order of columns same as what it is their in Property list. Example - I am passing List (Customer having different properties Name,Age,DOB,Place) and list of Properties that to be converted ie List(Name,Age).Also I want to rename Datatable Column Header of Name as "Person Name " and Age as "Person Age".Can anyone help how can I achieve this.Also you can propose better logic to achieve the requirement.
public DataTable ToDataTable<T>(List<T> items)
{
DataTable dataTable = new DataTable(typeof(T).Name);
PropertyInfo[] Props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo prop in Props)
{
//Setting column names as Property names
dataTable.Columns.Add(prop.Name);
}
foreach (T item in items)
{
var values = new object[Props.Length];
for (int i = 0; i < Props.Length; i++)
{
values[i] = Props[i].GetValue(item, null);
}
dataTable.Rows.Add(values);
}
return dataTable;
}
Upvotes: 0
Views: 3542
Reputation: 131364
The MoreLINQ package already has a ToDataTable method that works on any IEnumerable<T>
. You can use LINQ's Select
to shape the data in any way you want and then convert it to a DataTable with ToDataTable
:
var table= customers.Select (customer => new {
customer.Name,
customer.DOB,
Age=(DateTime.Today-customer.DOB).Days/365
})
.ToDataTable();
ToDataTable
has an overload that allows you specify the properties to use through expressions:
var table=customers.ToDataTable(new[]{ c=>c.Name, c=>c.DOB });
And another that allows you to fill an already created and configured table. From one of the unit tests:
var dt = new DataTable();
var columns = dt.Columns;
columns.Add("Column1", typeof(int));
columns.Add("Value", typeof(string));
columns.Add("Column3", typeof(int));
columns.Add("Name", typeof(string));
var vars = Environment.GetEnvironmentVariables()
.Cast<DictionaryEntry>()
.ToArray();
vars.Select(e => new { Name = e.Key.ToString(),
Value = e.Value.ToString() })
.ToDataTable(dt, e => e.Name, e => e.Value);
Columns with spaces
You can change DataColumn.ColumnName afterwards but perhaps a better solution would be to set the Caption property. The default value of Caption
is the ColumnName
. A name with spaces is almost certainly meant for display purposes.
It's better to leave ColumnName
unmodified so you can identify columns by name, and change the display caption to whatever you need.
For example:
var personColumns=new[]{"Name","Age"};
foreach(DataColumn column in table.Columns)
{
column.Caption = $"Person {column.ColumnName}";
}
Upvotes: 1
Reputation: 136104
I would suggest you change your merthod to take a Dictionary<string,string>
which acts as a mapping from the properties you're interested in to their mapped name. Then use this to filter the properties from the object and build the data table
public static DataTable ToDataTable<T>(List<T> items, Dictionary<string,string> properties)
{
DataTable dataTable = new DataTable(typeof(T).Name);
PropertyInfo[] Props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(p => properties.ContainsKey(p.Name)).ToArray();
foreach (PropertyInfo prop in Props)
{
//Setting column names as Property names
dataTable.Columns.Add(properties[prop.Name]);
}
foreach (T item in items)
{
var values = new object[Props.Length];
for (int i = 0; i < Props.Length; i++)
{
values[i] = Props[i].GetValue(item, null);
}
dataTable.Rows.Add(values);
}
return dataTable;
}
You can then do something like this:
var props = new Dictionary<string,string>
{
["Name"] = "Person Name",
["Age"] = "Person Age"
};
var dt = ToDataTable(people, props);
Live example: https://dotnetfiddle.net/7XkJvV
Upvotes: 1