Reputation: 1
I am trying to convert a List
to a datatable
with an extension method. Implementation is:
Extension method
public static class list2Dt
{
public static DataTable ToDataTable<T>(List<T> items)
{
DataTable dataTable = new DataTable(typeof(T).Name);
//Get all the properties
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++)
{
//inserting property values to datatable rows
values[i] = Props[i].GetValue(item, null);
}
dataTable.Rows.Add(values);
}
//put a breakpoint here and check datatable
return dataTable;
}
}
Controller
var noDups = firstTable.AsEnumerable()
.GroupBy(d => new
{
name = d.Field<string>("name"),
date = d.Field<string>("date")
})
.Where(d => d.Count() > 1)
.Select(d => d.First())
.ToList();
DataTable secondTable = new DataTable();
secondTable.Columns.Add("name", typeof(string));
secondTable.Columns.Add("date", typeof(string));
secondTable.Columns.Add("clockIn", typeof(string));
secondTable.Columns.Add("clockOut", typeof(string));
secondTable = list2Dt.ToDataTable(noDups);
I am getting this following error:
An exception of type 'System.Data.DuplicateNameException' occurred in System.Data.dll but was not handled in user code
Additional information: A column named 'Item' already belongs to this DataTable.
Above error is raised on line:
dataTable.Columns.Add(prop.Name);
Can someone find where problem lies.
Upvotes: 4
Views: 14398
Reputation: 136204
Your ToDataTable
method is expecting a list of objects - most likely a list of simple DTOs or similar.
You are passing it a list of DataRow
instances, of which that class has multiple overloads of property Item
which means when you're trying to build up the new DataTable
it will try to add multiple columns with the name Item
which is invalid in a DataTable
.
On way around this is to project noDups
to a new object, rather than retain the DataRow
:
public class MyClass
{
public string Name{get;set;}
public string Date{get;set;}
}
var noDups = firstTable.AsEnumerable()
.GroupBy(d => new
{
name = d.Field<string>("name"),
date = d.Field<string>("date")
})
.Where(d => d.Count() > 1)
.Select(d => {
var first = d.First();
return new MyClass()
{
Name = (string)first["name"],
Date = (string)first["date"]
}
})
.ToList();
Upvotes: 3