protected override Expression VisitMember(MemberExpression memberExpression) { var newExpression = Visit(memberExpression.Expression); var boundProperty = TryBindProperty(memberExpression, newExpression, memberExpression.Member.Name); var result = boundProperty ?? memberExpression.Update(newExpression); // add null safety when accessing property of optional navigation // we don't need to do it for collections (i.e. collection.Count) because they will be converted into subqueries anyway if (boundProperty == null && newExpression is NavigationBindingExpression navigationBindingExpression && navigationBindingExpression.NavigationTreeNode.Optional && navigationBindingExpression.NavigationTreeNode.Navigation?.IsCollection() != true) { var nullProtection = new NullConditionalExpression(newExpression, result); if (nullProtection.Type == result.Type) { return(nullProtection); } result = Expression.Convert(nullProtection, memberExpression.Type); } return(result); }
private void VisitNullConditionalExpression(NullConditionalExpression nullConditionalExpression) { if (nullConditionalExpression.AccessOperation is MemberExpression memberExpression) { Visit(nullConditionalExpression.Caller); _stringBuilder.Append("?." + memberExpression.Member.Name); } else if (nullConditionalExpression.AccessOperation is MethodCallExpression methodCallExpression) { if (methodCallExpression.Object != null) { Visit(nullConditionalExpression.Caller); _stringBuilder.Append("?." + methodCallExpression.Method.Name + "("); VisitArguments(methodCallExpression.Arguments, s => _stringBuilder.Append(s)); _stringBuilder.Append(")"); } var method = methodCallExpression.Method; _stringBuilder.Append(method.DeclaringType?.Name + "." + method.Name + "(?"); Visit(nullConditionalExpression.Caller); _stringBuilder.Append("?, "); VisitArguments(methodCallExpression.Arguments.Skip(1).ToList(), s => _stringBuilder.Append(s)); _stringBuilder.Append(")"); } else { _stringBuilder.Append("?"); Visit(nullConditionalExpression.AccessOperation); _stringBuilder.Append("?"); } }
private static Expression BuildCollectionAccessorExpression( ParameterExpression parameter, IEnumerable <IPropertyBase> navigations) { Expression result = parameter; Expression memberExpression = parameter; foreach (var navigation in navigations) { memberExpression = memberExpression.MakeMemberAccess(navigation.GetIdentifyingMemberInfo()); result = new NullConditionalExpression(result, memberExpression); } return(result); }
private static void ApplyParentOrderings( IEnumerable <Ordering> parentOrderings, QueryModel queryModel, QuerySourceMapping querySourceMapping, bool reverseOrdering) { var orderByClause = queryModel.BodyClauses.OfType <OrderByClause>().LastOrDefault(); if (orderByClause == null) { queryModel.BodyClauses.Add(orderByClause = new OrderByClause()); } foreach (var ordering in parentOrderings) { var newExpression = CloningExpressionVisitor .AdjustExpressionAfterCloning(ordering.Expression, querySourceMapping); if (newExpression is MethodCallExpression methodCallExpression && methodCallExpression.Method.IsEFPropertyMethod()) { newExpression = new NullConditionalExpression( methodCallExpression.Arguments[0], methodCallExpression.Arguments[0], methodCallExpression); } orderByClause.Orderings .Add(new Ordering(newExpression, ordering.OrderingDirection)); } if (reverseOrdering) { foreach (var ordering in orderByClause.Orderings) { ordering.OrderingDirection = ordering.OrderingDirection == OrderingDirection.Asc ? OrderingDirection.Desc : OrderingDirection.Asc; } } }