We are doing a query against an in-memory collection of LINQ data objects. The wrinkle is that we are ordering by a column in a related table whose records have not necessarily been loaded yet (deferred loading:)
Dim oPkgProducts = _
From b In oBillPkg.BillProducts _
Where b.Successful.GetValueOrDefault(Common.X_INDETERMINATE) = _
Common.X_INDETERMINATE _
Order By _
b.ProductFromCache.ProvisionCodePriority.ProvisionPriority Ascending _
Select b
We logged the following error in production when the code tried to call Count() on this query:
System.ArgumentException: An item with the same key has already been added. at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource) at System.Collections.Generic.Dictionary
2.Insert(TKey key, TValue value, Boolean add) at System.Data.Linq.IdentityManager.StandardIdentityManager.SetCurrent(MetaType type) at System.Data.Linq.IdentityManager.StandardIdentityManager.Find(MetaType type, Object[] keyValues) at System.Data.Linq.CommonDataServices.GetCachedObject(MetaType type, Object[] keyValues) at System.Data.Linq.CommonDataServices.DeferredSourceFactory
1.TryGetCached Object(Object[] keyValues, T& cached) at System.Data.Linq.CommonDataServices.DeferredSourceFactory1.Execute(Object instance) at System.Data.Linq.CommonDataServices.DeferredSourceFactory
1.DeferredSource.GetEnumerator() at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable1 source) at System.Data.Linq.EntityRef
1.get_Entity() at PackageManagement.Product.get_ProvisionCodePriority() in C:\Projects\DLLs\DotNet35\PackageManagement\PackageManagement.designer.vb:line 14431 at ProvisionEngine.BillPackageProvision.Lambda$_12(BillProduct b) in C:\Projects\DLLs\DotNet35\ProvisionEngine\BillPackageProvision.vb:line 394 at System.Linq.EnumerableSorter2.ComputeKeys(TElement[] elements, Int32 count) at System.Linq.EnumerableSorter
1.Sort(TElement[] elements, Int32 count) at System.Linq.OrderedEnumerable1.<GetEnumerator>d__0.MoveNext() at System.Linq.Enumerable.WhereSelectEnumerableIterator
2.MoveNext() at System.Linq.Enumerable.Count[TSource](IEnumerable`1 source) at ProvisionEngine.BillPackageProvision.ProvisionPackage(BillPackage oBillPkg, Boolean bRecursiveCall) in C:\Projects\DLLs\DotNet35\ProvisionEngine\BillPackageProvision.vb:line 397
The confusing part is that when the operation was automatically 开发者_如何学Goretried a few seconds later, it succeeded. And since this is the only time we've seen the exception (the code runs fine the rest of the time) it is not going to be easy to reproduce.
Some background: "ProductFromCache" is a helper property that uses Pete Montgomery's technique for implementing a LINQ to SQL cache. The code could be rewritten to use the default LINQ .Product property too. I don't think this is part of the problem because the stack trace shows that the exception is happening inside .NET System libraries. I think the exception is happening when the .ProvisionCodePriority property is called -- this returns a record from a table associated to the product table. LINQ seems to be trying to cache the result of this deferred load in a generic Dictionary object. But for some reason, the Dictionary already contains the specified key.
Does anyone have an idea why this might be happening?
精彩评论