I need to join two datatable's and select all values from both table because d1 columns are dynamic i have tried with below code and getting the join value but when i select it shows in 2 DataRows it should be in one row
DataTable dtRtn = new DataTable();
var result = from d1 in dtFormData.AsEnumerable()
join d2 in dtResponderDetails.AsEnumerable()
on d1.Field<string>("ResponderId") equals d2.Field<string>("EmployeeId")
select new { d1,d2};
I need both d1 and d2 joined result to be copied to dtRtn table
Edit
I have searched but there is not straight forward answer for and all answers shows how to select specific columns
Please help thanks
You will need to first dynamically add the columns from dtFormData and dtResponderDetails to dtRtn. Then you can iterate through the results of your LINQ query and create new DataRow objects for each.
Here is a quick stab at the necessary code you would need to add to what you currently have:
// Step 1: Add all columns from your two DataTables to dtRtn
// (with a prefix to avoid naming collisions)
DataTable dtRtn = new DataTable();
CopyColumns(dtFormData, dtRtn, "FormData.");
CopyColumns(dtResponderDetails, dtRtn, "ResponderDetails.");
// Step 2: Build a collection containing all of the values for this result
var numFormColumns = dtFormData.Columns.Count;
var numResponderColumns = dtResponderDetails.Columns.Count;
foreach(var row in result) {
var targetRow = new List<object>();
PopulateRows(row.d1, numFormColumns, targetRow);
PopulateRows(row.d2, numResponderColumns, targetRow);
// Pass the values in as an array, which will convert it to a new DataRow
dtRtn.Rows.Add(targetRow.ToArray());
}
//...
private void CopyColumns(DataTable sourceTable, DataTable targetTable, string rowPrefix)
{
foreach (DataColumn column in sourceTable.Columns)
{
var rowName = String.Format("{0}{1}", rowPrefix, column.ColumnName);
targetTable.Columns.Add(rowName, column.DataType);
}
}
void PopulateRows(DataRow sourceRow, int numColumns, List<object> targetRow)
{
for(var i = 0; i < numColumns; i++) {
targetRow.Add(sourceRow[i]);
}
}
Related
How do i populate this dataTable with array of strings? Im using this template but i can only add data hardcoded... I have an string[]values which contains my data and that should be added to the datatable. I think its quite easy but i don't see it. i've been trying to loop through it but that doens't seem to work? Think im missing a crucial step.
I've created a my datatable here :
DataTable dt = new DataTable() { TableName = "MBR" };
Adding the columns to it
string[] columns = new string [l];
for (int i = 0; i < l; i++)
{
columns[i] = tags[i];
}
for (int i = 0; i < timeStamps.Count(); i++)
{
foreach (var item in tagCollection)
{
if (timeStamps[i].Date == item.time)
{
Console.WriteLine(item.time + " " + item.name );
}
}
}
dt.Columns.AddRange(columns.Select(c => new DataColumn(c.ToString())).ToArray());
And this i used in the template my collegue is working with and we need to provide the data here
var rows = new string[][]
{
new string[] {"1", "2", "false" },
new string[] { "test", "10000", "19.9" },
};
foreach (var row in rows)
{
dt.Rows.Add(row);
}
//Convert datatable to dataset and add it to the workbook as worksheet
ds.Tables.Add(dt);
workbook.Worksheets.Add(ds);
I've got many columns like 500+. And i need to add to each column a piece of data which i get from my string[]. which can contains 10 or 500+ records it depends. I need to add each record to a row. My columns are already working in this thing. I just need a way to add multiple Arrays to the table
This works for me:
DataTable dt = new DataTable() { TableName = "MBR" };
dt.Columns.Add(new DataColumn("A", typeof(string)));
dt.Columns.Add(new DataColumn("B", typeof(string)));
dt.Columns.Add(new DataColumn("C", typeof(string)));
var rows = new string[][]
{
new string[] {"1", "2", "false" },
new string[] { "test", "10000", "19.9" },
};
foreach (var row in rows)
{
dt.Rows.Add(row);
}
That gives me:
Here's how you might fill a datatable from a file of people:
var people = new DataTable();
people.Columns.Add("Name");//string
people.Columns.Add("Age", typeof(int));
people.Columns.Add("HireDate", typeof(DateTime));
people.Columns.Add("IsManager", typeof(bool));
foreach(var line in File.ReadLines("people.csv")){
var bits = line.Split(',');
dt.Rows.Add(new object[]{
bits[0], //Name
int.Parse(bits[1]), //Age
DateTime.Parse(bits[2]), //HireDate
bool.Parse(bits[3]) //IsManager
});
}
It would, of course, be preferable to use some library like Csvhelper if you're reading from a CSV - it can read into DataTables directly and is a lot more sophisticated than this example. This is just to show the process of "make a datatable, add columns, add rows by providing values for columns"
It would be better to create a strongly typed datatable for this:
Add a new DataSet type of file to your project and goive it a good name
Open it, right click the surface, choose Add DataTable, give it a sensible name
Right click the table, choose Add Column .. add a column and set its name, data type, default value etc...
Repeat until all columns are done
Using this in your code is mostly the same as above, except you make an instance of the table. It is an inner class so you create it using the name of the dataset too:
var dt = new YourDataSetNameHere.YourDataTableNameHere_DataTable();
//the columns are already added, you don't need to add them
foreach(var line in ...){
...
dt.Add_YourDataTableNameHere_Row(
bits[0], //Name
int.Parse(bits[1]), //Age
DateTime.Parse(bits[2]), //HireDate
bool.Parse(bits[3]) //IsManager
);
}
They're a lot nicer to use than regular weakly typed datatables
I have 500 Columns in my DataTable and I want to remove all of them except for 25 columns.
Is there any way to do this faster to save time and lines of code?
This is what I already tried:
private static void DeleteUselessColumns()
{
//This is example data!
List<DataColumn> dataColumnsToDelete = new List<DataColumn>();
DataTable bigData = new DataTable();
bigData.Columns.Add("Harry");
bigData.Columns.Add("Konstantin");
bigData.Columns.Add("George");
bigData.Columns.Add("Gabriel");
bigData.Columns.Add("Oscar");
bigData.Columns.Add("Muhammad");
bigData.Columns.Add("Emily");
bigData.Columns.Add("Olivia");
bigData.Columns.Add("Isla");
List<string> columnsToKeep = new List<string>();
columnsToKeep.Add("Isla");
columnsToKeep.Add("Oscar");
columnsToKeep.Add("Konstantin");
columnsToKeep.Add("Gabriel");
//This is the code i want to optimize------
foreach (DataColumn column in bigData.Columns)
{
bool keepColumn = false;
foreach (string s in columnsToKeep)
{
if (column.ColumnName.Equals(s))
{
keepColumn = true;
}
}
if (!keepColumn)
{
dataColumnsToDelete.Add(column);
}
}
foreach(DataColumn dataColumn in dataColumnsToDelete)
{
bigData.Columns.Remove(dataColumn);
}
//------------------------
}
var columnsToKeep = new List<string>() { "Isla", "Oscar", "Konstantin", "Gabriel"};
var toRemove = new List<DataColumn>();
foreach(DataColumn column in bigData.Columns)
{
if (!columnsToKeep.Any(name => column.ColumnName == name ))
{
toRemove.Add(column);
}
}
toRemove.ForEach(col => bigData.Columns.Remove(col));
Test1...test9 same code could be made a loop. No need to add the columns to delete in a list, just delete them in the first while loop. As for performance, not sure how to improve it.
You could try to use a DataView that selects the desired columns then copy to table. You need to experiment.
if they have different names create an array of string
var columns = new string[] { "Harry", "Konstantin","John"};
var columnsToKeep = new string[] { "John", "Konstantin"};
var columnsToDelete = from item in columns
where !columnsToKeep.Contains(item)
select item;
or using lambda
var columnsToDelete = columns
.Where (i=> !columnsToKeep.Contains(i))
.ToList();
toDelete
Harry
I have a datagridview with values that I add manualy with a datasource, however I want to add a button where the user can shuffle the order of where the values are located in the datagridview. Does anyone have an idead on how to apply this?
if it comes from sql statement with
SELECT * FROM table
ORDER BY NEWID()
but if it is a different form of datasource
var data = //un randomed data
var randomData = data.OrderBy(x => Guid.NewGuid()).ToList();
//then bind randomData to your datasource
so on button click, update it by
getData(){
//use either sql statement or OrderBy() then bind
}
Add a hidden column that contains a random number and sort the rows using that.
If you set AutoGenerateColumns to false you can specify the order of the columns.
void ShuffleDataGridView(DataGridView dataGridView, DataTable dataTable)
{
// add or update random sort order column
const string randomSortConst = "RandomSort";
if (!dataTable.Columns.Contains(randomSortConst))
{
dataTable.Columns.Add(randomSortConst, typeof(int));
}
var rand = new Random();
foreach (DataRow drw in dataTable.Rows)
{
drw[randomSortConst] = rand.Next();
}
// randomize column display
dataGridView.AutoGenerateColumns = false;
dataGridView.AllowUserToOrderColumns = false;
dataGridView.Columns.Clear();
var columnsToAdd = new List<DataColumn>();
foreach (DataColumn dcl in dataTable.Columns)
{
if (!(dcl.ColumnName == randomSortConst))
{
columnsToAdd.Add(dcl);
}
}
while (columnsToAdd.Count > 0)
{
var j = rand.Next(0, columnsToAdd.Count - 1);
var dgvtbc = new DataGridViewTextBoxColumn
{
DataPropertyName = columnsToAdd[j].ColumnName,
HeaderText = columnsToAdd[j].ColumnName // remove this line to hide column headings
};
dataGridView.Columns.Add(dgvtbc);
columnsToAdd.RemoveAt(j);
}
// sort the rows using the hidden random column
dataGridView.DataSource = new DataView(dataTable, string.Empty, randomSortConst, DataViewRowState.CurrentRows);
}
I have a data table like below:
field_1 field_1 field_2 field_2
1 2 3 4
Now I want to convert it to:
field_1 field_2
1 3
2 4
using c#.
I tried to use this code to add columns header, but i cannot import rows to it:
private DataTable test(DataTable dispTable)
{
DataTable outputTbl = new DataTable();
int index = 0;
// Get list values of datatable
var stringArr = dispTable.Rows[0].ItemArray.Select(x => x.ToString()).ToArray();
// Add column headers
outputTbl.Columns.Add("hidden_col");
foreach (DataColumn dc in dispTable.Columns)
{
if (index % 2 == 0) //dispTable always contain 1 pair of column with same name
{
// Create a new column
outputTbl.Columns.Add(dc.ColumnName);
}
// Moving to next col
index++;
}
return outputTbl;
}
How to do it?
Are you looking for something like this?
public void Test(DataTable indata)
{
DataTable outdata = new DataTable();
ArrayList columns = new ArrayList();
// create a outdatatable to contain only distinct coulmn names
foreach (DataColumn dc in indata.Columns)
{
if (!columns.Contains(dc.ColumnName))
{
columns.Add(dc.ColumnName);
outdata.Columns.Add(dc);
}
}
foreach (DataRow dr in indata.Rows)
{
DataRow outdr = outdata.NewRow();
outdr["field_1"] = dr["field_1"] + " " +dr["field_1"]; // dont think it is possible to have two coulmns of same name
outdr["field_2"] = dr["field_2"] + " " + dr["field_2"];
}
}
Would someone kindly assist me with the following? I have two DataGridView objects that each display a DataTable, where the two datatables are related with the following code:
DataSet dSet = new DataSet();
DataTable ParentList = ListToDataTable(_listOfAllAlbumObjects);
DataTable ChildList = ListToDataTable(_listOfAllTrackObjects);
dSet.Tables.AddRange(new DataTable[]{ParentList, ChildList});
DataColumn parentRelationColumn = ParentList.Columns["AlbumId"];
DataColumn childRelationColumn = ChildList.Columns["AlbumId"];
dSet.Relations.Add("ParentToChild", parentRelationColumn, childRelationColumn);
ParentDataGridView.DataSource = dSet;
ParentDataGridView.DataMember = "ParentList";
ChildDataGridView.DataSource = ???;
ChildDataGridView.DataMember = "ParentToChild";
Both DataTables are actually List<> converted to DataTables with the following:`
public static DataTable ListToDataTable<T>( IList<T> data)
{
var props = TypeDescriptor.GetProperties(typeof(T));
var table = new DataTable();
for (var i = 0; i < props.Count; i++)
{
PropertyDescriptor prop = props[i];
table.Columns.Add(prop.Name, prop.PropertyType);
}
var values = new object[props.Count];
foreach (T item in data)
{
for (int i = 0; i < values.Length; i++)
{ values[i] = props[i].GetValue(item); }
table.Rows.Add(values);
}
return table;
}
Initially it appears that the each DataGridView displays the data appropriately; however the child DataGridView does not update with any change of record in the parent DataGridView.
I see that the tables need to be interconnected through the binding-source; however I don't believe there is a true binding-source here.
Could someone please steer me in the right direction? Thanks.
There's an MSDN article showing what you want to do:
How to: Create a Master/Detail Form Using Two Windows Forms DataGridView Controls
Here's how this might work for you:
Either through the designer or through code add two BindingSources to your project: parentBindingSource and childBindingSource. Then try this in place of the code you have.
// Associate your BSs with your DGVs.
ParentDataGridView.DataSource = parentBindingSource;
ChildDataGridView.DataSource = childBindingSource;
// (Most of) your code here:
DataSet dSet = new DataSet();
DataTable ParentList = ListToDataTable(_listOfAllAlbumObjects);
DataTable ChildList = ListToDataTable(_listOfAllTrackObjects);
dSet.Tables.AddRange(new DataTable[]{ParentList, ChildList});
DataColumn parentRelationColumn = ParentList.Columns["AlbumId"];
DataColumn childRelationColumn = ChildList.Columns["AlbumId"];
dSet.Relations.Add("ParentToChild", parentRelationColumn, childRelationColumn);
// Let's name this DT to make clear what we're referencing later on.
ParentList.TableName = "ParentListDT";
// Rather than set the data properties on your DGVs, set them in your BindingSources.
parentBindingSource.DataSource = dSet;
parentBindingSource.DataMember = "ParentListDT";
childBindingSource.DataSource = parentBindingSource;
childBindingSource.DataMember = "ParentToChild";