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;
Related
I have following string. I am trying to insert these details into dataTable but last columns in below string ("incident" column) not inserting into data table.The code is working based on first 4 column. I am getting these values from frontend using JavaScript and I have assigned to string.
String given below
[{"CompanayID":"k123","Role":"Admin","Country":"UK","Asset":"HD"},
"CompanayID":"k234","Role":"User","Country":"US","Asset":"HD12","incident":"abc 1"}]
I have done following code but it doesn't take last column
DataTable dt = new DataTable("UserDetails");
JavaScriptSerializer serializer = new JavaScriptSerializer();
object[] objCustomers = (object[])serializer.DeserializeObject(customers);
var columnNames = ((Dictionary<string, object>)objCustomers[0]).Select(x => x.Key).ToList();
for (int i = 0; i < columnNames.Count; i++)
{
dt.Columns.Add(columnNames[i]);
}
for (int i = 0; i < objCustomers.Length; i++)
{
Dictionary<string, object> keyValue = (Dictionary<string, object>)objCustomers[i];
DataRow dr = dt.NewRow();
foreach (KeyValuePair<string, object> item in keyValue)
{
for (int k = 0; k < columnNames.Count(); k++)
{
if (item.Key == columnNames[k].ToString())
{
dr[columnNames[k]] = item.Value;
break;
}
}
}
dt.Rows.Add(dr);
}
You are making the columns depending on the first object and it does not contain the last one 'incident'.
You Have more than a way to do it
Adding the columns depending on the second object
string customers = "[{\"CompanayID\":\"k123\",\"Role\":\"Admin\",\"Country\":\"UK\",\"Asset\":\"HD\"}, {\"CompanayID\":\"k234\",\"Role\":\"User\",\"Country\":\"US\",\"Asset\":\"HD12\",\"incident\":\"abc 1\"}]";
DataTable dt = new DataTable("UserDetails");
var rows = JsonConvert.DeserializeObject<List<Dictionary<string, object>>>(customers);
foreach (var c in rows[1])
{
dt.Columns.Add(c.Key);
}
foreach (var row in rows)
{
DataRow dr = dt.NewRow();
foreach (var innerColumn in row)
{
dr[innerColumn.Key] = innerColumn.Value;
}
dt.Rows.Add(dr);
}
}
Add missing column to the first object as "" or null
string customers = "[{\"CompanayID\":\"k123\",\"Role\":\"Admin\",\"Country\":\"UK\",\"Asset\":\"HD\",\"incident\":\"\"}, {\"CompanayID\":\"k234\",\"Role\":\"User\",\"Country\":\"US\",\"Asset\":\"HD12\",\"incident\":\"abc 1\"}]";
DataTable dt = new DataTable("UserDetails");
var rows = JsonConvert.DeserializeObject<List<Dictionary<string, object>>>(customers);
foreach (var c in rows[0])
{
dt.Columns.Add(c.Key);
}
foreach (var row in rows)
{
DataRow dr = dt.NewRow();
foreach (var innerColumn in row)
{
dr[innerColumn.Key] = innerColumn.Value;
}
dt.Rows.Add(dr);
}
Update (Dynamic Way)
string customers = "[{\"CompanayID\":\"k123\",\"Role\":\"Admin\",\"Country\":\"UK\",\"Asset\":\"HD\",\"incident\":\"\"}, {\"CompanayID\":\"k234\",\"Role\":\"User\",\"Country\":\"US\",\"Asset\":\"HD12\",\"incident\":\"abc 1\"}]";
DataTable dt = new DataTable("UserDetails");
var rows = JsonConvert.DeserializeObject<List<Dictionary<string, object>>>(customers);
foreach (var row in rows)
{
DataRow dr = dt.NewRow();
foreach (var innerColumn in row)
{
if (!dt.Columns.Contains(innerColumn.Key))
{
dt.Columns.Add(innerColumn.Key);
}
dr[innerColumn.Key] = innerColumn.Value;
}
dt.Rows.Add(dr);
}
check https://dotnetfiddle.net/RsOu87
I'd like to use LINQ to take a datarow, and parse out the datacolumn names with their values.
So if I had a dataRow with the following columns and values:
DataColumn column1 with value '1'
DataColumn column2 with value 'ABC'
I'd like to have a string returned as "column1 = '1' and column2 = 'ABC'"
**** code should not care about the column names, nor the number of columns in the table.****
Purpose being, to filter a dataTable like:
var newRows = myTable.Select ("column1 = '1' and column2 = 'ABC'");
I can parse out the columns of the table like this:
string[] columnName = myTable.Columns.Cast<DataColumn>().Select(cn => cn.ColumnName).ToArray();
But I need to also extract values from a target row.
It feels like this might be a start:
{
string[] columnNames = existingTable.Columns.Cast<DataColumn>().Select(cn => cn.ColumnName).ToArray();
foreach (DataRow oldRow in existingTable.Rows)
{
var criteria = string.Join("and", columnNames, oldRow.ItemArray);
}
}
I think you are trying to get the column names and rows without actually referencing them. Is this what you're trying to do:
var table = new DataTable();
var column = new DataColumn {ColumnName = "column1"};
table.Columns.Add(column);
column = new DataColumn {ColumnName = "column2"};
table.Columns.Add(column);
var row = table.NewRow();
row["column1"] = "1";
row["column2"] = "ABC";
table.Rows.Add(row);
string output = "";
foreach (DataRow r in table.Rows)
{
output = table.Columns.Cast<DataColumn>()
.Aggregate(output, (current, c) => current +
string.Format("{0}='{1}' ", c.ColumnName, (string) r[c]));
output = output + Environment.NewLine;
}
// output should now contain "column1='1' column2='ABC'"
You can create extension methods out of this too, which operate both on a DataTable (for all rows) or a DataRow (for a single row):
public static class Extensions
{
public static string ToText(this DataRow dr)
{
string output = "";
output = dr.Table.Columns.Cast<DataColumn>()
.Aggregate(output, (current, c) => current +
string.Format("{0}='{1}'", c.ColumnName, (string)dr[c]));
return output;
}
public static string ToText(this DataTable table)
{
return table.Rows.Cast<DataRow>()
.Aggregate("", (current, dr) => current + dr.ToText() + Environment.NewLine);
}
}
I would highly recommend mapping to a class, and then adding another property which combines both of them!
See if this gets you in the right direction
EDIT Added solution using reflection since that is more in line with what you are wanting to accomplish
void Main()
{
List<MyClass> myColl = new List<MyClass>() { new MyClass() { myFirstProp = "1", mySecondProp = "ABC" } };
foreach (MyClass r in myColl)
{
List<string> rPropsAsStrings = new List<string>();
foreach (PropertyInfo propertyInfo in r.GetType().GetProperties())
{
rPropsAsStrings.Add(String.Format("{0} = {1}", propertyInfo.Name, propertyInfo.GetValue(r, null)));
}
Console.WriteLine(String.Join(" and ", rPropsAsStrings.ToArray()));
}
}
public class MyClass
{
public string myFirstProp { get; set; }
public string mySecondProp { get; set; }
}
The below uses Linq with strong typed properties
System.Data.DataTable table = new DataTable("ParentTable");
DataColumn column;
DataRow row;
column = new DataColumn();
column.DataType = typeof(string);
column.ColumnName = "column1";
table.Columns.Add(column);
column = new DataColumn();
column.DataType = typeof(string);
column.ColumnName = "column2";
table.Columns.Add(column);
row = table.NewRow();
row["column1"] = "1";
row["column2"] = "ABC";
table.Rows.Add(row);
var results = from myRow in table.AsEnumerable()
select String.Format("column1 = {0}, column2 = {1}", myRow[0], myRow[1]);
foreach (string r in results)
{
Console.WriteLine(r);
}
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 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);