Using C#, how-to convert a dictionary to a datatable?
There is an example on how-to convert a list into a datatable at
Convert generic List/Enumerable to DataTable?
I started working on this, since 2019-12-17.
And, I have searched, Google, Stackoverflow, and Microsoft websites.
public static DataTable DictionaryToDataTable<T>(this IDictionary<K, V> data)
{
PropertyDescriptorCollection propertiesK = TypeDescriptor.GetProperties(typeof(K));
PropertyDescriptorCollection propertiesV = TypeDescriptor.GetProperties(typeof(V));
DataTable table = new DataTable();
foreach (PropertyDescriptor prop in propertiesK)
table.Columns.Add(prop.Name,
Nullable.GetUnderlyingType(prop.PropertyType)
?? prop.PropertyType);
foreach (PropertyDescriptor prop in propertiesV)
table.Columns.Add
(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType)
?? prop.PropertyType);
foreach(KeyValuePair<K, V> item in data)
{
DataRow row = table.NewRow();
foreach (PropertyDescriptor prop in propertiesK)
row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
foreach (PropertyDescriptor prop in propertiesV)
row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
table.Rows.Add(row);
}
return table;
}
Type ex = typeof(InformationInTransit.ProcessLogic.DataTableHelper);
MethodInfo mi = ex.GetMethod("DictionaryToDataTable");
MethodInfo miConstructed =
mi.MakeGenericMethod
(
typeof
(
Dictionary
<
String,
InformationInTransit.ProcessLogic.Exact.Participation
>
)
);
object[] args = {result};
DataTable dataTable = (DataTable) miConstructed.Invoke
(
null,
args
);
one attempt would simply be something like this:
Dictionary<int,int> dictionary=new Dictionary<int, int>();
DataTable dt=new DataTable();
dt.Columns.Add("Key", typeof(int));
dt.Columns.Add("Val", typeof(int));
foreach (var item in dictionary)
{
DataRow dr = dt.NewRow();
dr["Key"] = item.Key;
dr["Val"] = item.Value;
dt.Rows.Add(dr);
}
once try this: (nameList and globalVariable are list)
var dictionary = nameList.Zip(globalVariable, (k, v) => new { Key = k, Value = v })
.ToDictionary(x => x.Key, x => x.Value);
DataTable dt = new DataTable();
dt.Columns.Add("Variable names", typeof(string));
dt.Columns.Add("Variable values", typeof(string));
foreach (var pair in dictionary)
{
DataRow dr = dt.NewRow();
dr["Variable names"] = pair.Key;
dr["Variable values"] = pair.Value;
dt.Rows.Add(dr);
}
You might find it more convenient to write this as a generic for a Dictionary of any types. As a further refinement, you can make it as an Extension Method. Something like this:
public static class Extensions
{
public static DataTable ConvertToDataTable<TKey, TValue>(this Dictionary<TKey, TValue> data, string colName1, string colName2)
{
var dT = new DataTable();
dT.Columns.Add(colName1, typeof(TKey));
dT.Columns.Add(colName2, typeof(TValue));
foreach (var kVP in data)
{
var nR = dT.NewRow();
nR[0] = kVP.Key;
nR[1] = kVP.Value;
dT.Rows.Add(nR);
}
return dT;
}
}
It can be called simply by
var dT = myDictionary.ConvertToDataTable("keyColumnName", "valueColumnName");
Related
I am working in C# and .net core. I have an object which consist of multiple lists of strings and i want to convert this object into datatable.
I have tried this code, but it failed:
public static DataTable ObjectToData(object o)
{
DataTable dt = new DataTable("OutputData");
DataRow dr = dt.NewRow();
dt.Rows.Add(dr);
o.GetType().GetProperties().ToList().ForEach(f =>
{
try
{
f.GetValue(o, null);
dt.Columns.Add(f.Name, typeof(string));
dt.Rows[0][f.Name] = f.GetValue(o, null);
}
catch { }
});
return dt;
}
Generic convertion:
public DataTable ListToDataTable<T>(IList<T> data)
{
PropertyDescriptorCollection properties =
TypeDescriptor.GetProperties(typeof(T));
DataTable table = new DataTable();
foreach (PropertyDescriptor prop in properties)
table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
foreach (T item in data)
{
DataRow row = table.NewRow();
foreach (PropertyDescriptor prop in properties)
{
row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
}
table.Rows.Add(row);
}
return table;
}
your problem is that you add the DataRow at the start of it. what you have to do is instanciate it, and then assign the values and finally add it to the datatable.
Also change the add information into the row for the next dr[f.Name] = f.GetValue(o, null);
here is the code:
public static DataTable ObjectToData(object o)
{
DataTable dt = new DataTable("OutputData");
DataRow dr = dt.NewRow();
o.GetType().GetProperties().ToList().ForEach(f =>
{
try
{
f.GetValue(o, null);
dt.Columns.Add(f.Name, typeof(string));
dr[f.Name] = f.GetValue(o, null);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
});
dt.Rows.Add(dr);
return dt;
}
you can find an example here https://dotnetfiddle.net/EeegHg
I currently have this code, I'm aware how to print out the rows, but I can't figure out how to get my column headers? I don't want to use the solution I had that I commented out because I want to make the code generic so that I can use it for other lists too.
static DataTable ConvertListToDataTable(List<List<string>> list)
{
// New table.
DataTable table = new DataTable();
/* table.Columns.Add("Employee ID");
table.Columns.Add("First Name");
table.Columns.Add("Last Name");
table.Columns.Add("Job Title");
table.Columns.Add("Address");
table.Columns.Add("City");
*/
foreach(List<string> row in list) {
table.Rows.Add(row.ToArray());
}
return table;
}
It's impossible to derive the column headers from the List<List<string>> since the information is simply not available. You could provide them per parameter:
static DataTable ConvertListToDataTable(List<List<string>> list, IList<string> columnNames)
{
DataTable table = new DataTable();
foreach (string columnName in columnNames)
table.Columns.Add(columnName);
foreach (List<string> row in list)
{
if (row.Count != columnNames.Count)
throw new ArgumentException(string.Format("Invalid data in list, must have the same columns as the columnNames-argument. Line was: '{0}'", string.Join(",", row)), "list");
DataRow r = table.Rows.Add();
for (int i = 0; i < columnNames.Count; i++)
r[i] = row[i];
}
return table;
}
How to use:
string[] columns = { "Employee ID", "First Name", "Last Name", "Job Title", "Address", "City"};
DataTable tblEmployee = ConvertListToDataTable(employees, columns);
But instead of using a List<List<string>>(or a DataTable) to store your employees you should use a custom class, for example Employee with all those properties. Then you can fill a List<Employee>. On that way your code is much better to read and to maintain.
The following code gives you the facility to convert an IEnumerable type to DataTable with dynamic Headers using System.Reflection.PropertyInfo. try to use this.
public static DataTable EnumerableToDataTable<T>(IEnumerable<T> varlist)
{
DataTable dtReturn = new DataTable();
// column names
PropertyInfo[] oProps = null;
if (varlist == null) return dtReturn;
foreach (T rec in varlist)
{
// Use reflection to get property names, to create table, Only first time, others will follow
if (oProps == null)
{
oProps = ((Type)rec.GetType()).GetProperties();
foreach (PropertyInfo pi in oProps)
{
Type colType = pi.PropertyType;
if ((colType.IsGenericType) && (colType.GetGenericTypeDefinition() == typeof(Nullable<>)))
{
colType = colType.GetGenericArguments()[0];
}
dtReturn.Columns.Add(new DataColumn(pi.Name, colType));
}
}
DataRow dr = dtReturn.NewRow();
foreach (PropertyInfo pi in oProps)
{
dr[pi.Name] = pi.GetValue(rec, null) == null ? DBNull.Value : pi.GetValue
(rec, null);
}
dtReturn.Rows.Add(dr);
}
return dtReturn;
}
I need to convert a list array of type List<string>[] to Datatable in C#.
I have found many topics related to List<string[]> to Datatable conversion but nothing on the conversion I need.
Pseudocode:
//Retrieve data from MySQL server
db.Select(category, productID);
//populate List<string>[] array
list[0] = db.ListQuery[0];
list[1] = db.ListQuery[1];
//convert list[] to Datatable
.....
Any help is much appreciated.
If I'm understanding your question right, do you mean something like this?
string category = "Category";
string productId = "ProductId";
List<string[]> tempList = db.Select(category, productID); //Not necessarily correct (I'm not familiar with MySQL). Do what you need to do to create the List<string[]>
DataTable table = new DataTable();
DataRow row;
table.Columns.Add(category);
table.Columns.Add(productId);
foreach (string[] s in tempList)
{
row = table.NewRow();
row[category] = s[0];
row[productId] = s[1];
table.Rows.Add(row);
}
DataTable dataTable = new DataTable();
List<MemberInfo> props = typeof(T).GetFields().Select(objField => (MemberInfo)objField).ToList();
props.AddRange(typeof(T).GetProperties().Select(objField => (MemberInfo)objField));
if (props.Count > 0)
{
Type t;
bool tIsField = false;
for (int iCnt = 0; iCnt < props.Count; iCnt++)
{
var prop = props[iCnt];
tIsField = prop.MemberType == MemberTypes.Field;
dataTable.Columns.Add(prop.Name, tIsField ? ((FieldInfo)prop).FieldType : ((PropertyInfo)prop).PropertyType);
}
foreach (T item in data)
{
DataRow dr = dataTable.NewRow();
foreach (var field in props)
{
tIsField = field.MemberType == MemberTypes.Field;
object value = tIsField ? ((FieldInfo)field).GetValue(item) : ((PropertyInfo)field).GetValue(item, null);
dr[field.Name] = value;
}
dataTable.Rows.Add(dr);
}
}
return dataTable;
I am using .NET 3.5 and need to convert the below select new result into a DataTable. Is there something built in for this or anyone know of a method that can do this?
var contentList = (from item in this.GetData().Cast<IContent>()
select new
{
Title = item.GetMetaData("Title"),
Street = item.GetMetaData("Street"),
City = item.GetMetaData("City"),
Country = item.GetMetaData("Country")
});
Easy and straightforward thing to do is to use reflection:
var records = (from item in this.GetData().Cast<IContent>()
select new
{
Title = "1",
Street = "2",
City = "3",
Country = "4"
});
var firstRecord = records.First();
if (firstRecord == null)
return;
var infos = firstRecord.GetType().GetProperties();
DataTable table = new DataTable();
foreach (var info in infos) {
DataColumn column = new DataColumn(info.Name, info.PropertyType);
table.Columns.Add(column);
}
foreach (var record in records) {
DataRow row = table.NewRow();
for (int i = 0; i < table.Columns.Count; i++)
row[i] = infos[i].GetValue(record);
table.Rows.Add(row);
}
Code may not be working up front but should give you a general idea. First, you get propertyInfos from anonymous type and use this metadata to create datatable schema (fill columns). Then you use those infos to get values from every object.
Here is one generic solution without Reflecting over the properties. Have an extension method as below
public static DataTable ConvertToDataTable<TSource>(this IEnumerable<TSource>
records, params Expression<Func<TSource, object>>[] columns)
{
var firstRecord = records.First();
if (firstRecord == null)
return null;
DataTable table = new DataTable();
List<Func<TSource, object>> functions = new List<Func<TSource, object>>();
foreach (var col in columns)
{
DataColumn column = new DataColumn();
column.Caption = (col.Body as MemberExpression).Member.Name;
var function = col.Compile();
column.DataType = function(firstRecord).GetType();
functions.Add(function);
table.Columns.Add(column);
}
foreach (var record in records)
{
DataRow row = table.NewRow();
int i = 0;
foreach (var function in functions)
{
row[i++] = function((record));
}
table.Rows.Add(row);
}
return table;
}
And Invoke the same using where parameters will be the column name in the order you want.
var table = records.ConvertToDataTable(
item => item.Title,
item => item.Street,
item => item.City
);
You can convert your list result to datatable by the below function
public static DataTable ToDataTable<T>(IEnumerable<T> values)
{
DataTable table = new DataTable();
foreach (T value in values)
{
if (table.Columns.Count == 0)
{
foreach (var p in value.GetType().GetProperties())
{
table.Columns.Add(p.Name);
}
}
DataRow dr = table.NewRow();
foreach (var p in value.GetType().GetProperties())
{
dr[p.Name] = p.GetValue(value, null) + "";
}
table.Rows.Add(dr);
}
return table;
}
There is a CopyToDataTable extension method which does that for you. It lives in System.Data.DataSetExtensions.dll
Try this:
// Create your datatable.
DataTable dt = new DataTable();
dt.Columns.Add("Title", typeof(string));
dt.Columns.Add("Street", typeof(double));
// get a list of object arrays corresponding
// to the objects listed in the columns
// in the datatable above.
var result = from item in in this.GetData().Cast<IContent>()
select dt.LoadDataRow(
new object[] { Title = item.GetMetaData("Title"),
Street = item.GetMetaData("Street"),
},
false);
// the end result will be a set of DataRow objects that have been
// loaded into the DataTable.
Original Article for code sample : Converting Anonymous type generated by LINQ to a DataTable type
EDIT: Generic Pseudocode:
void LinqToDatatable(string[] columns, Type[] datatypes, linqSource)
{
for loop
{
dt.columns.add(columns[i], datatypes[i]);
}
//Still thinking how to make this generic..
var result = from item in in this.GetData().Cast<IContent>()
select dt.LoadDataRow(
new object[] { string[0] = item.GetMetaData[string[0]],
string[1] = item.GetMetaData[srring[1]
},
false);
}
public static DataTable ListToDataTable<T>(this IList<T> data)
{
DataTable dt = new DataTable();
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(T));
for (int i = 0; i < props.Count; i++)
{
PropertyDescriptor prop = props[i];
dt.Columns.Add(prop.Name, prop.PropertyType);
}
object[] values = new object[props.Count];
foreach (T t in data)
{
for (int i = 0; i < values.Length; i++)
{
values[i] = props[i].GetValue(t);
}
dt.Rows.Add(values);
}
return dt;
}
After you do your select new you can to .ToList().ListToDataTable(). This uses ComponentModel reflection and is (theroetically) faster than System.Reflection.
This works:
var Result = from e in actual.Elements
select new
{
Key = e.Key,
ValueNumber = e.Value.ValueNumber,
ValueString = e.Value.ValueString,
ValueBinary = e.Value.ValueBinary,
ValueDateTime = e.Value.ValueDateTime
};
But this doesn't work:
IEnumerable<DataRow> Result = from e in actual.Elements
select new DataRow
{
Key = e.Key,
ValueNumber = e.Value.ValueNumber,
ValueString = e.Value.ValueString,
ValueBinary = e.Value.ValueBinary,
ValueDateTime = e.Value.ValueDateTime
};
DataTable dt = Result.CopyToDataTable(Result);
Can you fix it for me? I want the second bit of code to work so that I can put it into the DataTable. I realize the syntax is totally wrong in #2. How do you specify a column using LINQ like this?
You can write a simple extension method that takes any IEnumerable<T>, uses reflection to get the PropertyDescriptors associated with T, and creates a DataColumn for each
public static DataTable PropertiesToDataTable(this IEnumerable<T> source)
{
DataTable dt = new DataTable();
var props = TypeDescriptor.GetProperties(typeof(T));
foreach (PropertyDescriptor prop in props)
{
DataColumn dc = dt.Columns.Add(prop.Name,prop.PropertyType);
dc.Caption = prop.DisplayName;
dc.ReadOnly = prop.IsReadOnly;
}
foreach (T item in source)
{
DataRow dr = dt.Rows.NewRow();
foreach (PropertyDescriptor prop in props)
dr[prop.Name] = prop.GetValue(item);
dt.Rows.Add(dr);
}
return dt;
}
I can't offer much help other than to point you here:
http://blogs.msdn.com/b/aconrad/archive/2007/09/07/science-project.aspx
You might want to look into the DataTableExtensions.AsEnumerable Method
I haven't tested this, but this might get you pointed in the right direction:
IEnumerable<DataRow> result = (from e in actual.Elements
select new DataRow
{
Key = e.Key,
ValueNumber = e.Value.ValueNumber,
ValueString = e.Value.ValueString,
ValueBinary = e.Value.ValueBinary,
ValueDateTime = e.Value.ValueDateTime
}).AsEnumerable();
DataTable dt = Result.CopyToDataTable(Result);