none
DataTable index corruption RRS feed

  • Question

  • I have the following configuration.


    DevExpress XtraTreeList is bound to an sql server 2008 database table with BindingSource component.
    Typed dataset(dsProd) used for the table(customers). Table has a foreign key constraint on it. Also, there is a column that does not allow null.

    I try to update the rows immediately when they are changed/added or deleted and i use ListChanged event for this purpose.
    dsProd.Customers.BeginLoadData()/EndLoadData(); is not used while updating to the database, the following stringent error raised;

     "DataTable internal index is corrupted: '5'."

    However, after adding and saving a record, when that record is modified and saved, index corruption error is raised again which follows a nullreference exception.

    Thus, i have found that when the following code for the Reset case is added, exceptions gone away.
                    case ListChangedType.Reset:
                        dsProd.Customers.BeginLoadData();
                        dsProd.Customers.EndLoadData();
    I don't know how it helped to work around the problem so i have concerns whether it may broke at any occasion.

    I have .Net Framework 3.5 SP1 and updates installed. So .Net Framework 2.0 Sp2 update installed.

    There a lot of articles complaning about the index corruption problem but no one o could provide a solution.
    Microsoft recommends installing SP2 for .net framework 2.0 but it does not solve the problem.
    So, Microsoft does not seem to have a solution to the problem.

    What do you think about it? Are there any people have similar solution like to this one?


            private void Customers_Load(object sender, EventArgs e)
            {
                tlCustomers.RootValue = null;

                tlCustomers.OptionsBehavior.DragNodes = true;

                tlCustomers.OptionsBehavior.ImmediateEditor = false;
                tlCustomers.OptionsBehavior.MoveOnEdit = false;
                tlCustomers.OptionsBehavior.UseTabKey = true;

                // TODO: This line of code loads data into the 'dsProd.Customers' table. You can move, or remove it, as needed.
                this.customersTableAdapter.Fill(this.dsProd.Customers);
            }

           
            private void tlCustomers_AfterDragNode(object sender, DevExpress.XtraTreeList.NodeEventArgs e)
            {
                customersTableAdapter.Update(dsProd.Customers);
            } 

            private void UpdateTheData()
            {
                try
                {
                    dsProd.Customers.BeginLoadData();
                    customersTableAdapter.Update(dsProd.Customers);
                    dsProd.Customers.EndLoadData();
                }
                catch(Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }

            private void customersBindingSource_ListChanged(object sender, ListChangedEventArgs e)
            {
                switch (e.ListChangedType)
                {
                    case ListChangedType.ItemAdded:
                        if (e.NewIndex >= 0)
                        {
                            DataRowView customersRow = customersBindingSource[e.NewIndex] as DataRowView;
                            // Do not try to update to database when row is added but not yet modified and saved to DataTable.
                            if (customersRow != null && customersRow.Row.RowState == DataRowState.Detached)
                                break;
                        }                   
                        UpdateTheData();
                        break;

                    case ListChangedType.ItemDeleted:
                    case ListChangedType.ItemChanged:
                        UpdateTheData();
                        break;
                    case ListChangedType.Reset:
                        dsProd.Customers.BeginLoadData();
                        dsProd.Customers.EndLoadData();
                        break;
                }
            }

    Friday, June 5, 2009 7:54 AM

Answers

  • Looks like you are making changes to the data in the ListChanged event (yes, doing a Update counts as it transitions row versions, syncs identity values with those determined by the database, etc.).  This is asking for trouble with nearly all APIs, not just DataSet.  It is not a good idea to make further modifications to data in an event notifying you that there were changes to the data.

    I'm not sure what you are trying to accomplish.  Most programs provide a button that saves the data to the database on demand and does not attempt to write every change to the database as soon as it is made.  If you really must, you might see whether calling BeginInvoke on your form from within ListChanged would defer the save adequately so that it works successfully.

    Friday, June 5, 2009 8:26 PM

All replies

  • Looks like you are making changes to the data in the ListChanged event (yes, doing a Update counts as it transitions row versions, syncs identity values with those determined by the database, etc.).  This is asking for trouble with nearly all APIs, not just DataSet.  It is not a good idea to make further modifications to data in an event notifying you that there were changes to the data.

    I'm not sure what you are trying to accomplish.  Most programs provide a button that saves the data to the database on demand and does not attempt to write every change to the database as soon as it is made.  If you really must, you might see whether calling BeginInvoke on your form from within ListChanged would defer the save adequately so that it works successfully.

    Friday, June 5, 2009 8:26 PM
  • As BinaryCoder points out changes in the ListChanged event should not occur. Just as a note this was posted in a sticky post in the forum already.

    http://social.msdn.microsoft.com/Forums/en-US/adodotnetdataset/thread/6693db3a-1098-44d4-8b18-6ca85f59b075

    Thanks
    Chris Robinson
    Program Manager - DataSet
    This posting is provided "AS IS" with no warranties, and confers no rights.
    Friday, June 5, 2009 9:19 PM
  • so i have grids and treelists and, i want the changes user made on a row immediately post to database whenever user tries to move to another row. i also use a record navigator that user could start editing however, row editing starts automatically when user double clicks on the grid. i could not find a consistent way to reflect changes to database except the ListChanged event.

    thanks for the answer BinaryCoder, but could you give some sample code that how could i get the BeginInvoke called after ListChanged event, afaik, BeginInvoke runs async. on another thread, could it be possible to determine the actions related to ListChanged and wait until they are completed when the method BeginInvoke launched.

    besides i have tried rowchanged and rowdeleted events of datatable but there are other problems arise like concurrency errors and reader is not closed yet(it could be solved with multipleactiverecordsets = true).

    to summarize, i want to get the changes on a datatable reflected immediately to database whenever a row is added,changed or deleted.
    • Edited by Patogenx Saturday, June 6, 2009 10:19 AM
    Saturday, June 6, 2009 5:56 AM
  • The Control.BeginInvoke method does not use a separate thread.  It schedules the work to be performed on the main UI thread.  The same one that processes button clicks, repaints, and most everything else that goes on in the typical GUI application.  Control.BeginInvoke is an "invoke later" function.  The main GUI thread will invoke the code once it regains control (sometime hopefully shortly after ListChanged has returned).

    Saturday, June 6, 2009 4:27 PM