DataTable internal index is corrupted

前端 未结 18 1400
轻奢々
轻奢々 2020-12-04 15:55

I am working with a .NET WinForms app in C#, running against the 3.5 .NET framework. In this app, I am setting the .Expression member of a DataColumn in a

相关标签:
18条回答
  • 2020-12-04 16:13

    can't you just use:

    dtData.Columns.Add("TestColumn", typeof(Decimal), "Price * Quantity");
    
    0 讨论(0)
  • 2020-12-04 16:16

    You mention "not threadsafe". Are you manipulating the object from different threads? If so then that might very well be the reason for the corruption.

    0 讨论(0)
  • 2020-12-04 16:16

    This is how I fixed my Internal index is corrupted problem:

    System.Data.DataTable dtNew = new DataTable();
    for (int iCol = 0; iCol < dtOriginalData.Columns.Count; iCol++)
    {
        dtNew.Columns.Add(dtOriginalData.Columns[iCol].ColumnName, dtOriginalData.Columns[iCol].DataType);
    }
    for (int iCopyIndex = 0; iCopyIndex < item.Data.Rows.Count; iCopyIndex++)
    {
        dtNew.Rows.Add(dtOriginalData.Rows[iCopyIndex].ItemArray);
        //dtNew.ImportRow(dtOriginalData.Rows[iCopyIndex]); 
    }
    dtOriginalData = dtNew; 
    

    Enjoy, Andrew M

    0 讨论(0)
  • 2020-12-04 16:16

    Had the same with .NET 4.5.2 win forms app. In my case the reason appeared to be multiple controls bound to single BindingSource column. I am aware that binding many controls to one value is asking for trouble but I it has been the lesser evil for me due to pretty complex layout.

    It appeared that changing the value from one side raised multiple OnChange events trying to perform the same operation against the BindingSource which resulted with the error in question.

    I have tried suspending binding but with no success. I have implemented flags preventing the code from being executed many times on parallel and things are better.

    0 讨论(0)
  • 2020-12-04 16:19

    In my case the Framework version is 2.0. The source of a problem was in DataView ListChanged event. The code below initializes the new row with some default values.

    private void dataView_ListChanged(object sender, ListChangedEventArgs e)
    {
        if (e.ListChangedType == ListChangedType.ItemAdded)
        {
            DataView v = (DataView)sender;
            DataRowView drv = v[e.NewIndex];
    
            // This "if" works fine
            if (drv["Foo"] == DBNull.Value)
            {
                drv["Foo"] = GetFooDefault();
            }
    
            // This "if" brakes the internal index     
            if (drv["Bar"] == DBNull.Value && drv["Buz"] != DBNull.Value)
            {
                drv["Bar"] = drv["Buz"];
            }
        }
    }
    

    After some investigation it became clear that ItemAdded event is called at least twice per row. First time when the UI creates new line for entering data and second time, well I'm not sure, but looks like when the DataRowView is added to a DataView.

    The first "if" works only when the ItemAdded is called first time. On second call "Foo" column is already populated and left as is.

    However the "Bar" column defaulting code can be executed on both calls. Actually in my case it was executed only on second ItemAdded event, when the user had a chance to fill in the data for "Buz" column (initially "Buz" has DBNull value).

    So here is recommendations based on my findings:

    • The data in ListChanged event can be changed only when e.ListChangedType == ListChangedType.ItemAdded.
    • Prior to setting the column value the check should be performed to ensure that this is the first ItemAdded event (e.g. if the value cannot be null on second call, check if it is DBNull.Value etc.)
    0 讨论(0)
  • 2020-12-04 16:21

    Personally, this particular bug has been my nemesis for 3 weeks in various fashions. I have solved it in one part of my code base and it shows up elsewhere (I believe I finally squashed it tonight). The exception info is rather unhelpful, and a way to force a reindex would have been a nice feature given the lack of MS to solve the problem.

    I wouldn't look for MS's hotfix -- they have a KB article on it, then redirect you to an ASP.Net fix that is completely unrelated.

    Ok - enough complaining. Let's see what has actually helped me in resolving this particular issue in the various places I've encountered it:

    • Avoid using Default Views, and modifying the Default View if possible. Btw, .Net 2.0 has a number of reader/writer locks on creating views, so they are not the issue they were pre 2.0.
    • Call AcceptChanges() where possible.
    • Be careful about .Select(expression), since there is no reader/writer lock in this code -- and it is the only place (at least according to a person on the usenet so take it w/ a grain of salt -- however, this is very similar to your issue -- so using Mutexes may help)
    • Set AllowDBNull to the column in question (questionable value, but reported on the usenet -- I've used it only in places where it makes sense)
    • Make sure that you are not setting null (C#)/Nothing (VB) to a DataRow field. Use DBNull.Value instead of null. In your case you may wish to check that the field is not null, the expression syntax does supports the IsNull(val, alt_val) operator.
    • This has probably helped me the most (absurd as it sounds): If a value is not changing, don't assign it. So in your case use this instead of your outright assignment:

      if (column.Expression != "some expression") column.Expression = "some expression";

    (I removed the square brackets, not sure why they were there).

    Edit (5/16/12): Just ran into this issue repeatedly (with an UltraGrid/UltraWinGrid). Used the advice of removing the sort on the DataView, and then added a sorted column which matched the DataView sort, and this resolved the issue.

    0 讨论(0)
提交回复
热议问题