-
Notifications
You must be signed in to change notification settings - Fork 934
NH-3961 - Linq auto-parameterization failures #570
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@@ -26,9 +27,11 @@ static NhRelinqQueryParser() | |||
transformerRegistry.Register(new RemoveRedundantCast()); | |||
transformerRegistry.Register(new SimplifyCompareTransformer()); | |||
|
|||
var processor = ExpressionTreeParser.CreateDefaultProcessor(transformerRegistry); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This (current source) was creating a CompoundExpressionTreeProcessor
containing a PartialEvaluatingExpressionTreeProcessor
then a TransformingExpressionTreeProcessor
.
But this parser is currently only used by NhLinqExpression
, which has already processed the expression with a PartialEvaluatingExpressionVisitor
(which the corresponding processor use itself without additional processing as of current sources).
This second evaluation was sometimes able of evaluating further some sub-trees, altering constants which were awaiting conversion to query parameters, and causing them to no more be converted to parameters. This was occurring with MappedAs
on a non nullable constant compared to a nullable entity property. See NH-3961 comments for more details.
(Unfortunately, this change may be a possible breaking change for some external library, since NhRelinqQueryParser
is public and could have other usages outside of NHibernate.)
I just realize this change could have an interesting "side effect": allowing non-runtime Linq extension to be used without referencing an entity. And I have tested it: yes it works! With this PR, we could additionaly define and use something like:
And use it:
And it get executed as following SQL:
That was not anticipated, but eliminating this second But then I have to update the new Linq provider documentation ^^. |
@fredericDelaporte it's described here: NH-3386. Can you also add test cases for it? |
Test case for NH-3386 added. Now I have seen we may filter out some evaluations by adding a filter deriving from But changing that in this PR is maybe not adequate. If done separately, it will then have to wait for this PR. |
But EvaluatableExpressionFilterBase is available only in ReLinq 2.1, isn't
it?
…On Sat, 18 Mar 2017 at 9:50 PM, Frédéric Delaporte ***@***.***> wrote:
Test case for NH-3386 added.
Now I have seen we may filter out certain evaluations by adding a filter
deriving from {{EvaluatableExpressionFilterBase}}. This could allow
supporting this feature without relying on exception being thrown, and
silently swallowed by NH partial evaluation as it is currently.
I think I would add a parameter on {{LinqExtensionMethod}} such as
{{DBSideOnly}}, defaulting to {{false}}. The filter would check it and also
explicitly filter the {{MappedAs}} case. Partial evaluation exceptions
would no more be swallowed.
But changing that in this PR is maybe not adequate. If done separately, it
will then have to wait for this PR.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#570 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAI1l7TLV16hlKwQjpJrtGIOgrGiqCH1ks5rm5rbgaJpZM4MgvX0>
.
|
You are right, I have seen it in 2.1 reference documentation and not checked with IlSpy it was there in 1.13. Implementing it that way would have to wait for your PR for upgrading re-linq. Otherwise we may define a specific exception to throw (such as As NH-3386 was never supported, it would be preferable to freeze its interface before release. If it gets released with this "any exception causes it to be silently evaluated db-side" behavior, changing that afterward for what I suggest would be a breaking change. |
I did not check your request, but I suppose that removing a |
With the filter (in 2.1) we would be able to make a generator for |
.OrderBy(e => SqlServerFunction.NewID()); | ||
|
||
Assert.DoesNotThrow(() => { result.ToList(); }); | ||
Assert.AreEqual(true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please update to NUnit fluent syntax: Assert.That(sqlInterceptor.Sql.ToString(), Does.Contain(nameof(SqlServerFunction.NewID)).IgnoreCase)
c0a5ebd
to
b5bf1b2
Compare
Done and squashed. |
As EF 6 is doing, but I am not fond of that. I think something missing about functions is a static class like |
b5bf1b2
to
aba2943
Compare
|
Tests and fix for NH-3961: in some edge circumstances, the parameters parsed from an expression are not actually parameterized in the final resulting query.
This causes bugs as described in NH-3961, including queries ending up executed with parameter values of previous queries.