NH 3.0 Linq provider uses query parameters from first call in subsequent calls.


NH 3.0 Linq provider uses query parameters from first call in subsequent calls if this parameters are not propagated to SQL.

I've debugged NH and found that in second query it gets QueryPlan from cache in NHibernate.Impl.AbstractSessionImpl.GetHQLQueryPlan() and it contains parameters from first call of query (NHibernate.Linq.NhLinqExpression.ParameterValuesByName) and then fails to replace them in NHibernate.Linq.NhQueryProvider.SetParameters() because they are not actual SQL parameters (query.NamedParameters).

Sample solution is attached (VS2010, SQL Server Express DB). Put NH and LinFu.DynamicProxy binaries to .Libraries\NHibernate before build.

I think actual parameters should be cleared from query (set to default(T)) before putting plan in QueryPlanCache to let them be garbage collected and prevent real magic happen in case of similar bugs.




Frédéric Delaporte
January 18, 2018, 6:04 PM

Moved here.

Frédéric Delaporte
July 13, 2017, 5:12 PM

is unrelated, it is about the first level entity cache. Here the trouble lies in the query plan cache. This does not cache anything entity related.

It appears a fix and a test have been contributed in January 2012, without reporting here. They have made it in 3.3.0 version. But I suspect they have fixed only a subset of the trouble.

More tests should be contributed and checked/fixed. The fix looks a bit hackish to me, but I have not analyzed it thoroughly.

Ricardo Peres
September 18, 2014, 9:08 AM

: I have submitted a similar suggestion: NH-3231.
Haven't given up on that, but it would work per query. For permanent solutions, use a stateless session.

September 17, 2014, 9:47 AM

Hey, guys, what about implementing another feature - disable cache (permanently or temporarely).
We already did this by reflection (see an attachment 'QueryPlanCacheControl.cs') in our project. Through Reflection we are receiving QyerPlanCache instance and replace its fields with empty mocks. So, cache always misses, but query executes correctly.
We didn't see big performance issues in our solution, so we disabled cache permanently. If you think, that performance reducing, so you can replace caching values back, after "dangerous" query completes execution.

Scott Whitlock
February 27, 2014, 11:59 AM

I've been burned by this several times. It's completely unintuitive until you really grasp what it's doing under the hood, and even then it's hard to avoid. In order to always avoid this issue, now I always just return full entities from my queries, and then I translate into DTO's, but that completely nullifies any performance advantage I would be seeing from the cache feature that's creating this problem. How about removing the query cache feature completely until it can be done correctly?





Andrey Titov



Fix versions

Affects versions