This thread looks to be a little on the old side and therefore may no longer be relevant. Please see if there is a newer thread on the subject and ensure you're using the most recent build of any software if your question regards a particular product.
This thread has been locked and is no longer accepting new posts, if you have a question regarding this topic please email us at support@mindscape.co.nz
|
Hi guys, In my production environment I'm receiving a KeyNotFoundException with the following stack trace... System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
The interesting thing is I can't reproduce this error on my development machine - even taking the exact same binaries and a database backup from production doesn't show this error. In the past when I've seen a similar KeyNotFoundException, it has been related to a mismatch between the Lightspeed model and the database schema. But since I'm unable to reproduce this locally with the same database as production I'm dubious as to whether this is the cause this time. Are you able to give me some feedback on what situations might cause the failed dictionary lookup based on this stacktrace? Thanks, Greg |
|
|
Could you let us know which build of the LightSpeed DLL you are using in production? |
|
|
Hi Greg, The error looks to be being generated from an association load (e.g. an eager load) where the parent of a loaded child does not exist in the identity map, which sounds like an odd case indeed, but perhaps it could happen if the IdentityMap was flushed between loading the parents and the children. Is it consistent enough on the production box or is it fairly intermittent in its behavior there?
Jeremy |
|
|
Hi Ivan / Jeremy, The version I'm using is: 3.1.1540. I've just downloaded last nights build and will look to see if that fixes it in prod. This gets more confusing, because I've just noticed that when the same query is executed but with a different criteria, the query succeeds. But returning to the original criteria it continues to fail. Thanks for you time, Cheers, Greg |
|
|
Wow - just had a quick look in the SQL trace, and it looks like one of the foreign keys from the parent entity has not been eager loaded (instead there is another entity id in the eager load list). I'll see if I can narrow it down some more... |
|
|
Ok I've tracked it down... The query I'm doing looks something like... var r = UOW.Results.OrderBy(r=> r.Placing).Take(10) The problem occurs when there are two or more entities Results with a Placing of 10... The subquery used by the eager load is not guaranteed to return the same 10 results as the initial query. Hence, you end up with an eagerloaded entity without a matching parent entity. Obviously this is non-deterministic, hence why its not easily reproducible on my local machine. In the short term, I will include an additional deterministic ordering criteria. Is this scenario something you guys would be able to guard against longer term? Thanks for your help, Cheers, |
|
|
Hi, we're having a similar issue to this: - We specify the page size to be, say 10 on a collection larger than this - We eagerly load StockTakeItem items, including StockTakeItem.Product.Generic objects - We sort on a the 'Brand' property of StockTakeItem.Product The generated SQL contains 3 queries - The first query gets StockTakeItems, the second gets Products and the third query (which gets the Generic objects) looks like:
SELECT [Generic].[Id], [Generic].[AxGenericCode], [Generic].[CreatedOn], [Generic].[DeletedOn], [Generic].[GenericName], [Generic].[LockVersion], [Generic].[UpdatedOn] FROM [HosPharm].[Generic] WHERE (EXISTS ( SELECT [Product].* FROM [HosPharm].[Product] WHERE [Product].[GenericId] = [Generic].[Id] AND [Product].[DeletedOn] IS NULL AND EXISTS ( SELECT [StockTakeItem].* FROM ( SELECT [StockTakeItem].*, ROW_NUMBER() OVER(ORDER BY [Product].[Brand],[StockTakeItem].[CreatedOn] DESC,[StockTakeItem].[Id]) as RowNumber FROM [HosPharm].[StockTakeItem] INNER JOIN [HosPharm].[Product] [Product0] ON [StockTakeItem].[ProductId] = [Product0].[Id] WHERE [StockTakeItem].[StockTakeId] = @p2 ) [StockTakeItem] WHERE [StockTakeItem].[ProductId] = [Product].[Id] AND RowNumber > @p0 AND RowNumber <= @p1 ) ) AND [Generic].[DeletedOn] IS NULL)
The issue is that the [Product] alias being used in the 'ORDER BY' piece is incorrectly stated as [Product].[Brand], not [Product0],[Brand] - the result of this is that we are not getting the same, e.g. 10, products coming back for this 3rd query as for the first two, and we are seeing the 'KeyNotFoundException' I've downloaded the latest nightly builds, and reproduced the problem.
Are you able to have a look into this? Let me know if you need some scripts/code to repro...
thanks, Ian
|
|
|
Hi Ian, Can certainly have a look at this if you are able to send through a repro for this :)
Jeremy |
|
|
Hi Jeremy,
Below is a repro as small as I can make it. You'll notice that the 3rd eager loaded entity ends up with a
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.VisualStudio.TestTools.UnitTesting; using Mindscape.LightSpeed.Querying; using Mindscape.LightSpeed; using Hps.HosPharm.ServerCore.Model; using Hps.HosPharm.ServerServices.Common; using Mindscape.LightSpeed.Logging;
namespace Hps.HosPharm.UnitTests.Common.Querying { public class Person : Entity<int> { private int _countryId;
[EagerLoad] private readonly EntityHolder<Country> _country = new EntityHolder<Country>();
public Country Country { get { return Get(_country); } set { Set(_country, value); } }
public int CountryId { get { return Get(ref _countryId, "CountryId"); } set { Set(ref _countryId, value, "CountryId"); } }
}
public class Country : Entity<int> { private int _continentId;
[EagerLoad] private readonly EntityHolder<Continent> _continent = new EntityHolder<Continent>();
public Continent Continent { get { return Get(_continent); } set { Set(_continent, value); } }
public int ContinentId { get { return Get(ref _continentId, "ContinentId"); } set { Set(ref _continentId, value, "ContinentId"); } }
private readonly EntityCollection<Person> _persons = new EntityCollection<Person>();
public EntityCollection<Person> Persons { get { return Get(_persons); } }
private string _name;
public string Name { get { return Get(ref _name, "Name"); } set { Set(ref _name, value, "Name"); } } }
public class Continent : Entity<int> { private readonly EntityCollection<Country> _countries = new EntityCollection<Country>();
public EntityCollection<Country> Countries { get { return Get(_countries); } }
private string _name;
public string Name { get { return Get(ref _name, "Name"); } set { Set(ref _name, value, "Name"); } } }
[TestClass] public class LightspeedIssues { [TestMethod] public void LightspeedIssueWithSortingAndEagerLoading() { var query = new Query { Order = Order.By("Country.Name").AndBy("Id"), Page = Page.Offset(0).LimitTo(2) };
var logger = new StringLogger();
LightSpeedContext context = new LightSpeedContext() { ConnectionString = @"Data Source=localhost;Initial Catalog=Lightspeed;Integrated Security=SSPI", PluralizeTableNames = false, IdentityMethod = IdentityMethod.Guid, DataProvider = DataProvider.SqlServer2008, QuoteIdentifiers = false, Logger = logger };
try { using (var uow = context.CreateUnitOfWork()) { uow.Find<Person>(query); } } catch {}
Assert.Fail(); }
public class StringLogger : ILogger { public string Sql { get; private set; } public string Debug { get; private set; }
public StringLogger() { this.Sql = string.Empty; this.Debug = string.Empty; }
public void LogDebug(object text) { if (text != null) this.Debug += text.ToString(); }
public void LogSql(object sql) { if (sql != null) this.Sql += sql.ToString(); } } } } Part of sql with issues (3rd entity). The alias of Country0 is not updating the order by, resulting in wrong entities being selected (and thus error when its unable to create the whole graph).
SELECT
Continent.Id,
Continent.Name
FROM
Continent
WHERE
EXISTS (
SELECT
Country.*
FROM
Country
WHERE
Country.ContinentId = Continent.Id AND
EXISTS (
SELECT
Person.*
FROM
(
SELECT
Person.*,
ROW_NUMBER() OVER(ORDER BY Country.Name,Person.Id) as RowNumber
FROM
Person
INNER JOIN
Country Country0
ON
Person.CountryId = Country0.Id
)
Person
WHERE
Person.CountryId = Country.Id AND
RowNumber > 0 AND
RowNumber <= 2
)
)
|
|
|
And didn't finish my first sentence like usual. Hope you can work out my intention :)
Mark |
|
|
Hi guys, We have added in a candidate fix for this which will be available in tonights nightly build. Can you please have a look and confirm that it fixes the issue are seeing. It is generating the correct SQL for me for your test case so it looks happy but I dont have the same data to verify that it fixes the KeyNotFoundException part of this.
Jeremy |
|
|
Thanks Jeremy, Will check it out and let you know.
Mark |
|