DataTable 内部索引已损坏

时间:2022-05-30 08:03:22

由于性能原因,DataTable   没有设计成线程安全的,解决这个问题,可以在修改数据的时候采用lock语句

这里的修改包括:
1,添加,删除,修改DataTable的行
2,使用DataTable   的Select方法选择行,这会通过创建索引从而修改DataTable  
3,在DataTable上创建DataViews   ,也会导致重建索引
4,修改Sort属性也会导致DataTable的修改。

 

症状

当您尝试应用程序, 基于 Microsoft NET Framework 2.0, 中使用组件数据与组件时可能损坏。 该组件使用 System.Data.DataSet 对象时出现此问题。 发生此问题时, 可能会遇到一个或多个下列问题:


记录管理器在调用 AcceptChanges 方法 DataView 类中, 可能损坏。


可能无法正确更新表达式列中计算值。


通过使用多个语句, 调用 DataTable.Select 方法时可能会返回正确结果。


可能的 DataTable 对象内部索引损坏。 此外, 收到 ' 13 ' 错误信息。


合并操作时, 如果目标行处于编辑状态可能损坏记录管理器。


可能的 DataTable 对象内部索引损坏。 此外, 收到 5 ' ' 错误信息。

解决方案

支持修补程序现已推出来自 Microsoft。 但是, 它旨在解决只问题本文中描述。 它仅适用于系统是经历此特定问题。 此修复程序可能需要接受其他测试。 因此, 如果您受此问题, 的影响不严重我们建议您等待下 Microsoft NET Framework 2.0 服务包包含此修复程序。
要立即, 解决问题请与 Microsoft 客户支持服务以获取此修复程序。 有关 Microsoft 客户支持服务电话号码和支持费用, 信息的完整列表请访问 Microsoft Web 站点:

http://support.microsoft.com/contactus/?ws=support (http://support.microsoft.com/contactus/?ws=support)

注意 在特殊情况下, 如果 Microsoft 支持专家确定该特定更新将解决问题可能是免, 是正常收取支持电话费用。 通常支持成本将应用于其他支持问题和问题做不符合特定更新问题。

先决条件

有用于安装此修复程序没有先决条件。

重新启动要求

您没有要应用此修复程序后重新启动计算机

修补程序替换信息

此修复程序不替代任何其他修复程序。

文件信息

文件属性 (或更高文件属性) 的此修复程序英文版具有下表中列出。 中协调通用时间 (UTC) 列出日期和时间对这些文件。 当您查看文件信息, 将转换为本地时间。 要查找 UTC 与本地时间, 区别控制面板中 DateandTime 项目中使用 时区 选项卡。

对记录管理器调用 AcceptChanges 方法 DataView 类中, 时可能会损坏问题 1:

从事件处理程序写操作期间可能发生记录经理损坏。 这时, System.NullreferenceException 异常可能引发。 按正确顺序此外, 当应用程序执行写入操作 ListChanged 事件, 中可能出现索引更新。
例如, 考虑以下情形:

1.
您在应用程序使用以下代码:

 
 
 
using System;
using System.ComponentModel;
using System.Data;
class Test
{
    
private static DataRow _dr = null;
    
private static bool _accept = false;
    
public static void Main()
    {
        
try
        {
            DataSet ds 
= new DataSet();
            DataTable dt 
= ds.Tables.Add("Customers");
            DataColumn c 
= dt.Columns.Add("Id"typeof(int));
            dt.PrimaryKey 
= new DataColumn[] { c };
            dt.Columns.Add(
"Name"typeof(string));
            dt.Columns.Add(
"Age"typeof(int));
            dt.Rows.Add(
new object[] { 1"A"10 });
            dt.Rows.Add(
new object[] { 2"B"20 });
            dt.Rows.Add(
new object[] { 3"G"30 });
            dt.Rows.Add(
new object[] { 4"H"40 });
            dt.Rows.Add(
new object[] { 5"I"50 });
            ds.AcceptChanges();
            DataView dv 
= new DataView(dt);
            dv.Sort 
= "Name ASC";
            dv.ListChanged 
+= new ListChangedEventHandler(OnListChanged);
            _dr 
= dt.Rows[4];
            _accept 
= true;
            _dr[
"Name"= "C";
            _accept 
= false;
            _dr[
"Name"= "D";
            _dr[
"Age"= 55;
            Console.WriteLine(dv[
2][1]);
        }
        
catch (Exception exc)
        {
            Console.WriteLine(exc);
        }
    }
    
public static void OnListChanged(object sender, ListChangedEventArgs args)
    {
        
if (_dr != null && _accept)
        {
            _dr.AcceptChanges();
        }
    }
}

 

2.
运行该应用程序。

在此方案, 收到错误信息类似以下错误信息:

未设置为对象的实例 System.NullReferenceException: 对象引用。 c:\Work\bugs\newbug1\Test.cs:line 42 中 Test.Main() 上 System.Data.DataRowView.get_Item (Int 32 ndx) 上 System.Data.DataView.IsOriginalVersion (Int 32 index) 上

要变通解决此问题, 不在 ListChanged 事件执行写入操作。 最好使用 RowChanged 事件代替 ListChanged 事件。

一个表达式列中: 计算值可能无法正确更新问题 2:

当您尝试计算, DataSet 对象中的表达式列的值, 表达式列是关系, 一部分可能无法正确更新计算值的表达式列。 例如, 考虑以下情形:

1.
您在应用程序使用以下代码:

 

using  System;
using  System.ComponentModel;
using  System.Data;
class  Test
{
    
public   static   void  Main()
    {
        
try
        {
            DataSet ds 
=   new  DataSet();
            DataTable dt1 
=  ds.Tables.Add( " T1 " );
            dt1.Columns.Add(
" CustId " typeof ( int ));
            dt1.Columns.Add(
" CustName " typeof ( string ));
            DataTable dt2 
=  ds.Tables.Add( " T2 " );
            dt2.Columns.Add(
" EmpId " typeof ( int ));
            DataColumn dcEmpName 
=  dt2.Columns.Add( " EmpName " typeof ( string ));
            DataColumn dcMgrName 
=  dt2.Columns.Add( " MgrName " typeof ( string ));
            DataColumn dcReports 
=  dt2.Columns.Add( " NumberOfReports " typeof ( int ));
            DataRelation rel1 
=  ds.Relations.Add( " T1T2 " , dt1.Columns[ " CustId " ], dt2.Columns[ " EmpId " ],  false );
            DataRelation rel2 
=  ds.Relations.Add( " T2T2 " , dt2.Columns[ " EmpName " ], dt2.Columns[ " MgrName " ],  false );
            dcEmpName.Expression 
=   " Parent(T1T2).CustName " ;
            dcMgrName.Expression 
=   " Parent(T1T2).CustName " ;
            
// Each person is a manager to himself.
            dcReports.Expression  =   " Count(Child(T2T2).EmpName) " ;
            AddRow(dt1, 
1 " N1 " );
            AddRow(dt1, 
2 " N2 " );
            AddRow(dt1, 
3 " N3 " );
            AddRow(dt2, 
1 );
            AddRow(dt2, 
2 );
            AddRow(dt2, 
3 );
            Console.WriteLine(ds.GetXml());
            dt1.Rows[
0 ][ " CustName " =   " N4 " ;
            Console.WriteLine(ds.GetXml());
        }
        
catch  (Exception exc)
        {
            Console.WriteLine(exc);
        }
    }
    
public   static   void  AddRow(DataTable dt,  params   object [] objArr)
    {
        Console.WriteLine(
" Adding row to table {0} " , dt.TableName);
        dt.Rows.Add(objArr);
    }
}

 


 

2.
运行该应用程序。

在此方案, 您收到以下输出:

 

< NewDataSet >
    
< T1 >
        
< CustId > 1 </ CustId >
        
< CustName > N4 </ CustName >
    
</ T1 >
    
< T1 >
        
< CustId > 2 </ CustId >
        
< CustName > N2 </ CustName >
    
</ T1 >
    
< T1 >
        
< CustId > 3 </ CustId >
        
< CustName > N3 </ CustName >
    
</ T1 >
    
< T2 >
        
< EmpId > 1 </ EmpId >
        
< EmpName > N4 </ EmpName >
        
< MgrName > N4 </ MgrName >
        
< NumberOfReports > 0 </ NumberOfReports >
    
</ T2 >
    
< T2 >
        
< EmpId > 2 </ EmpId >
        
< EmpName > N2 </ EmpName >
        
< MgrName > N2 </ MgrName >
        
< NumberOfReports > 1 </ NumberOfReports >
    
</ T2 >
    
< T2 >
        
< EmpId > 3 </ EmpId >
        
< EmpName > N3 </ EmpName >
        
< MgrName > N3 </ MgrName >
        
< NumberOfReports > 1 </ NumberOfReports >
    
</ T2 >
</ NewDataSet >

 



此输出, 中首 T2 元素中 NumberOfReports 元素包含错误值为 0 而不是 1。

问题 3: 通过使用多个语句, 调用 DataTable.Select 方法时可能会返回正确结果

当您使用 选择 方法同时具有 AND 子句的 DataTable 对象来检索数据对于多语句, 选择 方法可能返回正确结果。 例如, 以下代码返回正确结果:

string filter = "(NOT ColTwo = 1) AND (ColOne = 2)";
DataTable.Select(filter);

但是, 下列代码返回正确结果:

string filter = "NOT ColTwo = 1 AND ColOne = 2";
DataTable.Select(filter);

此外, 请考虑以下情形:

1.
您在应用程序使用以下代码:

 
 
 
public static void Main()
{
  DataTable table 
= new DataTable();
  table.Columns.Add(
"ColID"typeof(int));
  table.Columns.Add(
"ColOne"typeof(int));
  table.Columns.Add(
"ColTwo"typeof(int));
  table.Rows.Add(
new object[] { 111 });
  table.Rows.Add(
new object[] { 212 });
  table.Rows.Add(
new object[] { 321 });
  table.Rows.Add(
new object[] { 422 });

  
string[] queries = new string[] {
      
"(NOT ColTwo = 1) AND (ColOne = 2)",
      
"(ColOne = 2) AND (NOT ColTwo = 1)",

      
"NOT ColTwo = 1 AND ColOne = 2",
      
"ColOne = 2 AND NOT ColTwo = 1",

      
"NOT ColTwo = 1 AND (ColOne = 2)",
      
"(ColOne = 2) AND NOT ColTwo = 1",

      
"(NOT ColTwo = 1) AND ColOne = 2",
      
"ColOne = 2 AND (NOT ColTwo = 1)",
  };

  Console.WriteLine(
"Select");
  
foreach(string query in queries) {
      DataRow[] rows 
= table.Select(query);
      Console.WriteLine(
"query=\"{0}\" count={1}", query, rows.Length);
      
foreach(DataRow row in rows) {
          Console.WriteLine(
"\t{0}, {1}, {2}", row[0], row[1], row[2]);
      }
  }
}

 

2.
运行该应用程序。

在此方案, 您收到以下输出:

query="(NOT ColTwo = 1) AND (ColOne = 2)" count=2
3, 2, 1
4, 2, 2
query="(ColOne = 2) AND (NOT ColTwo = 1)" count=1
4, 2, 2
query="NOT ColTwo = 1 AND ColOne = 2" count=1
4, 2, 2
query="ColOne = 2 AND NOT ColTwo = 1" count=1
4, 2, 2
query="NOT ColTwo = 1 AND (ColOne = 2)" count=2
3, 2, 1
4, 2, 2
query="(ColOne = 2) AND NOT ColTwo = 1" count=1
4, 2, 2
query="(NOT ColTwo = 1) AND ColOne = 2" count=1
4, 2, 2
query="ColOne = 2 AND (NOT ColTwo = 1)" count=1
4, 2, 2

此输出, "(ColOne = 2) 中 " 右侧的 AND 子句上正确显示。

问题 4: 可能损坏的 DataTable: 内部索引, 并且您收到 ' 13 ' 错误信息

当尝试使用的由 DataTable 对象, 使用 DataSet 对象 AcceptChanges 方法并且您设置到 AcceptRule.Cascade , ForeignKey 规则所使用的 DataSet 对象内部索引值可能损坏。 如果下列条件为真会发生此问题:


DataSet 对象包含一个或多个表具有到一对多关系。


调用 AcceptChanges 方法的 DataSet 对象。


DataSet 对象的 < A0 > AcceptRejectRule < / A0 > 值设置为层叠。 当此值设为层叠, 子表将更改以便它自动或者接受数据或者拒绝数据。

例如, 考虑以下情形:

1.
您在应用程序使用以下代码:

 

    public   void  Main()
        {
            DataTable Table 
=   new  DataTable( " Employee " );
            Table.Columns.Add(
" Id " typeof ( int ));
            Table.Columns.Add(
" ManagerId " typeof ( int ));
            Table.Columns.Add(
" Name " typeof ( string ));
            Table.Columns[
" Name " ].AllowDBNull  =   false ;
            Table.PrimaryKey 
=   new  DataColumn[] { Table.Columns[ " Id " ] };
            DataSet Employees 
=   new  DataSet();
            Employees.Tables.Add(Table);
            DataRelation rel 
=  Employees.Relations.Add(Table.Columns[ " ID " ], Table.Columns[ " ManagerId " ]);
            rel.ChildKeyConstraint.AcceptRejectRule 
=  AcceptRejectRule.Cascade;
            DataRow ManagerA 
=  Table.NewRow();
            ManagerA[
" ID " =   2019 ;
            ManagerA[
" Name " =   " Manager A " ;
            Table.Rows.Add(ManagerA);
            DataRow ManagerB 
=  Table.NewRow();
            ManagerB[
" ID " =   392 ;
            ManagerB[
" Name " =   " Manager B " ;
            Table.Rows.Add(ManagerB);
            DataRow EmployeeB 
=  Table.NewRow();
            EmployeeB[
" ID " =   716 ;
            EmployeeB[
" Name " =   " Employee of B " ;
            EmployeeB.SetParentRow(ManagerB);
            Table.Rows.Add(EmployeeB);
            EmployeeB 
=  Table.NewRow();
            EmployeeB[
" ID " =   637 ;
            EmployeeB[
" Name " =   " 2nd employee of B " ;
            EmployeeB.SetParentRow(ManagerB);
            Table.Rows.Add(EmployeeB);
            Employees.AcceptChanges();
            Table.Rows.Find(
392 ).Delete();
            Employees.AcceptChanges();
        }

 


 

2.
运行该应用程序。

此方案, 中收到以下错误信息:

DataTable 内部索引已损坏: ' 13 '。

问题 5: 合并操作发生, 时记录经理可能损坏如果目标行处于编辑状态

如果是 DataTable 对象中一个或多行编辑, 并再 DataTable.Merge 操作发生或者 DataSet.Merge 操作发生, 记录经理对 DataSet 对象是 DataTable 对象可能损坏。
注意 正在编辑, DataTable 对象中某行时的行 DataRowVersion 值设置为建议。
例如, 考虑以下情形:

1.
您在应用程序使用以下代码:

 

using  System;
using  System.Data;
using  System.Collections.Generic;
using  System.Text;
namespace  ConsoleApplication1
{
    
class  Program
    {
        
static   void  Main( string [] args)
        {
            DataSet 
set   =   new  DataSet();
            DataTable table 
=   set .Tables.Add( " table " );
            table.Columns.Add(
" C1 " typeof ( int ));
            table.Columns.Add(
" C2 " typeof ( char ));
            table.PrimaryKey 
=   new  DataColumn[] { table.Columns[ 0 ] };
            
for  ( int  i  =   0 ; i  <   26 ++ i)
            {
                table.Rows.Add(
new   object [] { i, ( char )(( ushort ) ' a '   +  i) });
            }
            table.AcceptChanges();
            DataSet clone 
=   set .Copy();
            clone.Tables[
0 ].Rows[ 0 ][ 1 =   ' Z ' ;
            
// clone.AcceptChanges();
            table.Rows[ 0 ][ 1 =   ' 1 ' ;
            table.Rows[
0 ].BeginEdit();
            table.Rows[
0 ][ 1 =   ' 2 ' ;
            
try
            {
                
set .Merge(clone);
            }
            
finally
            {
                
foreach  (DataRow row  in  table.Rows)
                {
                    Console.WriteLine(
" {0}={1} " , row[ 0 ], row[ 1 ]);
                }
            }
        }
    }
}

 


 

2.
运行该应用程序。

在此方案, 记录经理进行 DataSet 对象是 DataTable 对象损坏。
若要解决此问题, 处理请确认有目标 DataSet 对象中有 DataRowVersion 值设置为 < A0 > Proposed 使用 DataTable.Merge 方法或者 DataSet.Merge 方法之前没有行。

问题 6: 可能损坏的 DataTable 对象: 内部索引, 并且您收到 5 ' ' 错误信息

DataTable 对象中通过更改 DataTable 对象中的数据不更新的 DataTable 对象内部索引下列方案导致损坏:

1.
DataColumn.Expression 值由表达式更改为任何表达式。 在此方案, DataColumn 对象中所有数据设置为 DBNull。

2.
调用 DataTable.Clear 方法, 时 DataTable 对象中所有数据被删除并更新索引。 但是, 不更新其他表, 引用 DataTable 对象。

例如, 考虑以下情形:

1.
您在应用程序使用以下代码:

 
 
 
using System;
using System.Data;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication1
{
    
class Program
    {
        
static void Main(string[] args)
        {
            DataSet 
set = new DataSet("s");
            DataTable table1 
= set.Tables.Add("a");
            table1.Columns.Add(
"C1"typeof(int));
            table1.Columns.Add(
"C2"typeof(int));
            table1.DefaultView.Sort 
= "C2";
            DataTable table2 
= set.Tables.Add("b");
            table2.Columns.Add(
"C1"typeof(int));
            table2.Columns.Add(
"C2"typeof(int));
            table2.DefaultView.Sort 
= "C2";
            
set.Relations.Add(new DataRelation("t1t2", table1.Columns[0], table2.Columns[0], false));
            table1.Columns[
1].Expression = "Sum(Child(t1t2).C2)";
            AddData(table1, 
1);
            AddData(table2, 
2);
            table1.Columns[
1].Expression = null;
            AddData(table2, 
2);
            AddData(table1, 
2);
        }
        
private static void AddData(DataTable table, int y)
        {
            
object[] x = new object[y];
            Random rand 
= new Random(20070125);
            
for (int i = 0; i < 1000++i)
            {
                
switch (rand.Next(3))
                {
                    
case 0:
                    
case 1:
                        
for (int k = 0; k < x.Length; ++k)
                        {
                            x[k] 
= rand.Next(500);
                        }
                        table.Rows.Add(x);
                        
break;
                    
case 2:
                        
if (0 < table.Rows.Count)
                        {
                            table.Rows.RemoveAt(rand.Next(table.Rows.Count));
                        }
                        
break;
                }
            }
        }
    }
}

 

2.
运行该应用程序。

此方案, 中收到以下错误信息:

DataTable 内部索引已损坏: ' 5 '。