- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在处理遗留的 ASP.NET 代码库,该代码库有 一些 信息存储在 DataTable
对象的缓存中(通过企业库)。它是一个多用户、Intranet 环境,在 .NET 4.0 中运行。生产中存在一个问题,它指向一个先前的“已修复”问题作为其可能的根本原因:在调用 DataView.ToTable()
时发生的 KeyNotFoundException
。此特定代码是验证的一部分,可以在从应用程序中的大多数页面加载页面期间发生。
var table = GetSomeDataTableFromCache();
var view = table.DefaultView;
view.RowFilter = "Foo = 'Bar'";
var filteredTable = view.ToTable();
这是代码的简化。发生的事情是,在过去的 long 天里,这段代码显然抛出了上述异常。先前的开发人员通过捕获并吞下异常并返回 null 来“修复”它。此行为是已曝光的其他问题的推定罪魁祸首。
我曾尝试重现原始异常,但没有成功。我觉得如果我能重现它,我就能理解它并尝试形成一个比忽略它更好的原始问题的解决方案,从而也避免了忽略它 已创建。
我注意到 Google 搜索 DataView.ToTable() + KeyNotFoundException
产生的结果表明验证列名是否存在。示例位于此处:
http://forums.asp.net/t/1695676.aspx/1
但是,我观察到当将 RowFilter
设置为无效的列名时,该行会发生 EvaluateException
。我还尝试通过使用空表以及使用产生空结果的过滤器来解决错误。每个场景都被证明是正常的。
那么,如果不是建议的无效列名,KeyNotFoundException
会在哪里出现?一旦我们知道它是如何发生的,我们又该如何避免呢?
最佳答案
请注意,ASP.NET 本质上是一个多线程系统。 DataView
被记录为读取线程安全,但不是写入。考虑这一点很重要。
在给出的片段中,从缓存中提取 DataTable
的实例并访问其 DefaultView
以进行过滤并写入新的 DataTable
是可能会出现不安全的情况,这不是因为过滤器中的列,而是可能同时执行相同代码的多个线程。
作为实现细节,DataView
使用了多个内部状态位。在 ToTable()
执行期间,涉及多个非本地状态。特别是,有一个以 DataRow 为键的字典字段,还有一个用作键的 DataRow 字段!这个字典被清除,添加到,行被引用行的值覆盖,然后设置为 null,这都是过程的一部分。当多个线程同时执行此操作时,一个线程正在覆盖并使另一个线程所依赖的状态无效并不是不可想象的。这可能会导致问题中提到的异常,以及其他潜在的有害后果。
无论如何,让我们尝试使用代码片段作为起点来重现问题,同样是在可以利用多次执行的环境中。
static void Main()
{
var table = new DataTable();
table.Columns.Add("Foo");
table.Columns.Add("ID", typeof(int));
for (int i = 0; i < 100; i++)
{
table.Rows.Add(i.ToString(), i);
}
for (int j = 0; j < 100; j++)
{
Enumerable
.Range(0,100)
.AsParallel()
.ForAll(item => ExecuteToTable(table, item));
}
}
static void ExecuteToTable(DataTable table, int item)
{
var view = table.DefaultView;
view.RowFilter = string.Format("Foo = '{0}'", item);
var filteredTable = view.ToTable();
}
这会产生异常吗?运行一下看看!它可能需要多次执行,但如果运行代码的机器与我的相似,则不需要多次。 (通过并行查询循环,我真的只需要一次。)
我已在 LinqPad 中运行此代码,并且已生成“所需”异常。由于这是一个并行查询执行,它将被包装在一个 AggregatedException 中,但 InnerException 将讲述这个故事。
KeyNotFoundException: The given key was not present in the dictionary.
at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
at System.Data.DataView.CopyTo(DataRowView[] array, Int32 index)
at System.Data.DataView.GetEnumerator()
at System.Data.DataView.ToTable(String tableName, Boolean distinct, String[] columnNames)
at System.Data.DataView.ToTable()
所以我们已经复制了它,并希望能够理解它。怎么避免呢?有几种可能的解决方案,根据您的用例,一些解决方案比其他解决方案更可口,范围从全面重写到只是细微的更改。
你可以
使用 table.Copy()
复制 DataTable 以访问 DefaultView。这将为每个请求提供自己的表格(在上面的代码片段中)。但是,如果表很大,复制可能会很昂贵。尝试使用 Copy()
运行上面的重现代码,看看是否避免了异常。
完全避免使用 DataView。 Linq 对数据表也很有用。下面的代码片段可用于生成过滤后的 DataTable 输出。但是,另请注意,如果没有行通过过滤器,CopyToDataTable()
可能会抛出它自己的 异常。如果有可能发生这种情况,请在调用最后一部分之前拆分代码并检查结果(使用 .Any())。与 DataView
相比的另一个缺点是,如果您使用可用的 ToTable
,使用 DataView
允许您指定希望包含在输出表中的列> 过载。
var filteredTable
= table.AsEnumerable()
.Where(row => string.Equals(row.Field<string>("Foo"), item.ToString(), StringComparison.InvariantCultureIgnoreCase))
.CopyToDataTable();
当然,您可以进一步探索重新设计代码,将您自己的线程安全措施添加到缓存策略等,尽管这些将花费更多时间来实现改变实际表的过滤方式。
关于c# - 如何避免 DataView.ToTable() 中的 KeyNotFoundException?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15801934/
当我尝试删除具有多对一复合键的对象时,NHibernate 抛出异常。保存对象工作正常。这是异常(exception): [KeyNotFoundException: The given key wa
我正在存储一个二维数组,它表示向量之间的距离矩阵作为 Dictionary .我的实现 DistanceCell有两个字符串字段代表被比较的向量。 class DistanceCell { p
我正在尝试修改字典中的值,但编译器抛出 KeyNotFoundException。我敢肯定,我在字典中声明了该键,因为我正在调用 GenerateEmptyChunks() 方法,该方法用具有其位置键
我有一段看似简单的代码,它一直在抛出我不希望发生的错误: // Private member private Dictionary m_Completed; // Later on, during s
我正在尝试连接到一个免费的在线数据库 (db4free.net),但我无法连接,因为当程序尝试打开连接时会抛出 KeyNotFoundException。 这是我的代码: public static
我正在使用以下方法将 JSON 字符串反序列化到我自己的类中: JavaScriptSerializer serializer = new JavaScriptSerializer(); Dictio
我有一个随机抛出“KeyNotFoundException”的 C# Silverlight 应用程序。我不知道找不到什么 key 。这让我想到了两个问题: KeyNotFoundException
我有一些处理大量 response 的代码并行地从我的数据库中获取对象(使用 AsParallel() )。每个response有很多components . responses可能共享相同的组件。我
type bytesLookup = Map type lookupList = bytesLookup list let maps:bytesLookup = Map.empty let print
好吧,我正在尝试从表单更新数据库中的信息。但是当我调用 db.SaveShanges() 时,我得到 KeyNotFoundException。我正在使用 MVC3 和 EF 4.1。我使用 Cont
我猜测除了异常之外的所有信息都是额外的并且几乎不相关(并且在这里是为了完整性)。问题是:根据下面的异常,到底遇到了什么问题? 我无法理解异常消息。据我所知,将 BsonDocument 映射到 Chi
我正在使用字典来查找我正在处理的程序。我在字典中运行了一堆键,我希望有些键没有值。我 catch 了 KeyNotFoundException就在它发生的地方,吸收它。所有其他异常将传播到顶部。这是处
我正在尝试测试从我的 Nancy 应用程序返回的模型是否符合预期。我已关注文档 here但每当我调用 GetModel扩展方法它抛出 KeyNotFoundException . System.Col
当我尝试在 visual studio 2012 下的 asp.net web api 项目中使用 C# 中的嵌套字典时出现错误代码。此代码示例实际上是从其他支持者在 stack-overflow 上
我正在使用 unity 尝试连接到 MySQL 数据库。数据库运行良好,代码运行良好(在 Visual Studio 2010 中)。但是,当在 Unity 中运行以下命令时: // Connect
下面的代码 new Dictionary> { ["a"] = {1}, }; 抛出运行时 KeyNotFoundException ,尽管 {1} 是一个格式正确的数组(即 int[] a
如果有人问这个问题,我很抱歉,因为我错过了一些非常基本的东西。 我在 Unity 中搜索字典键时收到KeyNotFoundException:字典中不存在给定的键。然而,在我的(仍然很小)的项目中,我
我有一个 RegistryKey 作为我字典的键。 我似乎无法为该特定键设置值。无论我做什么,我都会收到 KeyNotFoundException。 key 确实存在,我在前一行创建了它 例如: pu
不确定为什么我每次尝试连接时都会收到错误消息。我尝试了很多东西。当我在手动连接时输入错误的密码时,它会显示未授予访问权限或其他任何内容,所以我知道它已连接但是当它连接时我收到这个奇怪的错误。 An u
我正在处理遗留的 ASP.NET 代码库,该代码库有 一些 信息存储在 DataTable 对象的缓存中(通过企业库)。它是一个多用户、Intranet 环境,在 .NET 4.0 中运行。生产中存在
我是一名优秀的程序员,十分优秀!