@@ -395,8 +395,25 @@ private SqlExpression ApplyTypeMappingOnJsonScalar(
395
395
ExpressionType operatorType ,
396
396
SqlExpression left ,
397
397
SqlExpression right ,
398
- RelationalTypeMapping ? typeMapping )
398
+ RelationalTypeMapping ? typeMapping ,
399
+ SqlExpression ? existingExpr = null )
399
400
{
401
+ if ( existingExpr is SqlBinaryExpression binaryExpr
402
+ && binaryExpr . OperatorType == operatorType
403
+ && left == binaryExpr . Left
404
+ && right == binaryExpr . Right )
405
+ {
406
+ return existingExpr ;
407
+ }
408
+
409
+ switch ( operatorType )
410
+ {
411
+ case ExpressionType . AndAlso :
412
+ return AndAlso ( left , right ) ;
413
+ case ExpressionType . OrElse :
414
+ return OrElse ( left , right ) ;
415
+ }
416
+
400
417
if ( ! SqlBinaryExpression . IsValidOperator ( operatorType ) )
401
418
{
402
419
return null ;
@@ -447,11 +464,78 @@ public virtual SqlExpression LessThanOrEqual(SqlExpression left, SqlExpression r
447
464
448
465
/// <inheritdoc />
449
466
public virtual SqlExpression AndAlso ( SqlExpression left , SqlExpression right )
450
- => MakeBinary ( ExpressionType . AndAlso , left , right , null ) ! ;
467
+ {
468
+ SqlExpression result ;
469
+
470
+ // false && x -> false
471
+ // x && true -> x
472
+ // x && x -> x
473
+ if ( left is SqlConstantExpression { Value : false }
474
+ || right is SqlConstantExpression { Value : true }
475
+ || left . Equals ( right ) )
476
+ {
477
+ result = left ;
478
+ }
479
+ // true && x -> x
480
+ // x && false -> false
481
+ else if ( left is SqlConstantExpression { Value : true } || right is SqlConstantExpression { Value : false } )
482
+ {
483
+ result = right ;
484
+ }
485
+ // x is null && x is not null -> false
486
+ // x is not null && x is null -> false
487
+ else if ( left is SqlUnaryExpression { OperatorType : ExpressionType . Equal or ExpressionType . NotEqual } leftUnary
488
+ && right is SqlUnaryExpression { OperatorType : ExpressionType . Equal or ExpressionType . NotEqual } rightUnary
489
+ && leftUnary . Operand . Equals ( rightUnary . Operand ) )
490
+ {
491
+ // the case in which left and right are the same expression is handled above
492
+ result = Constant ( false ) ;
493
+ }
494
+ else
495
+ {
496
+ result = new SqlBinaryExpression ( ExpressionType . AndAlso , left , right , typeof ( bool ) , null ) ;
497
+ }
498
+
499
+ return ApplyTypeMapping ( result , _boolTypeMapping ) ;
500
+ }
451
501
452
502
/// <inheritdoc />
453
503
public virtual SqlExpression OrElse ( SqlExpression left , SqlExpression right )
454
- => MakeBinary ( ExpressionType . OrElse , left , right , null ) ! ;
504
+ {
505
+ SqlExpression result ;
506
+
507
+ // true || x -> true
508
+ // x || false -> x
509
+ // x || x -> x
510
+ if ( left is SqlConstantExpression { Value : true }
511
+ || right is SqlConstantExpression { Value : false }
512
+ || left . Equals ( right ) )
513
+ {
514
+ result = left ;
515
+ }
516
+ // false || x -> x
517
+ // x || true -> true
518
+ else if ( left is SqlConstantExpression { Value : false }
519
+ || right is SqlConstantExpression { Value : true } )
520
+ {
521
+ result = right ;
522
+ }
523
+ // x is null || x is not null -> true
524
+ // x is not null || x is null -> true
525
+ else if ( left is SqlUnaryExpression { OperatorType : ExpressionType . Equal or ExpressionType . NotEqual } leftUnary
526
+ && right is SqlUnaryExpression { OperatorType : ExpressionType . Equal or ExpressionType . NotEqual } rightUnary
527
+ && leftUnary . Operand . Equals ( rightUnary . Operand ) )
528
+ {
529
+ // the case in which left and right are the same expression is handled above
530
+ result = Constant ( true ) ;
531
+ }
532
+ else
533
+ {
534
+ result = new SqlBinaryExpression ( ExpressionType . OrElse , left , right , typeof ( bool ) , null ) ;
535
+ }
536
+
537
+ return ApplyTypeMapping ( result , _boolTypeMapping ) ;
538
+ }
455
539
456
540
/// <inheritdoc />
457
541
public virtual SqlExpression Add ( SqlExpression left , SqlExpression right , RelationalTypeMapping ? typeMapping = null )
0 commit comments