C# DataTable 内部索引损坏
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/450675/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
DataTable internal index is corrupted
提问by user30525
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 DataTable
, like so:
我正在使用 C# 中的 .NET WinForms 应用程序,针对 3.5 .NET 框架运行。在这个应用程序中,我将 a 的 .Expression 成员设置为DataColumn
a DataTable
,如下所示:
DataColumn column = dtData.Columns["TestColumn"];
column.Expression = "some expression";
The 2nd line, where I actually set Expression
, will sometimes result in the following exception:
我实际设置的第二行Expression
有时会导致以下异常:
FileName=
LineNumber=0
Source=System.Data
TargetSite=Int32 RBInsert(Int32, Int32, Int32, Int32, Boolean)
System.InvalidOperationException: DataTable internal index is corrupted: '5'.
at System.Data.RBTree`1.RBInsert(Int32 root_id, Int32 x_id, Int32 mainTreeNodeID, Int32 position, Boolean append)
at System.Data.RBTree`1.RBInsert(Int32 root_id, Int32 x_id, Int32 mainTreeNodeID, Int32 position, Boolean append)
at System.Data.Index.InitRecords(IFilter filter)
at System.Data.Index.Reset()
at System.Data.DataTable.ResetInternalIndexes(DataColumn column)
at System.Data.DataTable.EvaluateExpressions(DataColumn column)
at System.Data.DataColumn.set_Expression(String value)
There is no perceptible rhyme or reason as to when the error will occur; in loading the same data set, it may work fine but then reloading it will fail, and vice versa. This leads me to think it is related to a race condition, where another write operation is occurring on the DataTable
as I'm trying to modify one of its columns. However, the code relating to DataTable
s is notmulti-threaded and runs only on the UI thread.
错误何时发生没有明显的韵律或原因;在加载相同的数据集时,它可能工作正常,但重新加载它会失败,反之亦然。这让我认为它与竞争条件有关,DataTable
当我试图修改其中一个列时,另一个写操作正在发生。但是,与DataTable
s相关的代码不是多线程的,仅在 UI 线程上运行。
I have searched the web and Microsoft forums, and there is much discussion and confusion over this issue. Back when the issue was first reported in 2006, the thought was that it was an flaw in the .NET framework, and there were some supposed hotfixes released that were presumably rolled into later versions of the .NET framework. However, people have reported mixed results in applying those hotfixes, which are no longer applicable to the current framework.
我在网上和微软论坛上搜索过,关于这个问题有很多讨论和困惑。早在 2006 年首次报告该问题时,人们就认为这是 .NET 框架中的一个缺陷,并且发布了一些假定的修补程序,推测这些修补程序已被纳入到 .NET 框架的更高版本中。但是,人们在应用这些修补程序时报告了不同的结果,这些修补程序不再适用于当前框架。
Another prevailing theory is that there are operations on the DataTable which, though seemingly innocuous, are actually write operations. For example, creating a new DataView
based on a DataTable
is actually a write operation on the table itself, because it creates an internal index in the DataTable
for later reference. These write operations are not thread-safe, so it sometimes happens that a race condition leads to an unthread-safe write coinciding with our access of the DataTable
. This, in turn, causes the internal index of the DataTable
to become corrupted, leading to the exception.
另一个流行的理论是,DataTable 上有一些操作,虽然看似无害,但实际上是写操作。比如DataView
基于a创建new ,DataTable
其实就是对表本身的写操作,因为它在a中创建了一个内部索引,DataTable
供以后参考。这些写入操作不是线程安全的,因此有时会发生竞争条件导致非线程安全写入与我们对DataTable
. 这反过来又会导致 的内部索引DataTable
损坏,从而导致异常。
I have tried putting lock
blocks around each DataView
creation in the code, but, as I mentioned before, code utilizing the DataTable
is not threaded, and the lock
s had no effect, in any case.
我曾尝试在代码中的lock
每个DataView
创建周围放置块,但是,正如我之前提到的,使用 的代码DataTable
不是线程化的,并且lock
s 在任何情况下都不起作用。
Has anyone seen this and successfully solved / worked around it?
有没有人看到这个并成功解决/解决它?
No, unfortunately I can not. Loading the DataTable has already occurred by the time I get a hold of it to apply an Expression to one of its DataColumn's. I could remove the column and then re-add it using the code you suggested, but is there a particular reason why that would solve the internal index is corrupted problem?
不,不幸的是我不能。当我掌握它以将表达式应用于其中一个 DataColumn 时,已经加载了 DataTable。我可以删除该列,然后使用您建议的代码重新添加它,但是是否有特殊原因可以解决内部索引损坏的问题?
回答by balexandre
can't you just use:
你不能只使用:
dtData.Columns.Add("TestColumn", typeof(Decimal), "Price * Quantity");
回答by Lasse V. Karlsen
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.
你提到“不是线程安全的”。您是否从不同的线程操作对象?如果是这样,那么这很可能是腐败的原因。
回答by torial
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.
就我个人而言,这个特定的错误以各种方式成为我 3 周的克星。我已经在我的代码库的一部分中解决了它,它出现在其他地方(我相信我今晚终于解决了它)。异常信息相当无用,鉴于缺少 MS 来解决问题,强制重新索引的方法将是一个不错的功能。
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.
我不会寻找 MS 的修补程序——他们有一篇关于它的知识库文章,然后将您重定向到一个完全不相关的 ASP.Net 修复程序。
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 yourcase you may wish to check that the field is not null, the expression syntax doessupports 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 yourcase use this instead of your outright assignment:
if (column.Expression != "some expression") column.Expression = "some expression";
- 避免使用默认视图,并尽可能修改默认视图。顺便说一句,.Net 2.0 在创建视图时有许多读/写锁,所以它们不是 2.0 之前的问题。
- 尽可能调用 AcceptChanges()。
- 请注意 .Select(expression),因为此代码中没有读取器/写入器锁——而且它是唯一的地方(至少根据 usenet 上的一个人的说法,所以请稍加保留——但是,这与您的问题非常相似-因此使用互斥体可能会有所帮助)
- 将 AllowDBNull 设置为有问题的列(值得怀疑,但在 usenet 上报告——我只在有意义的地方使用它)
- 确保您没有为 DataRow 字段设置 null (C#)/Nothing (VB)。使用 DBNull.Value 而不是 null。在您的情况下,您可能希望检查该字段是否为空,表达式语法确实支持 IsNull(val, alt_val) 运算符。
这可能对我帮助最大(听起来很荒谬):如果一个值没有改变,不要分配它。因此,在您的情况下,请使用它而不是您的直接分配:
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.
编辑(2012 年 5 月 16 日):反复遇到这个问题(使用 UltraGrid/UltraWinGrid)。使用了删除DataView上的排序的建议,然后添加了一个与DataView排序匹配的排序列,这样就解决了问题。
回答by Robert Rossney
My understanding, from long and painful haggling over this problem, is that it's an artifact of non-thread-safe write operations, which usually you didn't know you were making.
我的理解是,从对这个问题的长期而痛苦的讨价还价中,它是非线程安全的写操作的产物,通常你不知道你在做什么。
In my case, the culprit seemed to be the BindingSource. I found that I needed to suspend binding, perform whatever operation I was trying, and then resume binding when I was done, and the problem went away. This was 18 months ago, so I'm not clear on the details anymore, but I remember getting the impression that the BindingSource is doing some kind of operation on its own thread. (This makes less sense to me now than it did at the time.)
就我而言,罪魁祸首似乎是 BindingSource。我发现我需要暂停绑定,执行我正在尝试的任何操作,然后在完成后恢复绑定,问题就消失了。这是 18 个月前的事情,所以我不再清楚细节,但我记得印象中 BindingSource 正在它自己的线程上执行某种操作。(这对我来说比当时更没有意义。)
Another potential source of trouble is the DataTable's RowChanging event. If you do something that modifies the table in that event handler, expect bad things.
另一个潜在的麻烦来源是 DataTable 的 RowChanging 事件。如果你在那个事件处理程序中做了一些修改表的事情,那就是不好的事情。
回答by Bobby
I just had the same issue while importing rows, as it seems, calling DataTable.BeginLoadData
before the insert fixed it for me.
我在导入行时遇到了同样的问题,看起来,DataTable.BeginLoadData
在插入之前调用它为我修复它。
Edit:As it turns out, this only fixed it on one side, now adding rows throws this exception.
编辑:事实证明,这只在一侧修复了它,现在添加行会引发此异常。
Edit2:Suspending binding as suggested by Robert Rossneyfixed the adding problem for me, too. I simply removed the DataSource
from the DataGridView
and readded it after I was done with the DataTable
.
Edit2:按照罗伯特罗斯尼的建议暂停绑定也为我解决了添加问题。我只是DataSource
从 中删除DataGridView
并在完成DataTable
.
Edit3:Still not fixed...the exception keeps creeping up in all different places in my code since Thursday...this is by far the strangest and most f****ing bug I've encountered in the Framework so far (and I've seen many odd things in the 3 years I've been working with .NET 2.0, enough to warrant that not a single of my future projects will be build on it). But enough of ranting, back on topic.
编辑 3:仍然没有修复......自周四以来,异常一直在我代码中的所有不同地方蔓延......这是迄今为止我在框架中遇到的最奇怪和最糟糕的错误(在我使用 .NET 2.0 的 3 年里,我看到了许多奇怪的事情,足以保证我未来的任何项目都不会建立在它之上)。但是,足够的咆哮,回到主题。
I've read through the whole discussion at the Microsoft support forumsand I'll give you a brief summary of it. The original bug report originates in '05.
我已经通读了 Microsoft 支持论坛上的整个讨论,我会给你一个简短的总结。最初的错误报告起源于 '05。
- March '06:Bug is reported the first time, investigation starts. Throughout the course of the next year it is reported in different forms and different manifestations.
- March '07:Finally a hotfix with number KB 932491is released (don't get your hopes up), it links against a download of an completely irrelevant looking hotfix, or at least so it seems. Throughout the next months many report that the hotfix does not work, some are reporting success.
- July '07:Last sign of live from Microsoft (with a complete useless answer), beyond this point is no further response from Microsoft. No further confirmations, no attempts on support, no requests for more information...nothing. Beyond this point there's only community related information.
- 06 年 3 月:首次报告错误,调查开始。在接下来的一年中,它以不同的形式和不同的表现形式进行报道。
- 07 年 3 月:最终发布了编号为 KB 932491 的修补程序(不要抱有希望),它链接到一个完全不相关的修补程序的下载,或者至少看起来如此。在接下来的几个月中,许多报告说修补程序不起作用,有些报告成功。
- 07 年 7 月:Microsoft 的最后一次直播迹象(带有完全无用的答案),除此之外,Microsoft 没有进一步的回应。没有进一步的确认,没有尝试支持,没有要求更多的信息......什么都没有。除此之外,只有社区相关信息。
No seriously, this sums it up in my opinion. I was able to extract the following information from the whole discussion:
不严重,这在我看来就是总结。我能够从整个讨论中提取以下信息:
- The
DataTable
is notThread-Safe. You'll have toLock
/Synchronize
it on your own if you have Multi-Threading anywhere on it. - The corruption of the index happens somewhere beforethe actual exception is thrown.
- One possible corruption source is either an applied
Expression
or an appliedSort
. - Another possible source is the
DataTable.ListChanged()
event, do never modify data in this event or any event which spawns from it. This includes differentChanged
events from bound controls. - There are possible issues when binding the
DefaultView
against a control. Always useDataTable.BeginLoadData()
andDataTable.EndLoadData()
. - Creation and manipulation of the
DefaultView
is a writing operationon theDataTable
(and itsIndex
), the Flying Spaghetti Monster knows why.
- 该
DataTable
是不是线程安全的。你必须Lock
/Synchronize
在你自己,如果你有这多线程的任何地方。 - 索引的损坏发生在抛出实际异常之前的某处。
- 一种可能的损坏源是应用
Expression
或应用Sort
。 - 另一个可能的来源是
DataTable.ListChanged()
事件,切勿修改此事件或由此产生的任何事件中的数据。这包括Changed
来自绑定控件的不同事件。 - 将
DefaultView
与控件绑定时可能会出现问题。始终使用DataTable.BeginLoadData()
和DataTable.EndLoadData()
。 - 的创建和操作
DefaultView
是对(及其)的写操作,飞行意大利面怪物知道为什么。DataTable
Index
The possible source of this is most likely a race condition, either in our source code or in the code of the framework. As it seems, Microsoft is unable to fix this bug or has no intention to. Either way, check your code for race conditions, it has something to do with the DefaultView
in my opinion. At some point an Insert
or a manipulation of the data is corrupting the internal Index because the changes are not properly propagated through the whole DataTable
.
这种情况的可能来源很可能是我们的源代码或框架代码中的竞争条件。看起来,Microsoft 无法或无意修复此错误。无论哪种方式,请检查您的代码是否存在竞争条件,DefaultView
我认为这与. 在某些时候Insert
,对数据的操作或操作正在破坏内部索引,因为更改未正确传播到整个DataTable
.
I'll of course report back when I find further informations or additional fixes. And sorry if I get a little bit emotional here, but I've spent three days trying to pinpoint this issue, and it slowly starts to look like a good reason to get a new job.
当我找到更多信息或其他修复时,我当然会报告。很抱歉,如果我在这里有点情绪化,但我已经花了三天时间试图查明这个问题,并且慢慢地开始看起来像是获得一份新工作的一个很好的理由。
Edit4:I was able to avoid this bug by completely removing the binding (control.DataSource = null;
) and re-adding it after the loading of the data is completed. Which fuels my thought that it has something to do with the DefaultView
and the events which spawn from the bound controls.
Edit4:通过完全删除绑定 ( control.DataSource = null;
) 并在数据加载完成后重新添加它,我能够避免此错误。这激发了我的想法,它与DefaultView
绑定控件产生的事件和事件有关。
回答by David Catriel
Same prob over here, and tried a different approach. I'm not using the datatable for any screen related stuff (e.g. binding); I'm just creating DataRow objects (in multiple threads) and adding them to the table.
同样的问题在这里,并尝试了不同的方法。我没有将数据表用于任何与屏幕相关的内容(例如绑定);我只是创建 DataRow 对象(在多个线程中)并将它们添加到表中。
I've tried using lock(), and also tried centralizing the addition of the rows into a singleton, thinking this would help. It didn't. For reference, here's the singleton I used. Maybe someone else will be able to build on this and figure something out?
我尝试过使用 lock(),还尝试将行的添加集中到一个单例中,认为这会有所帮助。它没有。作为参考,这是我使用的单身人士。也许其他人能够以此为基础并想出一些办法?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace EntityToDataSet
{
public class RowAdder
{
#region Data
private readonly object mLockObject = new object();
private static RowAdder mInstance;
public static RowAdder Instance
{
get
{
if (mInstance == null)
{
mInstance = new RowAdder();
}
return mInstance;
}
}
object mSync;
#endregion
#region Constructor
private RowAdder()
{
}
#endregion
public void Add(DataTable table, DataRow row)
{
lock (mLockObject)
{
table.Rows.Add(row);
}
}
}
}
回答by Suj
How about trying the idea of applying a mutex as described hereto induce sleep in the thread in such conditions?
在这种情况下,尝试应用此处描述的互斥锁来在线程中引发睡眠的想法如何?
回答by Schnapz
The same happened to me too. Winforms, .NET 3.5, unexpectectly got this error trying to set one of the columns in typed row. Code was rather old and worked for a long time so it was kind of unpleasant surprise...
同样的事情也发生在我身上。Winforms,.NET 3.5,在尝试设置键入行中的列之一时意外出现此错误。代码相当旧并且工作了很长时间,所以有点令人不快的惊喜......
I needed to set new SortNo's in typed table TadaTable in dataset TadaSet.
我需要在数据集 TadaSet 的类型表 TadaTable 中设置新的 SortNo。
What helped me, you can also try this:
对我有什么帮助,你也可以试试这个:
int i = 0;
foreach (TadaSet.TadaTableRow row in source)
{
row.BeginEdit(); //kinda magical operation but it helped :)
// Also you can make EndEdit() for each row later if you need...
short newNo = i++;
if (newNo != row.SortNo) row.SortNo = newNo; //here was the crash
}
回答by Andrew Marais
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
享受,安德鲁M
回答by URVISH SUTHAR
May be you are using same datatable in mutiple process at same time.. I just resolved this issues using SYNCLOCK
...
可能是您同时在多个进程中使用相同的数据表..我刚刚使用SYNCLOCK
...解决了这个问题
Try this..
尝试这个..
SyncLock your datatable
'''' ----your datatable process
End SyncLock