Delete a specific row from datatable - c#

I am trying to delete a specific row from datatable. When adding the last row, I need to delete the yellow colored rows. It is very easy to Select from a datatable like below
DataRow[] dr = dt.Select("STOK_KODU='HAMMADDE_2'");
I was wondering if there is a way like below to delete ??? Or would you advice an easy way to delete a rows from datatable?
dt.Delete("STOK_KODU='HAMMADDE_2'");

One way is to recreate the table with the rows you want to keep:
dt = dt.AsEnumerable()
.Where(row => row.Field<string>("STOK_KODU") != "HAMMADDE_2")
.CopyToDataTable()
The other is to use DataRowCollection.Remove:
DataRow[] rowsToRemove = dt.Select("STOK_KODU='HAMMADDE_2'");
foreach (var rowToDelete in rowsToRemove)
dt.Rows.Remove(rowToDelete);
The second approach is more efficient if you want to delete few rows and the table is large. The first approach using LINQ is more powerful since you can use any code but it can be less efficient.

You can access the Rows collection of the DataTable:
foreach (var row in dr)
dt.Rows.Remove(row);

try this ::
DataRow[] rows;
rows=dt.Select("STOK_KODU='HAMMADDE_2'");
foreach(DataRow r in rows)
r.Delete();

Deleting rows from an in memory DataTable object is really easy
dt.Select("STOK_KODU='HAMMADDE_2'").AsEnumerable().ToList().ForEach(x => x.Delete());
However you should consider that the Delete method simply marks the RowState to Deleted, but the rows are still in the DataTable.Rows collection. To really remove them you need to call
dt.AcceptChanges();
without this call, if you loop over the datatable rows collection, you need to check the RowState to avoid an error message stating that you cannot access the information of a deleted row
foreach(DataRow r in dt.Rows)
{
if(r.RowState != DataRowState.Deleted)
Console.WriteLine(r[0].ToString());
}

Related

Iterate Foreach loop in accordance with first row to get all recors of Table

In following code i want read dataset records for only once to avoid database transaction and want to iterate loop in accordance with first row.
//InitializeConfig method return dataset which contains 6 records
// i.e. Table with 6 rows and 6 columns
dsConfig = objConfig.InitializeConfig(objConfig, NoOfGates);
foreach (DataRow dr in dsConfig.Tables[0].Rows)
{
objCR.GetCard(objConfig.iIndex, objConfig.iCRNo, out MainId);
}
but I am getting always records from first rows only for each iteration.
The question is rather unclear, but let me expand on the comment from venerik. It is pointless to iterate over rows when you're not using them inside the loop body.
foreach (DataRow dr in dsConfig.Tables[0].Rows)
{
// starting from here the variable dr is available
Console.WriteLine(dr["GateNo"].ToString()) // this should print the value of GateNo column for each row
objCR.GetCard(objConfig.iIndex, objConfig.iCRNo, out MainId);
}
Here No need to use Foreach loop simply I can Iterate for loop for my dataset Object
for(i=0; i<dsConfig.Rows.Count; i++)
{
objCR.GetCard(Convert.ToInt32(dsConfig.Tables[0].Rows[i].ItemArray[2]), Convert.ToInt32(dsConfig.Tables[0].Rows[i].ItemArray[3]), out MainId);
}
Because My iIndex and iCRNo parameters from dataset passed to GetCard Method.

How to remove more DataTable Columns using C#.Net?

I have One DataTable may have more Columns. But "NetAmount", "TotalAmount", "Destination" are the DataTable Columns which always present in the DataTable.
Here I want to Remove the three Columns such as "NetAmount", "TotalAmount" and "Destination" from the DataTable and to take the other column values in the DataTable.
I tried like the below and get the Desired Output.
dtAttribute.Columns.Remove("NetAmount"); //dtAttribute is the Main DataTable
dtAttribute.Columns.Remove("TotalAmount");
dtAttribute.Columns.Remove("Destination");
DataTable dtItem = dtAttribute.Copy();
But it looks like very childish and lengthy. Is there any other method to do? Please give suggestions.
There's nothing wrong with your code (except that you are copying the table after removing the columns -- are you sure that this is what you want?).
If you want something more abstract (instead of repeating the same line again and again), you might consider removing the columns in a loop:
var dtItem = dtAttribute.Copy(); // if you want to keep a copy of the original table
var toRemove = new string[] {"NetAmount", "TotalAmount", "Destination"};
foreach (col in toRemove)
dtItem.Columns.Remove(col);
Instead of removing the columns, how about not putting them in the DataTable in the first place?
First select columns which you want to remove, then remove them
List<string> toRemove = dt.Columns.Cast<DataColumn>().Where(c => c.ColumnName.StartsWith("ExtraColumn")).Select(c => c.ColumnName).ToList();
foreach (var col in toRemove) dt.Columns.Remove(col);

How to assign a row collection (obtained by a linq query) to a datatable without using a loop?

I've scenario where the datatable may contain large number of rows. As a result i can't iterate and update the datatable using a loop.
I am using the following code to get row collection,
from row in CSVDataTable.AsEnumerable()
where CSVDataTable.Columns.Cast<DataColumn>().Any(col => !row.IsNull(col))
select row;
Any one please tell me how to assign the result of the above code to a datatable without using a loop.
I could assign the Linq query result to a data table by the following code,
// Create a DataTable from Linq query.
IEnumerable<DataRow> query = from row in CSVDataTable.AsEnumerable()
where CSVDataTable.Columns.Cast<DataColumn>().Any(col => !row.IsNull(col))
select row; //returns IEnumerable<DataRow>
DataTable CSVDataTableWithoutEmptyRow = query.CopyToDataTable<DataRow>();
See the link for further details,
http://msdn.microsoft.com/en-us/library/bb386921.aspx
You are trying to avoid the unavoidable I think.
You have a "lazy" query wich returns an IEnumerable<DataRow>. This query will be enumerated no matter what when you try to access the DataRow collection it represents.
The only difference will be if you do it directly or some method of DataTable hides that implementation detail.
I'd do the following:
DataTable table;
table.BeginLoadData();
foreach (DataRow row in query)
{
table.ImportRow(row);
}
table.EndLoadData();

Deleting specific rows from DataTable

I want to delete some rows from DataTable, but it gives an error like this,
Collection was modified; enumeration operation might not execute
I use for deleting this code,
foreach(DataRow dr in dtPerson.Rows){
if(dr["name"].ToString()=="Joe")
dr.Delete();
}
So, what is the problem and how to fix it? Which method do you advise?
If you delete an item from a collection, that collection has been changed and you can't continue to enumerate through it.
Instead, use a For loop, such as:
for(int i = dtPerson.Rows.Count-1; i >= 0; i--)
{
DataRow dr = dtPerson.Rows[i];
if (dr["name"] == "Joe")
dr.Delete();
}
dtPerson.AcceptChanges();
Note that you are iterating in reverse to avoid skipping a row after deleting the current index.
Before everyone jumps on the 'You can't delete rows in an Enumeration' bandwagon, you need to first realize that DataTables are transactional, and do not technically purge changes until you call AcceptChanges()
If you are seeing this exception while calling Delete, you are already in a pending-changes data state. For instance, if you have just loaded from the database, calling Delete would throw an exception if you were inside a foreach loop.
BUT! BUT!
If you load rows from the database and call the function 'AcceptChanges()' you commit all of those pending changes to the DataTable. Now you can iterate through the list of rows calling Delete() without a care in the world, because it simply ear-marks the row for Deletion, but is not committed until you again call AcceptChanges()
I realize this response is a bit dated, but I had to deal with a similar issue recently and hopefully this saves some pain for a future developer working on 10-year-old code :)
P.s. Here is a simple code example added by Jeff:
C#
YourDataTable.AcceptChanges();
foreach (DataRow row in YourDataTable.Rows) {
// If this row is offensive then
row.Delete();
}
YourDataTable.AcceptChanges();
VB.Net
ds.Tables(0).AcceptChanges()
For Each row In ds.Tables(0).Rows
ds.Tables(0).Rows(counter).Delete()
counter += 1
Next
ds.Tables(0).AcceptChanges()
with this solution:
for(int i = dtPerson.Rows.Count-1; i >= 0; i--)
{
DataRow dr = dtPerson.Rows[i];
if (dr["name"] == "Joe")
dr.Delete();
}
if you are going to use the datatable after deleting the row, you will get an error. So what you can do is:
replace dr.Delete(); with dtPerson.Rows.Remove(dr);
This works for me,
List<string> lstRemoveColumns = new List<string>() { "ColValue1", "ColVal2", "ColValue3", "ColValue4" };
List<DataRow> rowsToDelete = new List<DataRow>();
foreach (DataRow row in dt.Rows) {
if (lstRemoveColumns.Contains(row["ColumnName"].ToString())) {
rowsToDelete.Add(row);
}
}
foreach (DataRow row in rowsToDelete) {
dt.Rows.Remove(row);
}
dt.AcceptChanges();
DataRow[] dtr = dtPerson.Select("name=Joe"); //name is the column in the data table
foreach(var drow in dtr)
{
drow.Delete();
}
dtperson.AcceptChanges();
To remove entire row from DataTable , do like this
DataTable dt = new DataTable(); //User DataTable
DataRow[] rows;
rows = dt.Select("UserName = 'KarthiK'"); //'UserName' is ColumnName
foreach (DataRow row in rows)
dt.Rows.Remove(row);
Or just convert a DataTable Row collection to a list:
foreach(DataRow dr in dtPerson.Rows.ToList())
{
if(dr["name"].ToString()=="Joe")
dr.Delete();
}
Where is the problem: It is forbidden to delete items from collection inside a foreach loop.
Solution: Either do it like Widor wrote, or use two loops. In the first pass over DataTable you only store (in a temporary list) the references to rows you want to delete. Then in the second pass over your temporary list you delete those rows.
<asp:GridView ID="grd_item_list" runat="server" AutoGenerateColumns="false" Width="100%" CssClass="table table-bordered table-hover" OnRowCommand="grd_item_list_RowCommand">
<Columns>
<asp:TemplateField HeaderText="No">
<ItemTemplate>
<%# Container.DataItemIndex + 1 %>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Actions">
<ItemTemplate>
<asp:Button ID="remove_itemIndex" OnClientClick="if(confirm('Are You Sure to delete?')==true){ return true;} else{ return false;}" runat="server" class="btn btn-primary" Text="REMOVE" CommandName="REMOVE_ITEM" CommandArgument='<%# Container.DataItemIndex+1 %>' />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
**This is the row binding event**
protected void grd_item_list_RowCommand(object sender, GridViewCommandEventArgs e) {
item_list_bind_structure();
if (ViewState["item_list"] != null)
dt = (DataTable)ViewState["item_list"];
if (e.CommandName == "REMOVE_ITEM") {
var RowNum = Convert.ToInt32(e.CommandArgument.ToString()) - 1;
DataRow dr = dt.Rows[RowNum];
dr.Delete();
}
grd_item_list.DataSource = dt;
grd_item_list.DataBind();
}
I know this is, very, old question, and I have similar situation few days ago.
Problem was, in my table are approx. 10000 rows, so looping trough DataTable rows was very slow.
Finally, I found much faster solution, where I make copy of source DataTable with desired results, clear source DataTable and merge results from temporary DataTable into source one.
note : instead search for Joe in DataRow called name You have to search for all records whose not have name Joe (little opposite way of searching)
There is example (vb.net) :
'Copy all rows into tmpTable whose not contain Joe in name DataRow
Dim tmpTable As DataTable = drPerson.Select("name<>'Joe'").CopyToTable
'Clear source DataTable, in Your case dtPerson
dtPerson.Clear()
'merge tmpTable into dtPerson (rows whose name not contain Joe)
dtPerson.Merge(tmpTable)
tmpTable = Nothing
I hope so this shorter solution will help someone.
There is c# code (not sure is it correct because I used online converter :( ):
//Copy all rows into tmpTable whose not contain Joe in name DataRow
DataTable tmpTable = drPerson.Select("name<>'Joe'").CopyToTable;
//Clear source DataTable, in Your case dtPerson
dtPerson.Clear();
//merge tmpTable into dtPerson (rows whose name not contain Joe)
dtPerson.Merge(tmpTable);
tmpTable = null;
Of course, I used Try/Catch in case if there is no result (for example, if Your dtPerson don't contain name Joe it will throw exception), so You do nothing with Your table, it stays unchanged.
You try this for getting and removing id column from data table
if (dt1.Columns.Contains("ID"))
{
for (int i = dt1.Rows.Count - 1; i >= 0; i--)
{
DataRow dr = dt1.Rows[i];
if (dr["ID"].ToString() != "" && dr["ID"].ToString() != null)
{
dr.Delete();
}
}
dt1.Columns.Remove("ID");
}
I'm seeing various bits and pieces of the right answer here, but let me bring it all together and explain a couple of things.
First of all, AcceptChanges should only be used to mark the entire transaction on a table as being validated and committed. Which means if you are using the DataTable as a DataSource for binding to, for example, an SQL server, then calling AcceptChanges manually will guarantee that that the changes never get saved to the SQL server.
What makes this issue more confusing is that there are actually two cases in which the exception is thrown and we have to prevent both of them.
1. Modifying an IEnumerable's Collection
We can't add or remove an index to the collection being enumerated because doing so may affect the enumerator's internal indexing.
There are two ways to get around this: either do your own indexing in a for loop, or use a separate collection (that is not modified) for the enumeration.
2. Attempting to Read a Deleted Entry
Since DataTables are transactional collections, entries can be marked for deletion but still appear in the enumeration. Which means that if you ask a deleted entry for the column "name" then it will throw an exception.
Which means we must check to see whether dr.RowState != DataRowState.Deleted before querying a column.
Putting it all together
We could get messy and do all of that manually, or we can let the DataTable do all the work for us and make the statement look and at more like an SQL call by doing the following:
string name = "Joe";
foreach(DataRow dr in dtPerson.Select($"name='{name}'"))
dr.Delete();
By calling DataTable's Select function, our query automatically avoids already deleted entries in the DataTable. And since the Select function returns an array of matches, the collection we are enumerating over is not modified when we call dr.Delete(). I've also spiced up the Select expression with string interpolation to allow for variable selection without making the code noisy.
I have a dataset in my app and I went to set changes (deleting a row) to it but ds.tabales["TableName"] is read only. Then I found this solution.
It's a wpf C# app,
try {
var results = from row in ds.Tables["TableName"].AsEnumerable() where row.Field<string>("Personalid") == "47" select row;
foreach (DataRow row in results) {
ds.Tables["TableName"].Rows.Remove(row);
}
}
the easy way use this in button :
var table = $('#example1').DataTable();
table.row($(`#yesmediasec-${id}`).closest('tr')).remove( ).draw();
example1 = id table .
yesmediasec = id of the button in the row
use it and every thing will be ok

How to remove rows from huge data table without iterating it?

I have a DataTable available with me which contains thousands of rows. There is a column called EmpID which is containing '0' for some of the rows. I want to remove them from my current DataTable and want to create a new correct DataTable. I cannot go row by row checking it since it contains huge amount of data. Give me a suggestion to overcome this problem.
the best way would be to filter it at source (if possible) - so if you are creating it from a db, exclude all 0 values in your sql query itself using a where
starting .net 2.0, ms enhanced the filtering logic on the datatable to a great extent. so if you used the dataview (on top of your datatable) and added the where clause in there and added some sort of runtime indexes on this field, it would give you the desired results without looping over all records
You can use DataTable.Select("EmpID <> 0"). This will return an array of DataRows which you can create your new DataTable from if required.
Isn't it possible to first select the rows with EmpID = 0 and then iterate over these only ?
DataTable newTable = new DataTable();
foreach (DataRow dr in oldTable.Select("EmpID = '0'")) {
newTable.Rows.Add(dr);
oldTable.Rows.Remove(dr);
}
You can try
DataRow[] temp=
table.Select("EmpID ='0'");
foreach(DataRow dr in temp)
{
table.Rows.Remove(dr);
}
table.acceptchanges();

Categories