You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Lets assume we want to execute 2 queries that contains a constant expression with the same object but with different values inside this object. In provided example query has been created with a help of EF.Const and with a object (value) of type List.
For queryResultWithOneId query has been generated correctly.
Generated query: SELECT [i].[Id] FROM [Items] AS [i] WHERE [i].[Id] = 1
However after changing contents of idList by adding a value (2) and executing the same query second time, generated query is no longer correct as it is exactly the same as the one generated for queryResultWithOneId.
Generated query: SELECT [i].[Id] FROM [Items] AS [i] WHERE [i].[Id] = 1
Correct query: SELECT [i].[Id] FROM [Items] AS [i] WHERE [i].[Id] IN (1, 2)
After a brief investigation, it became apparent that ICompiledQueryCache got a hit and returned a complied query from cache. It seems that ICompiledQueryCacheKeyGenerator generates a key based of created expression. This expression contains ConstantExpression that holds a reference (or value, depending on the provided constant type) to provided value. Consequently, modifying contents of idList also changes value stored in expression stored within cache key. When executing a second query, the query plan cache key has already been altered due to changing idList contents. Subsequently, _memoryCache.TryGetValue in ICompiledQueryCache got a hit and returns compiled query that was created when idList contained old values.
In sumary, changing values in reference types referenced in ConstantExpression changes cache key of previously generated query plan which causes cache to return invalid query plans.
Include provider and version information
EF Core version:
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET 8.0
Operating system: Windows 10
IDE: Visual Studio 2022 17.8.6
The text was updated successfully, but these errors were encountered:
The query cache comparison likely doesn't check inside collections in ConstantExpression - this is something we can look at.
Though note that we have #33674, which is about reimplementing EF.Constant in a more efficient way, which would also fix this (queries with different values of the list would always have the same cache key, and the actual list would be integrated only later, in the 2nd part of the query pipeline). However, the problem would technically remain for people building expression trees manually and inserting ConstantExpression nodes themselves.
Note: you should be able to work around this by using a different list instance (though this should produce a cache miss for all cases, even those where the collection contents is the same).
Lets assume we want to execute 2 queries that contains a constant expression with the same object but with different values inside this object. In provided example query has been created with a help of EF.Const and with a object (value) of type List.
For queryResultWithOneId query has been generated correctly.
Generated query:
SELECT [i].[Id] FROM [Items] AS [i] WHERE [i].[Id] = 1
However after changing contents of idList by adding a value (2) and executing the same query second time, generated query is no longer correct as it is exactly the same as the one generated for queryResultWithOneId.
Generated query:
SELECT [i].[Id] FROM [Items] AS [i] WHERE [i].[Id] = 1
Correct query:
SELECT [i].[Id] FROM [Items] AS [i] WHERE [i].[Id] IN (1, 2)
How to reproduce
Investigation
After a brief investigation, it became apparent that ICompiledQueryCache got a hit and returned a complied query from cache. It seems that ICompiledQueryCacheKeyGenerator generates a key based of created expression. This expression contains ConstantExpression that holds a reference (or value, depending on the provided constant type) to provided value. Consequently, modifying contents of idList also changes value stored in expression stored within cache key. When executing a second query, the query plan cache key has already been altered due to changing idList contents. Subsequently, _memoryCache.TryGetValue in ICompiledQueryCache got a hit and returns compiled query that was created when idList contained old values.
In sumary, changing values in reference types referenced in
ConstantExpression
changes cache key of previously generated query plan which causes cache to return invalid query plans.Include provider and version information
EF Core version:
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET 8.0
Operating system: Windows 10
IDE: Visual Studio 2022 17.8.6
The text was updated successfully, but these errors were encountered: