I'm trying to convert a gridview datasource to a datatable.
What I have tried so far
dt = (DataTable)GridCanvas.DataSource; // Unable to cast object of type 'System.Collections.Generic.List`1 to type 'System.Data.DataTable'
Also I have tried this
Unable to cast object of type 'System.Collections.Generic.List`1[CRM.Models.Leads]' to type 'System.Windows.Forms.BindingSource'
BindingSource bindingSource = (BindingSource)GridCanvas.DataSource;
dt = (DataTable)bindingSource.DataSource;
And this
'Object reference not set to an instance of an object.'
dt = GridCanvas.DataSource as DataTable;
I'm populating my gridview in the following way
var dispatchLeads = await API.Zelkon.Leads.Dispatch.Leads(Variables.Agent.username);
GridCanvas.DataSource = dispatchLeads;
I'm trying to avoid loop solutions. Hope someone has an idea how to solve this. Thanks!
First get the List<Leads> from GridCanvas as
List<Leads> data=(List<Leads>)GridCanvas.DataSource;
Then Convert the List<Leads> to DataTable as;
DataTable dt=ToDataTable<Leads>(data);
use following methods for conversion.
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)
{
//Defining type of data column gives proper data table
var type = (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>) ? Nullable.GetUnderlyingType(prop.PropertyType) : prop.PropertyType);
//Setting column names as Property names
dataTable.Columns.Add(prop.Name, type);
}
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;
}
I am here today trying to work out how I can do this. I have the code below to look through each column in a DataRow, but how can I access the key AND value? I want to assign it to a dictionary in the class but I can't seem to get both of them, the only way I can get anything is by calling:
var columnValue = playerDataRow[column];
Here is the full thing:
using (var mysqlConnection = Sirius.GetServer().GetDatabaseManager().GetConnection())
{
mysqlConnection.SetQuery("SELECT * FROM `users` WHERE `auth_ticket` = #authTicket LIMIT 1");
mysqlConnection.AddParameter("authTicket", authTicket);
var playerDataTable = mysqlConnection.GetTable();
foreach (DataRow playerDataRow in playerDataTable.Rows)
{
foreach (DataColumn column in playerDataTable.Columns)
{
var columnValue = playerDataRow[column];
}
}
}
foreach (DataRow playerDataRow in playerDataTable.Rows)
{
var myDic = new Dictionary<string, object>();
foreach (DataColumn column in playerDataTable.Columns)
{
myDic.Add(column.ColumnName, playerDataRow[column]);
}
}
the variable column will be the key and the value will be columnValue
looks that you only want one row of output - perhaps for this specific user based on auth_ticket
here is an example of how to get all values for this row into a Dictionary of strings (I'm converting all data to strings by the way just for this example)
var htRowValues = new Dictionary<string,string>();
using (var mysqlConnection = Sirius.GetServer().GetDatabaseManager().GetConnection())
{
mysqlConnection.SetQuery("SELECT * FROM `users` WHERE `auth_ticket` = #authTicket LIMIT 1");
mysqlConnection.AddParameter("authTicket", authTicket);
var playerDataTable = mysqlConnection.GetTable();
foreach (DataRow playerDataRow in playerDataTable.Rows)
{
foreach (DataColumn column in playerDataTable.Columns)
{
var columnValue = playerDataRow[column];
htRowValues[column.ColumnName]=System.Convert.ToString(columnValue);
}
}
}
now you have all column values in the dictionary for this one row of data.
I'm calling WCF Service that gives me a list of customers with specified field names in the BAL. I created a method ToDataTable as instructed on many forums (it might be wrong for this instance). I use it to convert the list into a datatable but there is a challenge that I'm facing. The error says 'Cannot implicitly convert type 'System.Data.DataTable to mHotRes.DesktopPresentation.ListFrm.ListType'.
Here is my code for binding data:
private void BindData()
{
try
{
switch (_ListType)
{
case ListType.Customers:
IHotRes res = new MHotServiceProvider().Service;
List<Customer> customer = res.CustomerSaveDataList();
_ListType = ToDataTable(customer); //the problem occurs here
break;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Here is the code for ToDataTable method:
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;
}
If any more code samples are needed let me know.
Your reflection ToDataTable code is working correctly:
_ListType = ToDataTable(customer); //the problem occurs here
The problem is that the _ListType have different type from DataTable.
You should change the line to
DataTable tbl = ToDataTable(customer);//Your method returns DataTable
I want a function which takes in a datatable & returns a List (object is not DataRow)
Eg. :
I know I can do this (but this requires column names to be known) :
// Datatable dt = Filled from a Database query & has 3 columns Code,Description & ShortCode
List<object> rtn = new List<object>();
var x = from vals in dt.Select()
select new
{
Code = vals["Code"],
Description = vals["Description"],
ShortCode = vals["ShortCode"],
};
rtn.AddRange(x)
return rtn;
What i want is a generic version so that i can pass in any datatable & it will generate based on column names in the datatable.
Since the property names are not known at compile time and you want to use the data for JSON serialization, you can use the following to create a list of dictionary. If you use Newtonsoft JSON, then the serialization takes care of converting the key value pairs in a JSON object format.
IEnumerable<Dictionary<string,object>> result = dt.Select().Select(x => x.ItemArray.Select((a, i) => new { Name = dt.Columns[i].ColumnName, Value = a })
.ToDictionary(a => a.Name, a => a.Value));
In order to dynamically create properties so as to treat different dataTables with different set of Columns, we can use the System.Dynamic.ExpandoObject. It basically implements, IDictionary <string,object>. The format, which can easily be converted to JSON.
int colCount = dt.Columns.Count;
foreach (DataRow dr in dt.Rows)
{
dynamic objExpando = new System.Dynamic.ExpandoObject();
var obj = objExpando as IDictionary<string, object>;
for (int i = 0; i < colCount; i++)
{
string key = dr.Table.Columns[i].ColumnName.ToString();
string val = dr[key].ToString();
obj[key] = val;
}
rtn.Add(obj);
}
String json = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(rtn);
You can use the following generic function:-
private static List<T> ConvertDataTable<T>(DataTable dt)
{
List<T> data = newList<T>();
foreach (DataRowrow in dt.Rows)
{
Titem = GetItem<T>(row);
data.Add(item);
}
return data;
}
private static TGetItem<T>(DataRow dr)
{
Type temp = typeof(T);
T obj =Activator.CreateInstance<T>();
foreach (DataColumncolumn in dr.Table.Columns)
{
foreach (PropertyInfopro in temp.GetProperties())
{
if (pro.Name == column.ColumnName)
pro.SetValue(obj,dr[column.ColumnName], null);
else
continue;
}
}
return obj;
}
Please check my article, which has complete demonstration on how to use this generic method.
Here is the original question:
// Datatable dt = Filled from a Database query & has 3 columns Code,Description & ShortCode
List<object> rtn = new List<object>();
var x = from vals in dt.Select()
select new
{
Code = vals["Code"],
Description = vals["Description"],
ShortCode = vals["ShortCode"],
};
rtn.AddRange(x)
return rtn;
Just replace with
List<object> rtn = JsonConvert.DeserializeObject<List<object>>(JsonConvert.SerializeObject(dt));
You will have the provide the anonymous object as a parameter and use json/xml serialization:
protected static List<T> ToAnonymousCollection<T>(DataTable dt, T anonymousObject)
{
List<DataColumn> dataColumns = dt.Columns.OfType<DataColumn>().ToList();
return dt.Rows.OfType<DataRow>().Select(dr =>
{
Dictionary<string, object> dict = new Dictionary<string, object>();
dataColumns.Each(dc => dict.Add(dc.ColumnName, dr[dc]));
return JsonConvert.DeserializeAnonymousType(JsonConvert.SerializeObject(dict), anonymousObject);
}).ToList();
}
Usage:
var anonymousCollection = ToAnonymousCollection(dt, new { Code = [ColumnTypeValue, eg. 0], Description = [ColumnTypeValue, eg. string.Empty], ShortCode = Code=[ColumnTypeValue, eg. 0] })
I can't seem to get passed this error message using this code.
System.Data.DuplicateNameException: A column named 'Url' already belongs to this DataTable.
foreach (var user in users.Users)
{
using (DataTable table = new DataTable())
{
table.Clear();
for (int i = 0; i < users.Users[0].GetType().GetProperties().Count(); i++)
{
table.Columns.Add(users.Users[0].GetType().GetProperties()[i].Name);
Console.WriteLine(table.Columns.Add(users.Users[0].GetType().GetProperties()[i].Name));
}
}
}
Any ideas?
UPDATE
var properties = users.Users[0].GetType().GetProperties();
for (int i = 0; i < properties.Count(); i++)
{
table.Columns.Add(properties[i].Name, typeof(String));
}
Because I didn't know what the type was to use the foreach. This:
var properties = users.Users[0].GetType().GetProperties();
foreach (PropertyInformation prop in properties)
{
table.Columns.Add(properties.);
Console.WriteLine(prop.Name);
}
gave me Cannot convert type 'System.Reflection.PropertyInfo' to 'System.Configuration.PropertyInformation'
Anyway I can figure out how to get the correct type in there? #barrick
The error won't lie. In the Console.WriteLine() call, you're adding the column again, which will cause the problem.
Try:
var properties = users.Users[0].GetType().GetProperties();
foreach (PropertyInfo prop in properties)
{
table.Columns.Add(prop.Name);
Console.WriteLine(prop.Name);
}