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

Description

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.

Environment

None

Attachments

5

Activity

Show:

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

Moved here.

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

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 at 9:08 AM
Edited

: 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.

AlexanderM September 17, 2014 at 9:47 AM
Edited

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 at 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?

Fixed

Details

Assignee

Unassigned

Reporter

Labels

Components

Fix versions

Affects versions

Priority

Who's Looking?

Open Who's Looking?
Created January 13, 2011 at 10:32 AM
Updated January 20, 2018 at 10:48 PM
Resolved January 20, 2018 at 10:42 PM
Who's Looking?
Loading...