I have one dictionary Like
Dictionary<string, List<string>> first=new Dictionary<string, List<string>>();
I want to bind this dictionary to data table such that data table ColumnName should be key of the dictionary and respective columns should contain their dictionary values.
What I tried:
Dictionary<string, List<string>> some= new Dictionary<string, List<string>>();
System.Data.DataTable dt = new System.Data.DataTable();
foreach (var entry in some)
{
if (entry.Value.Count > 0)
{
dt.Columns.Add(entry.Key);
//entry.Value.count is not same for all entry.Key
foreach (var value in entry.Value)
{
DataRow row = dt.NewRow();
row[entry.Key] = value;
dt.Rows.Add(row);
}
}
}
Surely I know, above code is having some errors to achieve following result
DesirrdResultImage
any suggestions?
Here's a possible solution (note that I don't think this is the best way to do this, but I hope it'll help guide you):
Dictionary<string, List<string>> some = new Dictionary<string, List<string>>
{
{ "Key1", new List<string>
{
"Val1_1",
"Val2_1",
"Val3_1"
}
},
{ "Key2", new List<string>
{
"Val1_2",
"Val2_2",
"Val3_2"
}
}
};
DataTable dt = new DataTable();
var keys = some.Keys;
// Add all the columns from the beginning
dt.Columns.AddRange(keys.Select(key => new DataColumn(key)).ToArray());
// Get the rows number using the Max count of the lists (assuming the length of the lists might change, otherwise just use some.Values[0].Count)
int rowsNumber = some.Values.Max(s => s.Count);
for (int i = 0; i < rowsNumber; i++)
{
var row = dt.NewRow();
// Set all the values depending on the keys
foreach (var key in keys)
{
if (some[key].count <= i)
break;
row[key] = some[key][i];
}
dt.Rows.Add(row);
}
dataGridView1.DataSource = dt;
The result is:
Check if No row or less than Values than add Value to New row
else
Add value to existing row
DataTable dt = new DataTable();
int i = 0;
foreach (var entry in some)
{
if (entry.Value.Count > 0)
{
dt.Columns.Add(entry.Key);
DataRow row;
//entry.Value.count is not same for all entry.Key
foreach (var value in entry.Value)
{
int ValueCount = entry.Value.Count();
if (dt.Rows.Count <= ValueCount)
{
row = dt.NewRow();
row[entry.Key] = value;
dt.Rows.Add(row);
}
else
{
row = dt.Rows[i];
row[entry.Key] = value;
i++;
}
}
}
}
Related
I need to dynamically generate a query to access certain columns from a datatable.
string cols="row[Id],row[UserId], row[Code]";
var result= (from DataRow row in dt.Rows
select cols);
but this only returns "row[Id],row[UserId], row[Code]". How can I access the values in those columns?
I doubt this problem can be solved elegantly with a linq-based solution. It can be solved pretty easily using a loop and by accessing the column of the DataRow using the Item property.
public IEnumerable<object[]> GetValues(IList<string> columns, DataTable dt) {
foreach (var row in dt.Rows) {
var rowResult = new object[columns.Count];
for (var col = 0; col < columns.Count; col++) {
rowResult[col] = row.Item[columns[col]];
}
yield return rowResult;
}
}
Why not putting it in a dictionary? Dictionary<string, object> the key is the column name and the value is the value of the column.
string[] cols = new string[] { "Id", "UserId", "Code" };
var result = (from DataRow row in dt.Rows
select cols.ToDictionary(c => c, c => row[c]));
I'm trying to get some data from DataTable using Linq, but it gives me following error:
Specified cast is not valid.
First of all, i'm using this to paste copied cells from excel to datagridview
private void btnExcel_Click(object sender, EventArgs e)
{
dataGridView1.Columns.Clear();
dataGridView1.Columns.Add("Column1", "Column1");
dataGridView1.Columns.Add("Column2", "Column2");
dataGridView1.Columns.Add("Column3", "Column3");
dataGridView1.Columns.Add("Column4", "Column4");
dataGridView1.Columns.Add("Column5", "Column5");
dataGridView1.Columns.Add("Column6", "Column6");
dataGridView1.Columns.Add("Column7", "Column7");
dataGridView1.Columns.Add("Column8", "Column8");
dataGridView1.Columns.Add("Column9", "Column9");
dataGridView1.Columns.Add("Column10", "Column10");
dataGridView1.Columns.Add("Column11", "Column11");
dataGridView1.Columns.Add("Column12", "Column12");
dataGridView1.Columns.Add("Column13", "Column13");
DataObject o = (DataObject)Clipboard.GetDataObject();
if (o.GetDataPresent(DataFormats.UnicodeText))
{
if (dataGridView1.RowCount > 0)
dataGridView1.Rows.Clear();
string[] pastedRows = Regex.Split(o.GetData(DataFormats.UnicodeText).ToString().TrimEnd("\r\n".ToCharArray()), "\r\n");
int j = 0;
foreach (string pastedRow in pastedRows)
{
string[] pastedRowCells = pastedRow.Split(new char[] { '\t' });
dataGridView1.Rows.Add();
int myRowIndex = dataGridView1.Rows.Count - 1;
using (DataGridViewRow myDataGridViewRow = dataGridView1.Rows[j])
{
for (int i = 0; i < pastedRowCells.Length; i++)
myDataGridViewRow.Cells[i].Value = pastedRowCells[i];
this.dataGridView1.AutoResizeColumns();
}
j++;
}
}
}
Then I'm using this method to convert datagridview to DataTable
private DataTable GetDataTableFromDGV(DataGridView dgv)
{
var dt = new DataTable();
foreach (DataGridViewColumn column in dgv.Columns)
{
if (column.Visible)
{
// You could potentially name the column based on the DGV column name (beware of dupes)
// or assign a type based on the data type of the data bound to this DGV column.
dt.Columns.Add();
}
}
object[] cellValues = new object[dgv.Columns.Count];
foreach (DataGridViewRow row in dgv.Rows)
{
for (int i = 0; i < row.Cells.Count; i++)
{
cellValues[i] = row.Cells[i].Value;
}
dt.Rows.Add(cellValues);
}
return dt;
}
after that using this linq query to get data and display it to datagridview2
DataTable dt = GetDataTableFromDGV(dataGridView1);
//foreach (DataColumn c in dt.Columns)
//{
// MessageBox.Show(c.ColumnName);
//}
var groupedData = from b in dt.AsEnumerable()
group b by b.Field<int>("Column2") into g
select new
{
column2 = g.Key,
column13 = g.Sum(x => x.Field<decimal>("Column13"))
};
foreach (var result in groupedData)
{
dataGridView2.Rows.Add(result);
}
It throws a " Specified cast is not valid."
Basically what I want is shows on picture below:
pic
You never assign a type to any of the DataColumns that you show, so they will have a default data type of string, and calling Field<int> or Field<decimal> will throw an invalid cast exception.
Either assign the appropriate types to the columns when creating the data table or parse the string values:
var groupedData = from b in dt.AsEnumerable()
group b by int.Parse(b.Field<string>("Column2")) into g
select new
{
column2 = g.Key,
column13 = g.Sum(x => decimal.Parse(x.Field<string>("Column13")))
};
I have generic list and I'm converting that to DataTable
Then I'm generating columns with the properties of the list and adding rows to it, Now I want to remove the column headers fro the table
This is my code for Converting List To DataTable
public class ListtoDataTableConverter
{
public 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;
}
}
The result for the above code is
Name Age
---------------------------------
A 22
B 23
Now I want to have the output without the Name and Age.
How can I remove them
No real way of "removing" column headers from a table - it is a table after all. But why not just tell epplus to suppress the outputting of the header row with .LoadFromDataTable(dtdata, false) - note the false as the second paramter `PrintHeaders'.
[TestMethod]
public void ListToDataTableConverter()
{
//Use a func for demonstrative purposes
Func<List<NameAgeObject>, DataTable> ToDataTable = (items) =>
{
DataTable dataTable = new DataTable(typeof(NameAgeObject).Name);
//Get all the properties
PropertyInfo[] Props = typeof(NameAgeObject).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo prop in Props)
{
//Setting column names as Property names
dataTable.Columns.Add(prop.Name);
}
foreach (NameAgeObject 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;
};
var itemlist = new List<NameAgeObject>
{
new NameAgeObject {Name = "A", Age = 22},
new NameAgeObject {Name = "B", Age = 23},
new NameAgeObject {Name = "C", Age = 24},
new NameAgeObject {Name = "D", Age = 25},
new NameAgeObject {Name = "E", Age = 26},
};
var dtdata = ToDataTable(itemlist);
var existingFile = new FileInfo(#"c:\temp\temp.xlsx");
if (existingFile.Exists)
existingFile.Delete();
using (var package = new ExcelPackage(existingFile))
{
var ws = package.Workbook.Worksheets.Add("Sheet1");
ws.Cells[1, 1].LoadFromDataTable(dtdata, false);
package.Save();
}
}
If it is a very big table you might see a performance problem with LoadFromDataTable in which case you can manually write to the worksheet by hitting the individual cells in excel. Here you ap the datatable by row/column and simply skip any writing of column info.
How to convert a LINQ query result to a DataTable dynamically?
There are solutions where you create another class and specify the column names, but I want the flexibility to change the LINQ structure like column names, column quantities, and have a DataTable generated with the columns names automatically.
Thanks
I've included an extension method that I use with SqlBulkCopy that should do the job, but I'd like to ask why you want to this conversion. There are a very limited number of cases (SqlBulkCopy being one) where a list of objects can't do everything a datatable can. You can use them as binding sources for most controls ... just curious.
public static DataTable toDataTable<T>(this IEnumerable<T> value, List<string> exclusionList)
where T : class
{
var dataTable = new DataTable();
var type = typeof(T);
var properties = type.GetProperties().Where(x => !exclusionList.Contains(x.Name)).ToList();
foreach (var propertyInfo in properties)
{
var propertyType = propertyInfo.PropertyType;
if (!propertyType.IsScalar())
continue;
var nullableType = Nullable.GetUnderlyingType(propertyType);
propertyType = nullableType ?? propertyType;
var dataColumn = new DataColumn(propertyInfo.Name, propertyType);
if (nullableType != null)
dataColumn.AllowDBNull = true;
dataTable.Columns.Add(dataColumn);
}
foreach (var row in value)
{
var dataRow = dataTable.NewRow();
foreach (var property in properties)
{
var safeValue = property.GetValue(row, null) ?? DBNull.Value;
dataRow[property.Name] = safeValue;
}
dataTable.Rows.Add(dataRow);
}
return dataTable;
}
Look into the MoreLinq Nuget package. It has a function ToDataTable()
var LinqResults = from ......;
DataTable dt_Results = LinqResults.ToDataTable();
https://code.google.com/p/morelinq/
It has other VERY useful functions as well:
https://code.google.com/p/morelinq/wiki/OperatorsOverview
They key is to use the LINQ query result as its Implemented IList interface.
If you receive the result as a parameter on a method as an IList object, you can access its columns and rows, this way:
var props = item.GetType().GetProperties();
Refer to this example, it's a small class which please note the it just abstracts the creation of the DataTable, and there is a static method inside called "LINQToDataTable" which you should use.
Step 1, create a class called "GridHelper" (uses System.Data for DataTable structure)
public class GridHelper
{
private DataTable baseDt;
public GridHelper(string tableName)
{
baseDt = new DataTable(tableName);
}
public DataTable getDataTable()
{
return baseDt;
}
public object[,] getObjToFill()
{
object[,] obj = new object[baseDt.Columns.Count, 2];
for (int i = 0; i < baseDt.Columns.Count; i++)
{
obj[i, 0] = baseDt.Columns[i].ColumnName;
}
return obj;
}
public void addColumn(string colName, Type valueType)
{
baseDt.Columns.Add(colName, valueType);
}
public void addRow(object[,] values)
{
DataRow newRow = baseDt.NewRow();
for (int i = 0; i < values.Length / 2; i++)
{
bool colFound = false;
for (int j = 0; j < baseDt.Columns.Count; j++)
{
if (baseDt.Columns[j].ColumnName == values[i, 0].ToString())
{
colFound = true;
break;
}
}
if (colFound == false)
{
throw new Exception("The column " + values[i, 0].ToString() + " has not been added yet.");
}
newRow[values[i, 0].ToString()] = values[i, 1];
}
baseDt.Rows.Add(newRow);
}
public static DataTable LINQToDataTable<T>(T objToList) where T : System.Collections.IList
{
GridHelper ghResult = new GridHelper("Report");
foreach (Object item in objToList)
{
var props = item.GetType().GetProperties();
foreach (var prop in props)
{
ghResult.addColumn(prop.Name, typeof(string));
//prop.Name
//prop.GetValue(item)
}
break;
}
object[,] obj = ghResult.getObjToFill();
foreach (Object item in objToList)
{
var props = item.GetType().GetProperties();
int index = 0;
foreach (var prop in props)
{
//ReportValue(prop.Name, prop.GetValue(item, null));
//prop.Name
obj[index, 1] = prop.GetValue(item);
index++;
}
ghResult.addRow(obj);
}
return ghResult.getDataTable();
}
}
Usage:
var listaReporte =
(from t in dbContext.TablaPruebas
select new
{
Name = t.name,
Score = t.score
}
) .ToList();
DataTable dt = Library.GridHelper.LINQToDataTable(listaReporte);
And that is, use your DataTable as you wish, on a GridView or DataGridView
I have created an array of lists. The array has seven rows who represents the days of week and the lists contain the available slots for doctor appointments. I am trying to bind it with a GridView or a DataList (whatever is more appropriate) without success.
I have declared the list:
List<string>[] list=new List<string>[7]; //An array of 7 lists
for (int i = 0; i < 7; i++)
{
list[i]=new List<string>();
}
I have filled in the lists with strings that represent the available slots for appointments with a doctor.
The result that I want to achieve is the availability for one of the doctors as it is depicted at this site: link
You could change the array to a List<List<string>> like this:
List<List<string>> list = new List<List<string>>();
Then you can bind it to a GridView in the following way (just adapt to your case):
protected void Page_Load(object sender, EventArgs e)
{
List<string> cols = GetColDefsFromBackend();
List<List<string>> rows = GetDataFromBackend();
GridView1.DataSource = CreateDataTable(cols, rows);
GridView1.DataBind();
}
private System.Data.DataTable CreateDataTable(List<string> columnDefinitions, List<List<string>> rows)
{
DataTable table = new DataTable();
foreach (string colDef in columnDefinitions)
{
DataColumn column;
column = new DataColumn();
column.DataType = typeof(string);
column.ColumnName = colDef;
table.Columns.Add(column);
}
// Create DataRow and Add it to table
foreach (List<string> rowData in rows)
{
DataRow row = table.NewRow();
// rowData is in same order as columnDefinitions
for (int i = 0; i < rowData.Count; i++)
{
row[i] = rowData[i];
}
table.Rows.Add(row);
}
return table;
}
/// <summary>
/// Simulates a StoredProcedureCall which returns
/// the data in a List with Lists of strings
/// </summary>
private List<List<string>> GetDataFromBackend()
{
List<List<string>> myData = new List<List<string>>();
myData.Add(Row(1));
myData.Add(Row(2));
myData.Add(Row(3));
return myData;
}
private List<string> Row(int p)
{
List<string> row = new List<string>();
for (int i = 0; i < 4; i++)
{
row.Add(string.Format("Column {0}/{1}", p, i));
}
return row;
}
private List<string> GetColDefsFromBackend()
{
List<string> cols = new List<string>();
cols.Add("Col1");
cols.Add("Col2");
cols.Add("Col3");
cols.Add("Col4");
return cols;
}
Source: Use List<List<string>> as GridView - DataSource
Thank you very much. It was really helpful, I spent some time trying to understand the logic behind this transformation and as a newbie I end up with a little angler piece of code:
private System.Data.DataTable CreateDataTable(List<string> columnDefinitions, List<List<string>> rows)
{
DataTable table = new DataTable();
foreach (string colDef in columnDefinitions)
{
DataColumn column;
column = new DataColumn();
column.DataType = typeof(string);
column.ColumnName = colDef;
table.Columns.Add(column);
}
for (int i = 0; i < rows[0].Count; i++)
{
table.Rows.Add(rows[0][i], rows[1][i], rows[2][i], rows[3][i], rows[4][i], rows[5][i], rows[6][i]);
}
return table;
}
private List<string> GetColDefsFromBackend()
{
List<string> cols = new List<string>();
cols.Add("Monday");
cols.Add("Tuesday");
cols.Add("Wednesday");
cols.Add("Thursday");
cols.Add("Friday");
cols.Add("Saturday");
cols.Add("Sunday");
return cols;
}
Turn the List into a datatable and then bind. Array of array's are little complicated for binding clearly.