none
Getting a "Deleted row information cannot be accessed through the row." error RRS feed

  • Question

  • I'm working on a WCF service I wrote in VS 2008, .NET 3.5.  I'm passing in a strongly typed data set with 3 data tables in it.  The data reflects what's coming from the client, which is in a SQL Server 2008 Express database.  I'm trying to store the data into a SQL Server 2005 database on a Windows server.  Basically, what I do is go through the passed data, checking to see if relevant data is there, updating it if it isn't.  Then I review the data table from the server and see if it has a record that isn't in the data from the same table on the client (the SQL Express data).  If it isn't, then I call the Delete() method on the strongly typed data table.  I don't attempt to access an of the fields of that record after that point, so I don't see why I should be getting "deleted row information cannot be access through the row" error.  (Later I call a table adapter manager and save all of the changes I made to the data from the backend server.  I've tested inserting new records and this works fine.)  Since I'm doing the same thing for more than 1 table I'll produce below just one set of tables (from the client and from the server) so you get an idea as to what I'm doing.  In the code the data set EmploymentDataSet is from the client (SQL Express), and localEmploy is from the backend SQL Server.  Here's the code segment:

    for (int i = 0; i < EmploymentDataSet.ASIIncomeLast30.Rows.Count; i++)
    {
    	bool found = false;
    	int j = 0;
    	for (; j < localEmploy.ASIIncomeLast30.Rows.Count; j++)
    	{
    		if (EmploymentDataSet.ASIIncomeLast30[i].IncomeType == localEmploy.ASIIncomeLast30[j].IncomeType)
    		{
    			found = true;
    			break;
    		}
    	}
    	if (found)
    	{
    		localEmploy.ASIIncomeLast30[j].AmountEarned = EmploymentDataSet.ASIIncomeLast30[i].AmountEarned;
    	}
    	else
    	{
    		var newRow = localEmploy.ASIIncomeLast30.NewASIIncomeLast30Row();
    		newRow["ClientNumber"] = clientNumber;
    		newRow["CaseNumber"] = caseNumber;
    		newRow["Followup"] = 0;
    		newRow["IncomeType"] = EmploymentDataSet.ASIIncomeLast30[i].IncomeType;
    		newRow["AmountEarned"] = EmploymentDataSet.ASIIncomeLast30[i].AmountEarned;
    		localEmploy.ASIIncomeLast30.Rows.Add(newRow);
    	}
    }
    //see if there's any local income records that need to be removed
    for (int i = 0; i < localEmploy.ASIIncomeLast30.Rows.Count; i++)
    {
    	bool found = false;
    	int j = 0;
    	for (; j < EmploymentDataSet.ASIIncomeLast30.Rows.Count; j++)
    	{
    		if (localEmploy.ASIIncomeLast30[i].IncomeType == EmploymentDataSet.ASIIncomeLast30[j].IncomeType)
    		{
    			found = true;
    			break;
    		}
    	}
    	if (! found)
    	{
    		localEmploy.ASIIncomeLast30[i].Delete();
    	}
    }
    

    The only thing I can think of is could it be possible that calling the Delete() method on the strongly typed data table decrement the count of the number of rows in that data table?  Is that what might be going on?

    Rod

    Friday, March 23, 2012 8:32 PM

Answers

  • Rod,

    What I see is that you have an outer loop and an inner loop. 

    Like I wrote already 3 times the problem you have are almost always because of the enumeration. 

    So the inner loop most probably gives problems because you use the outer enumerator in the inner loop.

    Why not try what I wrote with two While loops?


    Success
    Cor

    • Marked as answer by Rod at Work Monday, June 4, 2012 7:52 PM
    Friday, March 30, 2012 7:47 AM

All replies

  • Most probably the error happens here, because you are looping through all rows, not just not-deleted

    if (localEmploy.ASIIncomeLast30[i].IncomeType == EmploymentDataSet.ASIIncomeLast30[j].IncomeType)
    You might filter the rows beforehand where RowState != DataRowState.Deleted


    Miha Markic [MVP C#] http://blog.rthand.com

    Saturday, March 24, 2012 4:55 PM
  • Never loop in a for forwards through an enumeration. 

    Do that backwards or use a do while (the later need a little bit more changes in your code).

    If you remove forwards then the enumeration will be broken if the previous was deleted.


    Success
    Cor

    Monday, March 26, 2012 8:56 AM
  • The only thing I can think of is could it be possible that calling the Delete() method on the strongly typed data table decrement the count of the number of rows in that data table?  Is that what might be going on?

    yes, that is the case.

    In order to avoid that, try Cor's suggestion and use this:

    for (int i = localEmploy.ASIIncomeLast30.Rows.Count - 1; i >= 0; i--)


    Regards, Nico

    Monday, March 26, 2012 2:24 PM
  • Miha, Cor and Nico,

    I've been swamped the last couple of days with other priorities, so haven't had a chance to try what you've suggested until now.  I just did.  In particular, here's how the code now looks:

    for (int i = localEmploy.ASIIncomeLast30.Rows.Count - 1; i >= 0; i--)
    {
    	bool found = false;
    	int j = 0;
    	for (; j < EmploymentDataSet.ASIIncomeLast30.Rows.Count; j++)
    	{
    		if (localEmploy.ASIIncomeLast30[i].IncomeType == EmploymentDataSet.ASIIncomeLast30[j].IncomeType)
    		{
    			found = true;
    			break;
    		}
    	}
    	if (! found)
    	{
    		localEmploy.ASIIncomeLast30[i].Delete();
    	}
    }
    

    As you can see, I'm now working through the localEmploy.ASIIncomeLast30 array backwards, from Count - 1 to 0.  However, I still got that, "Deleted row information cannot be access through the row." error message.  Any suggestions as to what I might be doing wrong still?

    Rod

    Wednesday, March 28, 2012 4:57 PM
  • Rod,

    In these cases like code of you I do it with a While just forward, I never know when the enumerators for the index are set in these cases so with a while I've no problem.


    Success
    Cor

    Thursday, March 29, 2012 7:17 AM
  • Rod,

    it would help if we knew on what line the error occurs.

    Anyhow, the error occurs when you're trying to read a field from a row that is in a 'deleted' rowstate.

    So you can check this property by putting breakpoints and look for:

    somerow.RowState = RowState.Deleted

    Is it possible that the rows that you get from the client were deleted?

    (i.e. they were marked for deletion, so that a dataadapter.update can delete these rows in the database)

    If that is the case, then you'll have to adapt your code so it checks first if the row is not deleted, before you try to read its fields,

    and/or you can read the fields of a deleted row this way: 

    Debug.Print(someDeletedRow("FieldName", RowVersion.Original).ToString())


    Regards, Nico

    Thursday, March 29, 2012 7:39 AM
  • I had 4 other priorities hitting me today (replacing UPS batteries, working on a SSRS report, doing ad hoc reports for managers), so until an hour ago I've not been able to get back to this.  Here's the line here it's failing:

    if (localEmploy.ASIVocationalNeeds[i].VocNeedType == EmploymentDataSet.ASIVocationalNeeds[j].VocNeedType)

    I created a console app, including all of the projects that comprised my WCF service into the solution for the console app, and found that it's happening here.  I think I finally know what and here the problem is.  Here's how the code currently is:

    for (int i = localEmploy.ASIVocationalNeeds.Rows.Count - 1; i >= 0; i--)
    {
    	bool found = false;
    	int j = 0;
    	err = string.Format("[Checking if we can delete row {0} in ASIVocationalNeeds]", i);
    	for (; j < EmploymentDataSet.ASIVocationalNeeds.Rows.Count; j++)
    	{
    		if (localEmploy.ASIVocationalNeeds[i].VocNeedType == EmploymentDataSet.ASIVocationalNeeds[j].VocNeedType)
    		{
    			found = true;
    			break;
    		}
    		if (! found)
    		{
    			err = string.Format("[Marking row {0} in ASIVocationalNeeds for deletion]", i);
    			localEmploy.ASIVocationalNeeds[i].Delete();
    		}
    	}
    }
    

    It's that if (! found) in the for loop over the count of j that's killing me. I believe my loop should be like this:

    for (int i = localEmploy.ASIVocationalNeeds.Rows.Count - 1; i >= 0; i--)
    {
    	bool found = false;
    	int j = 0;
    	err = string.Format("[Checking if we can delete row {0} in ASIVocationalNeeds]", i);
    	for (; j < EmploymentDataSet.ASIVocationalNeeds.Rows.Count; j++)
    	{
    		if (localEmploy.ASIVocationalNeeds[i].VocNeedType == EmploymentDataSet.ASIVocationalNeeds[j].VocNeedType)
    		{
    			found = true;
    			break;
    		}
    	}
    	if (!found)
    	{
    		err = string.Format("[Marking row {0} in ASIVocationalNeeds for deletion]", i);
    		localEmploy.ASIVocationalNeeds[i].Delete();
    	}
    }
    

    Stupid mistake on my part.

    Rod

    Thursday, March 29, 2012 9:07 PM
  • Rod,

    What I see is that you have an outer loop and an inner loop. 

    Like I wrote already 3 times the problem you have are almost always because of the enumeration. 

    So the inner loop most probably gives problems because you use the outer enumerator in the inner loop.

    Why not try what I wrote with two While loops?


    Success
    Cor

    • Marked as answer by Rod at Work Monday, June 4, 2012 7:52 PM
    Friday, March 30, 2012 7:47 AM