/// <summary> /// This API supports the Entity Framework Core infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// </summary> protected override Expression VisitMethodCall(MethodCallExpression methodCallExpression) { var newMethodCallExpression = (MethodCallExpression)base.VisitMethodCall(methodCallExpression); Expression newLeftExpression = null; Expression newRightExpression = null; if (newMethodCallExpression.Method.Name == nameof(object.Equals) && newMethodCallExpression.Object != null && newMethodCallExpression.Arguments.Count == 1) { newLeftExpression = newMethodCallExpression.Object; newRightExpression = newMethodCallExpression.Arguments[0]; } if (newMethodCallExpression.Method.Equals(_objectEqualsMethodInfo)) { newLeftExpression = newMethodCallExpression.Arguments[0]; newRightExpression = newMethodCallExpression.Arguments[1]; } if (newLeftExpression != null && newRightExpression != null) { var isLeftNullConstant = newLeftExpression.IsNullConstantExpression(); var isRightNullConstant = newRightExpression.IsNullConstantExpression(); if (isLeftNullConstant && isRightNullConstant) { return(newMethodCallExpression); } if (isLeftNullConstant || isRightNullConstant) { var result = RewriteNullEquality( ExpressionType.Equal, isLeftNullConstant ? newRightExpression : newLeftExpression); if (result != null) { return(result); } } var leftEntityType = _model.FindEntityType(newLeftExpression.Type) ?? MemberAccessBindingExpressionVisitor.GetEntityType(newLeftExpression, _queryCompilationContext); var rightEntityType = _model.FindEntityType(newRightExpression.Type) ?? MemberAccessBindingExpressionVisitor.GetEntityType(newRightExpression, _queryCompilationContext); if (leftEntityType != null && rightEntityType != null) { if (leftEntityType.RootType() == rightEntityType.RootType()) { var result = RewriteEntityEquality(ExpressionType.Equal, newLeftExpression, newRightExpression); if (result != null) { return(result); } } else { return(Expression.Constant(false)); } } } return(newMethodCallExpression); }
/// <summary> /// This API supports the Entity Framework Core infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// </summary> protected override Expression VisitBinary(BinaryExpression binaryExpression) { Check.NotNull(binaryExpression, nameof(binaryExpression)); var newBinaryExpression = (BinaryExpression)base.VisitBinary(binaryExpression); if (binaryExpression.NodeType == ExpressionType.Equal || binaryExpression.NodeType == ExpressionType.NotEqual) { var isLeftNullConstant = newBinaryExpression.Left.IsNullConstantExpression(); var isRightNullConstant = newBinaryExpression.Right.IsNullConstantExpression(); if (isLeftNullConstant && isRightNullConstant) { return(newBinaryExpression); } var isNullComparison = isLeftNullConstant || isRightNullConstant; var nonNullExpression = isLeftNullConstant ? newBinaryExpression.Right : newBinaryExpression.Left; var qsre = nonNullExpression as QuerySourceReferenceExpression; var leftProperties = MemberAccessBindingExpressionVisitor.GetPropertyPath( newBinaryExpression.Left, _queryCompilationContext, out var leftNavigationQsre); var rightProperties = MemberAccessBindingExpressionVisitor.GetPropertyPath( newBinaryExpression.Right, _queryCompilationContext, out var rightNavigationQsre); if (isNullComparison) { var nonNullNavigationQsre = isLeftNullConstant ? rightNavigationQsre : leftNavigationQsre; var nonNullproperties = isLeftNullConstant ? rightProperties : leftProperties; if (IsCollectionNavigation(nonNullNavigationQsre, nonNullproperties)) { // collection navigation is only null if its parent entity is null (null propagation thru navigation) // it is probable that user wanted to see if the collection is (not) empty, log warning suggesting to use Any() instead. _queryCompilationContext.Logger .PossibleUnintendedCollectionNavigationNullComparisonWarning(nonNullproperties); var callerExpression = CreateCollectionCallerExpression(nonNullNavigationQsre, nonNullproperties); return(Visit(Expression.MakeBinary(newBinaryExpression.NodeType, callerExpression, Expression.Constant(null)))); } } var collectionNavigationComparison = TryRewriteCollectionNavigationComparison( newBinaryExpression.Left, newBinaryExpression.Right, newBinaryExpression.NodeType, leftNavigationQsre, rightNavigationQsre, leftProperties, rightProperties); if (collectionNavigationComparison != null) { return(collectionNavigationComparison); } // If a reference navigation is being compared to null then don't rewrite if (isNullComparison && qsre == null) { return(newBinaryExpression); } var entityType = _queryCompilationContext.Model.FindEntityType(nonNullExpression.Type); if (entityType == null) { if (qsre != null) { entityType = _queryCompilationContext.FindEntityType(qsre.ReferencedQuerySource); } else { entityType = MemberAccessBindingExpressionVisitor.GetEntityType( nonNullExpression, _queryCompilationContext); } } if (entityType != null) { return(CreateKeyComparison( entityType, newBinaryExpression.Left, newBinaryExpression.Right, newBinaryExpression.NodeType, isLeftNullConstant, isRightNullConstant, isNullComparison)); } } return(newBinaryExpression); }