Sorting Datarows using any dataColumn - c#

I have a following datatable with 3 columns.
I want to sort the datatable rows on the basis of 2nd column.(with header E)
Is there any built in function do this?
i tried..
dt.DefaultView.Sort = dt.Columns[1].ColumnName;
dt.AcceptChanges();

Probably the easiest (and most powerful) way is to use Linq-To-DataSet and Enumerable.OrderBy:
var tblOrdered = tbl.AsEnumerable()
.OrderBy(row => row.Field<int>("E"))
.CopyToDataTable();
If you cannot use Linq, you can use DataView.Sort:
DataView view = tbl.DefaultView;
view.Sort = "E ASC";
But that uses a DataView, the original DataTable is unsorted.
So if you need the table, you could use DataView.ToTable:
tbl = view.ToTable();

You can sort a datable by column
dt.DefaultView.Sort = "E Asc";
Else this way
string[] names = new string[dt.Rows.Count];
for (int i = 0; i < dt.Rows.Count; i++)
{
names[i] = dt.Rows[i]["E"].ToString();
}
Array.Sort(names);
for (int i = 0; i < dt.Rows.Count; i++)
{
dt.Rows[i]["E"] = names[i];
}
Also dt.AcceptChanges will commits all the changes made to the table. aah msdn also say that it must be called after attempt to update is made
Remarks from MSDN
When AcceptChanges is called, any DataRow object still in edit mode
successfully ends its edits. The DataRowState also changes: all Added
and Modified rows become Unchanged, and Deleted rows are removed.
The AcceptChanges method is generally called on a DataTable after you
attempt to update the DataSet using the DbDataAdapter.Update method.

Related

Change values of Cells in a Filtered DataGridView

I have DataGridView with a Column named flag and others.
When I apply a filter:
dataGridView2.DataSource =
new DataView(ds, "flag = 1", "tw_Name DESC", DataViewRowState.CurrentRows);
it shows only Rows where he Column flag value is equal to 1, but...
when I try to programmatically change this value, for example in 6 checked rows:
foreach (DataGridViewRow row in dataGridView2.Rows)
{
if (Convert.ToBoolean(row.Cells["zazn"].Value))
{
row.Cells["flags"].Value = 0;
}
}
three Rows disappear, one Row changes its value, two Rows do not change.
Next, when I click any Row, I get only 2 of the desired changes.
Since you're working with a DataTable, it's preferable that you modify the values of its Rows' content instead the DataGridView Cells while a Filter is active on the DataTable's DataView.
This causes the immediate propagation of the data changes, which your DataGridView will acknowledge. Not guaranteed if you do the opposite, trying to propagate the Control's changes to the DataSource.
This may go against the internal mechanics used by the Control to notify the changes to its DataSource: a DataGridView notify value changes of its Cells after the Cell edit has completed and validation has been performed.
You could try to call [DataGridView].EndEdit() and Validate(), it doesn't mean that in any circumstance the Control and the DataSource will synchronize when you expect it to happen.
Set the Filter and order the View:
Note that the order is applied to the DefaultView, not the DataTable. The Rows' order in the DataTable remains unchanged.
In your sample code, a filter is set to flag = 1, while you use another name for the Column in row.Cells["flags"].
var dView = (dataGridView2.DataSource as DataTable).DefaultView;
dView.RowFilter = "flag = 1";
dView.Sort = "tw_Name DESC";
When you need to change values in some of the Rows, access the DataTable using the DataGridView.DataSource and cast it to DataTable (or BindingSouce or whatever other source of data you have used).
You can now loop the DataRows and set new values to some Columns base on a condition, as in this case:
var dt = dataGridView2.DataSource as DataTable;
for (int i = 0; i <= dt.Rows.Count - 1; i++) {
var row = dt.Rows[i];
if (row["zazn"] != DBNull.Value && (bool)row["zazn"]) {
row["flag"] = 0;
}
}
You could do the same thing using the DataGridView.Row.DataBoundItem, which is a DataRowView in this case, looping backwards (to only loop the visible Rows):
var dt = dataGridView2.DataSource as DataTable;
//BACKWARDS - also assuming there's a NewRow, so Rows.Count - 2
for (int i = dataGridView2.Rows.Count - 2; i >= 0; i--) {
var row = (dataGridView2.Rows[i].DataBoundItem as DataRowView).Row;
if (row["zazn"] != DBNull.Value && (bool)row["zazn"]) {
row["flag"] = 0;
}
}
If you do the same but with a forward loop:
for (int i = 0; i < dataGridView2.Rows.Count - 1; i++) { ... }
you're in the same situation as before.

Update :Result is not transfered to the orginal dataset. Sorting Rows in Dataset using C#

Update: even though I have got the required result but when the the second function access the data table the value is still the same
It a sequential program with two functions in different classes. First sort and second replace function. So it should sort the value and other function should be able to retrieve the sorted table but when it retrieve the datatable it gives the unsorted table.
I have used acceptchanges() but it also give the same result.
The program is trying to sort the table according to the required field and the result is stored in Sorted table variable. I am trying to copy this to the original i-e sourceTables but it is not working and is adding another row instead of updating [As shown in below dig]. I have tried to copy whole table but it does not work and by adding rows it is not giving the required result. I have used different methods but I am not getting the required result.
List<DataTable> sourceTables = context.GetDataByTable(sourceTable.StringValue);
List<DataTable> targetTables = context.GetDataByTable(targetTable.StringValue, sourceTables.Count);
string orderDesc= orderField.StringValue + " DESC";
for (int i = 0; i < sourceTables.Count; i++)
{
DataView dv = sourceTables[i].DefaultView;
if (orderDirection.StringValue == OrderDirectionAsc)
{
// for Sorting in Ascending Order
dv.Sort = orderField.StringValue;
}
else
{
// for Sorting in Descending Order
dv.Sort = orderDesc;
}
DataTable sortedTable = dv.ToTable();
DataTable dttableNew = sortedTable.Clone();
//sourceTables[i] = sortedTable.Copy();
//targetTables[i] = dv.ToTable();
//targetTables[i] = sortedTable.Copy();
// foreach (DataRow dr in sortedTable.Rows)
//// targetTables[i].Rows.Add(dr.ItemArray);
//}
for (int j = 0; j < sourceTables[i].Rows.Count; j++)
{
if (sourceTable.GetValue().ToString() == targetTable.GetValue().ToString())
{
foreach (DataRow dr in sortedTable.Rows)
{
targetTables[i].Rows.Add(dr.ItemArray);
}
else
{
foreach (DataRow dr in sortedTable.Rows)
{
targetTables[i].Rows.Add(dr.ItemArray);
}
// targetTables[i] = sortedTable.Copy(); does not work
//foreach (DataRow drtableOld in sortedTable.Rows)
//{
// targetTables[i].ImportRow(drtableOld);
//}
Instead of replacing the first values it is adding more rows
any help would be appreciated
If any one have problem with duplicate data or the changes are only local and is not effecting the original data table. Remember to always use .ImportRow(dr) function to add rows to the table and if you use Tables[i].Rows.Add(dr.ItemArray); the changes will affect only the local table and not the original one. Use .clear to remove the old rows from the orginal table. The action done directly on the original function will only effect the rows. If it is done on the clone copy changes will nor affect the original table.
Here is the complete code
DataTable sortTable = dv.ToTable();
if (sTable.GetValue().ToString() == tTable.GetValue().ToString())
{
sTables[i].Clear();
foreach (DataRow dr in sortTable.Rows)
{
sTables[i].ImportRow(dr);
}
sTables[i].AcceptChanges();
}

Iterating through 2 lists at a time using while

var itemAmountList = _itemAmountvalue.Split(',');
var listItemDescriptionValues = _itemDescriptionvalue.Split(',');
IEnumerator enum1 = itemAmountList.GetEnumerator();
IEnumerator enum2 = listItemDescriptionValues.GetEnumerator();
DataTable dtCustomInvoiceDetail = new DataTable();
dtCustomInvoiceDetail.Columns.Add("purchaseOrderID");
dtCustomInvoiceDetail.Columns.Add("itemAmount");
dtCustomInvoiceDetail.Columns.Add("itemDescription");
while ((enum1.MoveNext()) && (enum2.MoveNext()))
{
var description = enum1.Current;
var amount = enum2.Current;
DataRow dr = dtCustomInvoiceDetail.NewRow();
dr["itemDescription"] = description;
dr["itemAmount"] = amount;
dr["purchaseOrderID"] = strPoid;
}
Above is the code that I am using to iterate through a list and populate a datatable.
I do not see any rows added to the datatable
Verified the data and looks good
it iterates through the loop the no of times as required
But still do not see any data in the datatable
In your code
DataRow dr = dtCustomInvoiceDetail.NewRow();
does not actually add a row to the table, it only creates a table row with the correct columns. In order to add the row you need to call
dtCustomInvoiceDetail.Rows.Add(dr)
at the end
the problem is that you are not adding the generated row to datatable.
Datatable.NewRow :
You must use the NewRow method to create new DataRow objects with
the same schema as the DataTable. After creating a DataRow, you
can add it to the DataRowCollection, through the DataTable
object's Rows property
you should add the row to your datatable like this
dtCustomInvoiceDetail.Rows.Add(dr);
also note that you can convert the whole enumerator logic to a simple for loop, it has more readability and less overhead
for (int i = 0; i < Math.Min(itemAmountList.Count, listItemDescriptionValues.Count); i++)
{
var description = itemAmountList[i];
var amount = listItemDescriptionValues[i];
DataRow dr = dtCustomInvoiceDetail.NewRow();
dr["itemDescription"] = description;
dr["itemAmount"] = amount;
dr["purchaseOrderID"] = strPoid;
}
also it seems that there is an inconsistency between names and variable assignments. you assign a value from listItemDescriptionValues to amount variable and from itemAmountList to description. Please double check it.

Large sorted datatable "wraps" around

I am attempting to remove duplicates from a .NET datatable consisting of more than 50,000 rows. My approach is simple: I want to sort the datatable alphabetically, then scan through looking for rows that are the same as the row above it.
The problem I'm having is that the datatable "wraps" around when sorted. I use this to sort it:
myDataTable.DefaultView.Sort = "name";
When I view the datatable using the debugger, it is sorted alphabetically in chunks, like so:
Aardvark
Apple
Banana
...(20,000 rows later)...
Aardvark
Angle
Boat
Obviously this ruins my attempt to find duplicates. Is this some sort of optimization behavior of the framework when dealing with large tables? What is going on here?
Solution:
Here is what I was doing..
myDataTable.DefaultView.Sort = "name";
for (int i =0; i< myDataTable.DefaultView.Table.Rows.Count; i++)
{
var thisRow = myDataTable.DefaultView.Table.Rows[i];
var prevRow = myDataTable.DefaultView.Table.Rows[i-1];
}
Here is what I should have been doing:
myDataTable.DefaultView.Sort="name";
var myNewDatatable = myDataTable.DefaultView.ToTable();
for (int i =0; i< myNewDatatable.Rows.Count; i++)
{
var thisRow = myNewDatatable.Rows[i];
var prevRow = myNewDatatable.Rows[i-1];
}
myDataTable.DefaultView.Sort = "name";
Here you're sorting the DataView for the DataTable and not the DataTable.
So you have to either use the DataView (myDataTable.DefaultView)
or getting the DataRow's of the DataTable sorted by name
DataRow[] sorted = myDataTable.Select("", "name");
You can use this overload to accomplish this.
DataTable uniqueTable = myDataTable.DefaultView.ToTable("UniqueStuff", true, "SomeCol", "AnotherCol", "YetAnotherCol");

Copy rows from one Datatable to another DataTable?

How can I copy specific rows from DataTable to another Datable in c#? There will be more than one row.
foreach (DataRow dr in dataTable1.Rows) {
if (/* some condition */)
dataTable2.Rows.Add(dr.ItemArray);
}
The above example assumes that dataTable1 and dataTable2 have the same number, type and order of columns.
Copy Specified Rows from Table to another
// here dttablenew is a new Table and dttableOld is table Which having the data
dttableNew = dttableOld.Clone();
foreach (DataRow drtableOld in dttableOld.Rows)
{
if (/*put some Condition */)
{
dtTableNew.ImportRow(drtableOld);
}
}
Try This
String matchString="ID0001"//assuming we have to find rows having key=ID0001
DataTable dtTarget = new DataTable();
dtTarget = dtSource.Clone();
DataRow[] rowsToCopy;
rowsToCopy = dtSource.Select("key='" + matchString + "'");
foreach (DataRow temp in rowsToCopy)
{
dtTarget.ImportRow(temp);
}
Check this out, you may like it (previously, please, clone table1 to table2):
table1.AsEnumerable().Take(recodCount).CopyToDataTable(table2,LoadOption.OverwriteChanges);
Or:
table1.AsEnumerable().Where ( yourcondition ) .CopyToDataTable(table2,LoadOption.OverwriteChanges);
Supported in: 4, 3.5 SP1, you can now just call a method on the object.
DataTable dataTable2 = dataTable1.Copy()
As a result of the other posts, this is the shortest I could get:
DataTable destTable = sourceTable.Clone();
sourceTable.AsEnumerable().Where(row => /* condition */ ).ToList().ForEach(row => destTable.ImportRow(row));
I've created an easy way to do this issue
DataTable newTable = oldtable.Clone();
for (int i = 0; i < oldtable.Rows.Count; i++)
{
DataRow drNew = newTable.NewRow();
drNew.ItemArray = oldtable.Rows[i].ItemArray;
newTable.Rows.Add(drNew);
}
I needed to copy rows from multiple tables with the same structure into a new table to be used as a datasource for datagridview:
// Generate DataTable[] alltables from multiple datatables
DataTable newTable = alltables[0].Clone();
foreach (DataTable dt in alltables)
{
for (int i = 0; i < dt.Rows.Count; i++)
newTable.Rows.Add(dt.Rows[i].ItemArray);
}
below sample would be the fastest way to copy one row.
each cell is being copied based on the column name.
in case you dont need a specific cell to copy then have a try catch or add if.
if your going to copy more than 1 row then loop the code below.
DataRow dr = dataset1.Tables[0].NewRow();
for (int i = 0; i < dataset1.Tables[1].Columns.Count; i++)
{
dr[dataset1.Tables[1].Columns[i].ColumnName] = dataset1.Tables[1].Rows[0][i];
}
datasetReport.Tables[0].Rows.Add(dr);
dataset1.Tables[1].Rows[0][i]; change the index 0 to your specified row index or you can use a variable if your going to loop or if its going to be logical
private void CopyDataTable(DataTable table){
// Create an object variable for the copy.
DataTable copyDataTable;
copyDataTable = table.Copy();
// Insert code to work with the copy.
}
To copy whole datatable just do this:
DataGridView sourceGrid = this.dataGridView1;
DataGridView targetGrid = this.dataGridView2;
targetGrid.DataSource = sourceGrid.DataSource;
For those who want single command SQL query for that:
INSERT INTO TABLE002
(COL001_MEM_ID, COL002_MEM_NAME, COL002_MEM_ADD, COL002_CREATE_USER_C, COL002_CREATE_S)
SELECT COL001_MEM_ID, COL001_MEM_NAME, COL001_MEM_ADD, COL001_CREATE_USER_C, COL001_CREATE_S
FROM TABLE001;
This query will copy data from TABLE001 to TABLE002 and we assume that both columns had different column names.
Column names are mapped one-to-one like:
COL001_MEM_ID -> COL001_MEM_ID
COL001_MEM_NAME -> COL002_MEM_NAME
COL001_MEM_ADD -> COL002_MEM_ADD
COL001_CREATE_USER_C -> COL002_CREATE_USER_C
COL002_CREATE_S -> COL002_CREATE_S
You can also specify where clause, if you need some condition.
There is better way to do this.
DataTable targetDataTable = new DataTable();
targetDataTable = changedColumnMetadata.AsEnumerable().Where(dataRow => entityName.Equals(dataRow["EntityName"])).CopyToDataTable();
Please try this and let me know in case of any issues.
You can do it calling the DataTable.Copy() method, for example:
DataSet ds = new DataSet();
System.Data.DataTable dt = new System.Data.DataTable();
dt = _BOSearchView.DS.Tables[BusLib.TPV.TableName.SearchView].Copy();
ds.Tables.Add(dt);
UltGrdSaleExcel.SetDataBinding(ds, dt.TableName, true);
use Merge, this will append all rows of newDataTable with oldDateTale
oldDateTale.Merge(newDataTable);

Categories

Resources