-
Notifications
You must be signed in to change notification settings - Fork 934
Avoid unnecessary casting for Linq provider #2491
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
short value = 1; | ||
await (AssertTotalParametersAsync( | ||
db.Users.Where(o => o.NullableShort == value && o.NullableShort != value && o.Short == value), | ||
1)); |
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.
Prior this PR there would be 3 parameters.
@@ -560,6 +577,15 @@ public async Task NullInequalityAsync() | |||
|
|||
await (ExpectAsync(session.Query<User>().Where(o => o.CreatedBy.ModifiedBy.Id != 5), Does.Contain("is null").IgnoreCase)); | |||
await (ExpectAsync(session.Query<User>().Where(o => 5 != o.CreatedBy.ModifiedBy.Id), Does.Contain("is null").IgnoreCase)); | |||
|
|||
short value = 3; |
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.
unnecessary cast is exists short/long with == / <= / >= operators could you add additional test cases.
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.
When comparing two different types short == long
, a cast will always be added when the mapped sql type of short
and long
are different. I am thinking of restoring the previous behavior of Equals
in case a user wants to compare two different types without an explicit cast as this is not possible anymore in 5.3
.
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.
I think the operators and methods should work exactly the same, otherwise the software developer might make an error about which one to use and under what condition. If not careful, sql clauses are created which can cause performance problems.
The strange thing is that it casts unnecessarily in short to short or long to long comparisons.
Equals method with == operator
CompareTo method result == 0 with == operator
CompareTo method result < 0 with <= operator
CompareTo method result > 0 with >= operator
Does this case still qualifies as a regression? It is not really clear when reading #2490. |
The problem is that with #1996, o.Short.Equals(3) In 5.2.x a cast is not added, where in 5.3 it is added due to a type mismatch (
Technically it is a regression but this PR does not solves it entirely, that is why I am thinking to restore the old |
I think we have a flaw in the casting logic: it should cast the parameter whenever possible, instead of the column. Casting a parameter has far less potential for causing performances issues than casting a column. And a parameter cast could be even pre-evaluated. |
@fredericDelaporte @maca88 https://github.com/gokhanabatay/NHibernateBugTest/blob/master/NHibernateBugTest/CustomTypeSelectFailsTest.cs var query = session.Query<Customer>().Where(x => x.Addresses.Any(y => y.AddressType.Value == y.AddressType2.Value)); select customer0_.GUID as guid1_1_, customer0_.NAME as name2_1_ from CUSTOMER customer0_
where exists (select addresses1_.GUID from ADDRESS addresses1_ where customer0_.GUID=addresses1_.CUSTOMER_GUID
and (cast(addresses1_.ADDRESS_TYPE as int4)=cast(addresses1_.ADDRESS_TYPE2 as int4)
or (cast(addresses1_.ADDRESS_TYPE as int4) is null) and (cast(addresses1_.ADDRESS_TYPE2 as int4) is null))) |
I do agree, I will try to implement the following rules:
I think that the above rules should be good enough.
This is already fixed with the current state of this PR, I will add additional tests for that. |
The last commit implements almost all rules as described, except for rule:
which is implemented partially. For |
Rebased. |
@@ -24,7 +24,7 @@ public class FirebirdClientDriver : ReflectionBasedDriver | |||
// Zero-width negative look-behind: the match must not be preceded by | |||
@"(?<!" + | |||
// a comparison, | |||
@"[=<>]\s" + | |||
@"[=<>]\s*" + |
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.
Reverted the possible regex fix for Firebird as there are other tests that would need to be modified, so tests are now skipped instead. Maybe a better fix would be to use transparentcast
, similar what was done for SqLite.
src/NHibernate/Linq/Visitors/NhPartialEvaluatingExpressionVisitor.cs
Outdated
Show resolved
Hide resolved
Co-authored-by: Frédéric Delaporte <12201973+fredericDelaporte@users.noreply.github.com>
I did some refactoring for readability. |
Thanks! |
…od to make code more readable
I find it a bit confusing when 2 methods with the same name have some subtle difference in functionality - so I merged them. I hope readability is not affected ) |
Yes it does, updated the description of this PR. |
This PR contains an improvement for parameter detection that are related to nullable expressions, which was needed to avoid unnecessary casting reported in #2490.
Fixes #2490