@@ -32,7 +32,7 @@ public class SearchConditionConverter(ISqlExpressionFactory sqlExpressionFactory
3232 /// </summary>
3333 [ return : NotNullIfNotNull ( nameof ( expression ) ) ]
3434 public override Expression ? Visit ( Expression ? expression )
35- => Visit ( expression , inSearchConditionContext : false ) ;
35+ => Visit ( expression , inSearchConditionContext : false , allowNullFalseEquivalence : false ) ;
3636
3737 /// <summary>
3838 /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -41,12 +41,12 @@ public class SearchConditionConverter(ISqlExpressionFactory sqlExpressionFactory
4141 /// doing so can result in application failures when updating to a new Entity Framework Core release.
4242 /// </summary>
4343 [ return : NotNullIfNotNull ( nameof ( expression ) ) ]
44- protected virtual Expression ? Visit ( Expression ? expression , bool inSearchConditionContext )
44+ protected virtual Expression ? Visit ( Expression ? expression , bool inSearchConditionContext , bool allowNullFalseEquivalence )
4545 => expression switch
4646 {
47- CaseExpression e => VisitCase ( e , inSearchConditionContext ) ,
47+ CaseExpression e => VisitCase ( e , inSearchConditionContext , allowNullFalseEquivalence ) ,
4848 SelectExpression e => VisitSelect ( e ) ,
49- SqlBinaryExpression e => VisitSqlBinary ( e , inSearchConditionContext ) ,
49+ SqlBinaryExpression e => VisitSqlBinary ( e , inSearchConditionContext , allowNullFalseEquivalence ) ,
5050 SqlUnaryExpression e => VisitSqlUnary ( e , inSearchConditionContext ) ,
5151 PredicateJoinExpressionBase e => VisitPredicateJoin ( e ) ,
5252
@@ -139,19 +139,19 @@ private SqlExpression SimplifyNegatedBinary(SqlExpression sqlExpression)
139139 /// any release. You should only use it directly in your code with extreme caution and knowing that
140140 /// doing so can result in application failures when updating to a new Entity Framework Core release.
141141 /// </summary>
142- protected virtual Expression VisitCase ( CaseExpression caseExpression , bool inSearchConditionContext )
142+ protected virtual Expression VisitCase ( CaseExpression caseExpression , bool inSearchConditionContext , bool allowNullFalseEquivalence )
143143 {
144144 var testIsCondition = caseExpression . Operand is null ;
145145 var operand = ( SqlExpression ? ) Visit ( caseExpression . Operand ) ;
146146 var whenClauses = new List < CaseWhenClause > ( ) ;
147147 foreach ( var whenClause in caseExpression . WhenClauses )
148148 {
149- var test = ( SqlExpression ) Visit ( whenClause . Test , testIsCondition ) ;
150- var result = ( SqlExpression ) Visit ( whenClause . Result ) ;
149+ var test = ( SqlExpression ) Visit ( whenClause . Test , testIsCondition , testIsCondition ) ;
150+ var result = ( SqlExpression ) Visit ( whenClause . Result , inSearchConditionContext : false , allowNullFalseEquivalence ) ;
151151 whenClauses . Add ( new CaseWhenClause ( test , result ) ) ;
152152 }
153153
154- var elseResult = ( SqlExpression ? ) Visit ( caseExpression . ElseResult ) ;
154+ var elseResult = ( SqlExpression ? ) Visit ( caseExpression . ElseResult , inSearchConditionContext : false , allowNullFalseEquivalence ) ;
155155
156156 return ApplyConversion (
157157 sqlExpressionFactory . Case ( operand , whenClauses , elseResult , caseExpression ) ,
@@ -168,7 +168,7 @@ protected virtual Expression VisitCase(CaseExpression caseExpression, bool inSea
168168 protected virtual Expression VisitPredicateJoin ( PredicateJoinExpressionBase join )
169169 => join . Update (
170170 ( TableExpressionBase ) Visit ( join . Table ) ,
171- ( SqlExpression ) Visit ( join . JoinPredicate , inSearchConditionContext : true ) ) ;
171+ ( SqlExpression ) Visit ( join . JoinPredicate , inSearchConditionContext : true , allowNullFalseEquivalence : true ) ) ;
172172
173173 /// <summary>
174174 /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -179,9 +179,9 @@ protected virtual Expression VisitPredicateJoin(PredicateJoinExpressionBase join
179179 protected virtual Expression VisitSelect ( SelectExpression select )
180180 {
181181 var tables = this . VisitAndConvert ( select . Tables ) ;
182- var predicate = ( SqlExpression ? ) Visit ( select . Predicate , inSearchConditionContext : true ) ;
182+ var predicate = ( SqlExpression ? ) Visit ( select . Predicate , inSearchConditionContext : true , allowNullFalseEquivalence : true ) ;
183183 var groupBy = this . VisitAndConvert ( select . GroupBy ) ;
184- var havingExpression = ( SqlExpression ? ) Visit ( select . Having , inSearchConditionContext : true ) ;
184+ var havingExpression = ( SqlExpression ? ) Visit ( select . Having , inSearchConditionContext : true , allowNullFalseEquivalence : true ) ;
185185 var projections = this . VisitAndConvert ( select . Projection ) ;
186186 var orderings = this . VisitAndConvert ( select . Orderings ) ;
187187 var offset = ( SqlExpression ? ) Visit ( select . Offset ) ;
@@ -196,19 +196,19 @@ protected virtual Expression VisitSelect(SelectExpression select)
196196 /// any release. You should only use it directly in your code with extreme caution and knowing that
197197 /// doing so can result in application failures when updating to a new Entity Framework Core release.
198198 /// </summary>
199- protected virtual Expression VisitSqlBinary ( SqlBinaryExpression binary , bool inSearchConditionContext )
199+ protected virtual Expression VisitSqlBinary ( SqlBinaryExpression binary , bool inSearchConditionContext , bool allowNullFalseEquivalence )
200200 {
201201 // Only logical operations need conditions on both sides
202202 var areOperandsInSearchConditionContext = binary . OperatorType is ExpressionType . AndAlso or ExpressionType . OrElse ;
203203
204- var newLeft = ( SqlExpression ) Visit ( binary . Left , areOperandsInSearchConditionContext ) ;
205- var newRight = ( SqlExpression ) Visit ( binary . Right , areOperandsInSearchConditionContext ) ;
204+ var newLeft = ( SqlExpression ) Visit ( binary . Left , areOperandsInSearchConditionContext , allowNullFalseEquivalence : false ) ;
205+ var newRight = ( SqlExpression ) Visit ( binary . Right , areOperandsInSearchConditionContext , allowNullFalseEquivalence : false ) ;
206206
207207 if ( binary . OperatorType is ExpressionType . NotEqual or ExpressionType . Equal )
208208 {
209209 var leftType = newLeft . TypeMapping ? . Converter ? . ProviderClrType ?? newLeft . Type ;
210210 var rightType = newRight . TypeMapping ? . Converter ? . ProviderClrType ?? newRight . Type ;
211- if ( ! inSearchConditionContext
211+ if ( ! inSearchConditionContext && ! allowNullFalseEquivalence
212212 && ( leftType == typeof ( bool ) || leftType . IsInteger ( ) )
213213 && ( rightType == typeof ( bool ) || rightType . IsInteger ( ) ) )
214214 {
@@ -309,7 +309,7 @@ protected virtual Expression VisitSqlUnary(SqlUnaryExpression sqlUnaryExpression
309309 sqlUnaryExpression . OperatorType , typeof ( SqlUnaryExpression ) ) ) ;
310310 }
311311
312- var operand = ( SqlExpression ) Visit ( sqlUnaryExpression . Operand , isOperandInSearchConditionContext ) ;
312+ var operand = ( SqlExpression ) Visit ( sqlUnaryExpression . Operand , isOperandInSearchConditionContext , allowNullFalseEquivalence : false ) ;
313313
314314 return SimplifyNegatedBinary (
315315 ApplyConversion (
0 commit comments