Enhance nullability check for "==" and "!=" operators for LINQ provider#1996
Enhance nullability check for "==" and "!=" operators for LINQ provider#1996fredericDelaporte merged 11 commits intonhibernate:masterfrom
Conversation
| q = session.Query<AnotherEntityRequired>().Where(o => (o.NullableOutput + o.Output) == o.Output); | ||
| await (ExpectAsync(q, Does.Not.Contain("is null").IgnoreCase)); | ||
|
|
||
| q = session.Query<AnotherEntityRequired>().Where(o => (o.Input + o.Output) == o.Output); |
There was a problem hiding this comment.
Changed to o.Output + o.Output as otherwise it fails in oracle as in oracle concatenating null with a non empty string will not result in a null value like in the other databases. I think that we should add an additional logic when concatenating strings in order to have a consistent behaviour across various databases and possible align with Linq-to-Object so that null + "test" will not result in a null value.
| q = session.Query<AnotherEntityRequired>().Where(o => o.RelatedItems.Max(r => r.Id) != 0); | ||
| await (ExpectAllAsync(q, Does.Contain("is null").IgnoreCase)); | ||
|
|
||
| q = session.Query<AnotherEntityRequired>().Where(o => o.RelatedItems.Take(10).All(r => r.Output != null) != o.NullableBool); |
There was a problem hiding this comment.
Removed the Take call as it produces an invalid sql statement for Oracle.
| </id> | ||
| <property name="Output" not-null="true" /> | ||
| <property name="Input" not-null="true" /> | ||
| <property name="NullableOutput" formula="Output" lazy="true" /> |
There was a problem hiding this comment.
I've had to use lazy as otherwise an invalid query is generated due to the missing table alias for the column used in the formula.
| MapPropertyToIndex(null, prop, i); | ||
| } | ||
|
|
||
| private void MapPropertyToIndex(string path, Mapping.Property prop, int i) |
There was a problem hiding this comment.
Copied from #2079. It is a fix for including nested components.
| <property name="RegisteredAt" type="DateTime" /> | ||
| <property name="LastLoginDate" type="DateTime" /> | ||
|
|
||
| <many-to-one name="CreatedBy" class="User" not-null="true" lazy="false"> |
There was a problem hiding this comment.
I had to add lazy="false", otherwise some tests in QueryReuseTests (CanReuseAfterFirst, CanReuseAfterFirstOrDefault, CanReuseAfterSingle, CanReuseAfterSingleOfDefault) would fail.
0f8c46b to
d067e8c
Compare
|
Rebased and fixed |
I will agree with CodeFactor that this method is too complex (and too hard for me to understand). |
|
Ok, I will try to make the method more readable by adding documentation, split into multiple methods, try to simplify the logic and add isolated tests. |
|
I tried my best to make the method more readable and to reduce its complexity in #2036. I've added several isolated tests in order to cover all kind of mappings. I think that the method is now more readable but the complexity didn't dropped, it even increased so I am not sure what to do about it. Should I split it into more smaller methods or replace the method with a method object? EDIT: |
2e892c8 to
29d2052
Compare
|
Rebased and updated code to use |
This PR adds a slightly complex logic that determines if it should add a
OR <Property> IS NULLcheck for==and!=operators, fixes #1860. The logic will not add the additional null check for the following scenarios:Example:
s.Query<Order>().Where(o => o.Number != 5)Example:
s.Query<Order>().Where(o => o.Status != "NEW")!=operator.Example:
s.Query<Order>().Where(o => o.Status != null && o.Status != "NEW")HasValuecheck before or after the!=operator.Example:
s.Query<Order>().Where(o => o.Number.HasValue && o.Number != 3)!=operator is not null.Example:
s.Query<Order>().Where(o => (o.NotNullProperty + o.NotNullProperty2) != "TEST")==operator and one of them or both have a not null check.Example:
s.Query<Order>().Where(o => o.NullProperty != null && o.NullProperty == o.NullProperty2)There are some scenarios where the logic will add a null check where currently it is not added:
Example:
s.Query<Order>().Where(o => o.Rows.Max(r => r.Number) != 0)Example:
s.Query<Order>().Where(o => o.Status.Length != 3)In addition, the
Equalsmethod was modified to use the same logic as the==operator.