/// <summary> /// 获取成员名称 /// </summary> private static string GetMemberName(MemberExpression memberExpression) { if (memberExpression == null) return string.Empty; string result = memberExpression.ToString(); return result.Substring(result.IndexOf(".") + 1); }
protected override Expression VisitMemberAccess(MemberExpression m) { var result = m.ToString(); return Expression.Constant(result.Substring(result.IndexOf('.') + 1)); }
internal override Expression VisitMemberAccess(MemberExpression m) { PropertyInfo info; Expression expression; Type type = m.Expression.Type; this.leafExpressionIsMemberAccess = true; if (PrimitiveType.IsKnownNullableType(type)) { this.leafExpressionIsMemberAccess = false; return base.VisitMemberAccess(m); } if (ProjectionAnalyzer.IsCollectionProducingExpression(m.Expression)) { throw new NotSupportedException(System.Data.Services.Client.Strings.ALinq_ExpressionNotSupportedInProjection(this.type, m.ToString())); } if (!ResourceBinder.PatternRules.MatchNonPrivateReadableProperty(m, out info, out expression)) { throw new NotSupportedException(System.Data.Services.Client.Strings.ALinq_ExpressionNotSupportedInProjection(this.type, m.ToString())); } Expression expression2 = base.VisitMemberAccess(m); if (ClientTypeUtil.TypeOrElementTypeIsEntity(type)) { Type type2; ResourceBinder.StripTo<Expression>(m.Expression, out type2); this.box.AppendPropertyToPath(info, type2, this.context); this.leafExpressionIsMemberAccess = false; } return expression2; }
/// <summary> /// Visits member access. /// </summary> /// <param name="m">The expression.</param> /// <returns></returns> /// <exception cref="NotSupportedException"> /// </exception> protected override Expression VisitMemberAccess(MemberExpression m) { //if(m.Expression.NodeType == ExpressionType.MemberAccess) //{ // VisitMemberAccess((MemberExpression)m.Expression); //} if (m.Expression != null && m.Expression.NodeType == ExpressionType.Parameter) { var alias = MongoConfiguration.GetPropertyAlias(m.Expression.Type, m.Member.Name); var id = TypeHelper.GetHelperForType(m.Expression.Type).FindIdProperty(); if (id != null && id.Name == alias) { alias = "_id"; } if (UseScopedQualifier) { _sb.Append("this."); } _sb.Append(alias); _lastFlyProperty = alias; return m; } if (m.Member.DeclaringType == typeof(string)) { switch (m.Member.Name) { case "Length": _sb.Append("LEN("); Visit(m.Expression); _sb.Append(")"); return m; } } else if (m.Member.DeclaringType == typeof(DateTime) || m.Member.DeclaringType == typeof(DateTimeOffset)) { #region DateTime Magic var fullName = m.ToString().Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); // this is complex IsComplex = true; // this is a DateProperty hanging off the property - clip the last 2 elements var fixedName = fullName.Skip(1).Take(fullName.Length - 2).ToArray(); var propName = string.Join(".", fixedName); // now we get to do some tricky fun with javascript switch (m.Member.Name) { case "Day": Visit(m.Expression); _sb.Append(".getDate()"); return m; case "Month": Visit(m.Expression); _sb.Append(".getMonth()"); return m; case "Year": Visit(m.Expression); _sb.Append(".getFullYear()"); return m; case "Hour": Visit(m.Expression); _sb.Append(".getHours()"); return m; case "Minute": Visit(m.Expression); _sb.Append(".getMinutes()"); return m; case "Second": Visit(m.Expression); _sb.Append(".getSeconds()"); return m; case "DayOfWeek": Visit(m.Expression); _sb.Append(".getDay()"); return m; } #endregion } else { var fullName = m.ToString().Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); // this supports the "deep graph" name - "Product.Address.City" var fixedName = fullName.Skip(1).Take(fullName.Length - 1).ToArray(); String result = ""; if (m.Expression.NodeType == ExpressionType.Constant) { var constant = m.Expression as ConstantExpression; var fi = (FieldInfo)m.Member; var val = fi.GetValue(constant.Value); if (val is String) { result = String.Format("\"{0}\"", val); } else { result = val.ToString(); } SetFlyValue(val); } else { var expressionRootType = GetParameterExpression((MemberExpression)m.Expression); if (expressionRootType != null) { fixedName = GetDeepAlias(expressionRootType.Type, fixedName); } result = string.Join(".", fixedName); //sb.Append("this." + result); if (UseScopedQualifier) { _sb.Append("this."); } } _sb.Append(result); _lastFlyProperty = result; return m; } // if this is a property NOT on the object... throw new NotSupportedException(string.Format("The member '{0}' is not supported", m.Member.Name)); }
private string TranslateOneToMany(string functionName, MemberExpression memberExpression, LambdaExpression fieldExpression, LambdaExpression filterExpression) { if (!string.IsNullOrEmpty(TranslateMember(memberExpression))) // this shouldn't return any SQL throw new SqlExpressionTranslatorException(memberExpression.ToString()); var relation = GetRelation(memberExpression.Expression, memberExpression.Member.Name); if (relation == null) throw new SqlExpressionTranslatorException(memberExpression.ToString()); if (fieldExpression != null && filterExpression != null && fieldExpression.Parameters[0] != filterExpression.Parameters[0]) throw new SqlExpressionTranslatorException(null); var iterator = fieldExpression != null ? fieldExpression.Parameters[0] : filterExpression != null ? filterExpression.Parameters[0] : Expression.Parameter(relation.ElementType); LambdaExpression relationExpression = CreateToManyFilterExpression(relation, memberExpression.Expression, filterExpression, iterator); var template = _toManyTemplates[functionName]; if (template == null) throw new NotSupportedException(functionName); var alias = SqlNameGenerator.NextTableAlias(); _metaData[iterator] = new ExpressionMetaData { Iterator = iterator, Relation = relation, Schema = relation.ForeignSchema }; _relationAliases[iterator] = new Dictionary<object, string> { { relation, alias } }; _subQueries.Push(new SubQuery()); string sqlFields = Translate(fieldExpression); string sqlWhere = Translate(relationExpression); string sqlJoins = (Joins.Count > 0) ? string.Join(" ", Joins.Select(join => join.ToSql(_sqlDialect))) : null; _subQueries.Pop(); return string.Format(template, sqlFields, _sqlDialect.QuoteTable(relation.ForeignSchema.MappedName) + " " + alias, sqlJoins ?? "", sqlWhere ); }
private static bool MemberExpressionsEqual(MemberExpression x, MemberExpression y, LambdaExpression rootX, LambdaExpression rootY) { // Special case for static field and static property if (x.Expression == null) { return Equals(x.Member, y.Member); } if (x.Expression.NodeType != y.Expression.NodeType) return false; switch (x.Expression.NodeType) { case ExpressionType.Constant: var constx = GetValueOfConstantExpression(x); var consty = GetValueOfConstantExpression(y); return Equals(constx, consty); case ExpressionType.Parameter: case ExpressionType.MemberAccess: return Equals(x.Member, y.Member) && ExpressionEqual(x.Expression, y.Expression, rootX, rootY); case ExpressionType.New: case ExpressionType.Call: return ExpressionEqual(x.Expression, y.Expression, rootX, rootY); default: throw new NotImplementedException(x.ToString()); } }
/// <summary> /// Visits a member access expression in non-entity projections, validating that /// it's correct and recording the path visit to include in a projection if necessary. /// </summary> /// <param name="m">Expression to visit.</param> /// <returns>The same expression.</returns> /// <remarks> /// The projection analyzer runs after funcletization, so a member expression /// rather than a constant expression implies that this is correlated to /// a parameter, by dotting through the argument in valid cases, and possibly /// more complex cases in others like new DSC(p.Orders)*.Foo* <- .Foo is invalid. /// </remarks> internal override Expression VisitMemberAccess(MemberExpression m) { Debug.Assert(m != null, "m != null"); // if primitive or nullable primitive, allow member access... i.e. calling Value on nullable<int> if (ClientConvert.IsKnownNullableType(m.Expression.Type)) { return base.VisitMemberAccess(m); } // Only allowed to project entities if (!ClientType.CheckElementTypeIsEntity(m.Expression.Type) || IsCollectionProducingExpression(m.Expression)) { throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjection(this.type, m.ToString())); } PropertyInfo pi = null; if (ResourceBinder.PatternRules.MatchNonPrivateReadableProperty(m, out pi)) { Expression e = base.VisitMemberAccess(m); box.AppendToPath(pi); return e; } throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjection(this.type, m.ToString())); }
private BsonValue TranslateMemberAccess(MemberExpression node) { BsonValue result; if (node.Expression.Type == typeof(DateTime) && TryTranslateDateTimeMemberAccess(node, out result)) { return result; } if (node.Expression != null && (node.Expression.Type.ImplementsInterface(typeof(ICollection<>)) || node.Expression.Type.ImplementsInterface(typeof(ICollection))) && node.Member.Name == "Count") { return new BsonDocument("$size", TranslateValue(node.Expression)); } var message = string.Format("Member {0} of type {1} in the expression tree {2} cannot be translated.", node.Member.Name, node.Member.DeclaringType, node.ToString()); throw new NotSupportedException(message); }
// // Listing 12-38 (continue) // /// <summary> /// We support only TotalMinutes and TotalHours comparison /// </summary> private void TranslateTimeSpanComparison( ExpressionType nodeType, ConstantExpression constant, MemberExpression memberAccess) { MemberExpression parent = memberAccess.Expression as MemberExpression; if (parent.Member.ReflectedType != typeof(ImageInformation)) { throw new NotSupportedException( string.Format( "Member {0} is not of type Images", memberAccess.ToString())); } // We support only TotalMinutes for this simple provider if ((memberAccess.Member.Name == "TotalMinutes") && (parent.Member.Name == "TimeToArrival")) { SetIntParameter( (int)GetDoubleConstant(constant), ref queryParameters.Filter.MaxDaysTaken, ref queryParameters.Filter.MaxDaysTaken, nodeType); } else { throw new NotSupportedException( string.Format( "Query on {0} expression is not supported", memberAccess.ToString())); } }
/// <summary> /// The standard case supports an equal condition for strings /// and other comparisons for GroundSpeed and Altitude integers /// </summary> private void TranslateStandardComparisons( ExpressionType nodeType, ConstantExpression constant, MemberExpression memberAccess) { string stringFieldName = (from field in typeof(ImageInformation).GetProperties() where Type.GetTypeCode(field.PropertyType) == TypeCode.String && field.Name == memberAccess.Member.Name select field.Name).FirstOrDefault(); // Loop for all strings if (stringFieldName != null) { if (nodeType != ExpressionType.Equal) { throw new NotSupportedException( string.Format( "The binary operator '{0}' is not supported on {1} member", nodeType, memberAccess.Member.Name)); } queryParameters.Filter.GetType() .GetField(stringFieldName) .SetValue(queryParameters.Filter, constant.Value); } else { // String not found switch (memberAccess.Member.Name) { case "DateTaken": //SetDateTimeParameter( // constant.Value.ToString(), // ref queryParameters.Filter.MinDateTaken, // ref queryParameters.Filter.MaxDateTaken, // nodeType); //break; default: throw new NotSupportedException( string.Format("Condition on member {0} is not supported", memberAccess.ToString())); } } }
/// <summary> /// Process member references. /// </summary> /// <param name="expression"> /// The expression to visit. /// </param> /// <returns> /// The visited expression. /// </returns> private Expression VisitMemberAccess(MemberExpression expression) { // Lookup the Mobile Services name of the member and use that string memberName = GetTableMemberName(expression, this.contractResolver); if (memberName != null) { this.filterExpression.Push(new MemberAccessNode(null, memberName)); return expression; } // Check if this member is actually a function that looks like a // property (like string.Length, etc.) string methodName = null; MemberInfoKey memberInfoKey = new MemberInfoKey(expression.Member); if (InstanceProperties.TryGetValue(memberInfoKey, out methodName)) { var fnCallNode = new FunctionCallNode(methodName, null); this.filterExpression.Push(fnCallNode); this.Visit(expression.Expression); this.SetChildren(fnCallNode); return expression; } // Otherwise we can't process the member. throw new NotSupportedException( string.Format( CultureInfo.InvariantCulture, "The member '{0}' is not supported in the 'Where' Mobile Services query expression '{1}'.", expression != null && expression.Member != null ? expression.Member.Name : null, expression != null ? expression.ToString() : null)); }
private string TranslateMember(MemberExpression node) { if (node.Expression.Type == typeof(string) && node.Member.Name == "Length") { string fnName = _sqlDialect.SqlFunction(SqlDialect.Function.StringLength, Translate(node.Expression)); if (fnName != null) return fnName; } if (Translate(node.Expression) != null) throw new SqlExpressionTranslatorException(node.ToString()); string sql = ProcessRelation(node, node.Expression, node.Member.Name); if (sql != null) { if (node.Type == typeof (bool)) { return TranslateTrue(_sqlDialect.QuoteField(sql)); } else return _sqlDialect.QuoteField(sql); } return null; }
/// <summary> /// Visits member access. /// </summary> /// <param name="m">The expression.</param> /// <returns></returns> /// <exception cref="NotSupportedException"> /// </exception> protected override Expression VisitMemberAccess(MemberExpression m) { if (m.Expression != null && m.Expression.NodeType == ExpressionType.Parameter) { var alias = MongoConfiguration.GetPropertyAlias(m.Expression.Type, m.Member.Name); var id = TypeHelper.GetHelperForType(m.Expression.Type).FindIdProperty(); if (id != null && id.Name == alias) { alias = "_id"; } if (UseScopedQualifier) { _sbWhere.Append("this."); } _sbWhere.Append(alias); _lastFlyProperty = alias; return m; } if (m.Member.DeclaringType == typeof(string)) { switch (m.Member.Name) { case "Length": IsComplex = true; Visit(m.Expression); _sbWhere.Append(".length"); return m; } } else if (m.Member.DeclaringType == typeof(DateTime) || m.Member.DeclaringType == typeof(DateTimeOffset)) { #region DateTime Magic // this is complex IsComplex = true; // now we get to do some tricky fun with javascript switch (m.Member.Name) { case "Day": Visit(m.Expression); _sbWhere.Append(".getDate()"); return m; case "Month": Visit(m.Expression); _sbWhere.Append(".getMonth()"); return m; case "Year": Visit(m.Expression); _sbWhere.Append(".getFullYear()"); return m; case "Hour": Visit(m.Expression); _sbWhere.Append(".getHours()"); return m; case "Minute": Visit(m.Expression); _sbWhere.Append(".getMinutes()"); return m; case "Second": Visit(m.Expression); _sbWhere.Append(".getSeconds()"); return m; case "DayOfWeek": Visit(m.Expression); _sbWhere.Append(".getDay()"); return m; } #endregion } else { // this supports the "deep graph" name - "Product.Address.City" var fullName = m.ToString().Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); var fixedName = fullName .Skip(1) .Where(x => x != "First()") .Select(x => Regex.Replace(x, @"\[[0-9]+\]$", "")) .ToArray(); var expressionRootType = GetParameterExpression(m.Expression); if (expressionRootType != null) { fixedName = GetDeepAlias(expressionRootType.Type, fixedName); } if (UseScopedQualifier) { _sbWhere.Append("this."); } string result = string.Join(".", fixedName); _sbWhere.Append(result); _lastFlyProperty = result; return m; } // if this is a property NOT on the object... throw new NotSupportedException(string.Format("The member '{0}' is not supported", m.Member.Name)); }
private string VisitDeepAlias(MemberExpression m) { var fullName = m.ToString().Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); var fixedName = fullName .Skip(1) .Select(x => Regex.Replace(x, @"^get_Item\(([0-9]+)\)$", "$1|Ind")) .Select(x => Regex.Replace(x, @"\[([0-9]+)\]$", "$1|Ind")) .Select(x => x.Replace("First()", "0|Ind")) .ToArray(); if (!_isDeepGraphWithArrays) _isDeepGraphWithArrays = fullName.Length - fixedName.Length != 1; var expressionRootType = GetParameterExpression(m.Expression); if (expressionRootType != null) { fixedName = GetDeepAlias(expressionRootType.Type, fixedName); } string result = string.Join(".", fixedName.Select(x => x.Replace("|Ind", "")).ToArray()); return result; }
internal override Expression VisitMemberAccess(MemberExpression m) { Debug.Assert(m != null, "m != null"); if (!ClientType.CheckElementTypeIsEntity(m.Expression.Type) || IsCollectionProducingExpression(m.Expression)) { throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjectionToEntity(this.type, m.ToString())); } PropertyInfo pi = null; if (ResourceBinder.PatternRules.MatchNonPrivateReadableProperty(m, out pi)) { Expression e = base.VisitMemberAccess(m); box.AppendToPath(pi); return e; } throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjectionToEntity(this.type, m.ToString())); }
internal override Expression VisitMemberAccess(MemberExpression m) { Debug.Assert(m != null, "m != null"); if (ClientConvert.IsKnownNullableType(m.Expression.Type)) { return base.VisitMemberAccess(m); } if (!CommonUtil.IsClientType(m.Expression.Type)) { throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, SR.ALinqExpressionNotSupportedInProjection, this.type, m.ToString())); } PropertyInfo pi = null; if (ResourceBinder.PatternRules.MatchNonPrivateReadableProperty(m, out pi)) { Expression e = base.VisitMemberAccess(m); this.box.AppendToPath(pi); return e; } throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, SR.ALinqExpressionNotSupportedInProjection, this.type, m.ToString())); }
private string MemberExprToSql(MemberExpression memberExpr, bool isCondition) { if (groupKeySql != null && memberExpr.Member.DeclaringType.IsGenericType && memberExpr.Member.Name == "Key" && memberExpr.Member.DeclaringType.GetGenericTypeDefinition() == typeof(IGroup<,>)) return groupKeySql; if (memberExpr.Member.DeclaringType == typeof(TimeSpan)) return TimeStampPropToSql(memberExpr); var constExpr = memberExpr.Expression as ConstantExpression; if (constExpr != null) return ClosureMemberToSql(constExpr.Value, memberExpr.Member); var target = memberExpr.Expression != null ? ExpressionToSql(memberExpr.Expression, false) : null; var standard = MemberAccessToSql(memberExpr.Member, target); if (standard != null) return standard; var paramExpr = memberExpr.Expression as ParameterExpression; if (paramExpr != null) { var suffix = isCondition && memberExpr.Type == typeof(bool) ? " = 1" : ""; return string.Format("{0}.[{1}]{2}", ParamExprToSql(paramExpr), nameResolver.ResolveColumnName(memberExpr.Member), suffix); } var innerMemberExpr = memberExpr.Expression as MemberExpression; if (innerMemberExpr != null) return InnerMemberExprToSql(innerMemberExpr, memberExpr.Member); throw new NotSupportedException(string.Format("Can not translate expression: {0}.", memberExpr.ToString())); }
/// <summary> /// Process member references. /// </summary> /// <param name="expression"> /// The expression to visit. /// </param> /// <returns> /// The visited expression. /// </returns> private Expression VisitMemberAccess(MemberExpression expression) { // Lookup the Mobile Services name of the member and use that string memberName = GetTableMemberName(expression, this.contractResolver); if (memberName != null) { this.filter.Append(memberName); return expression; } // Check if this member is actually a function that looks like a // property (like string.Length, etc.) string methodName = null; MemberInfoKey memberInfoKey = new MemberInfoKey(expression.Member); if (InstanceProperties.TryGetValue(memberInfoKey, out methodName)) { this.filter.Append(methodName); this.filter.Append("("); this.Visit(expression.Expression); this.filter.Append(")"); return expression; } // Otherwise we can't process the member. throw new NotSupportedException( string.Format( CultureInfo.InvariantCulture, Resources.FilterBuildingExpressionVisitor_MemberUnsupported, expression != null && expression.Member != null ? expression.Member.Name : null, expression != null ? expression.ToString() : null)); }
private string GetCode(MemberExpression memberExpression) { return memberExpression.ToString(); }
/// <summary> /// Visits member access. /// </summary> /// <param name="m">The expression.</param> /// <returns></returns> /// <exception cref="NotSupportedException"> /// </exception> protected override Expression VisitMemberAccess(MemberExpression m) { var fullName = m.ToString().Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); if (m.Expression != null && m.Expression.NodeType == ExpressionType.Parameter) { var alias = MongoConfiguration.GetPropertyAlias(m.Expression.Type, m.Member.Name); sb.Append("this." + alias); // m.Member.Name); lastFlyProperty = alias; // m.Member.Name; return m; } if (m.Member.DeclaringType == typeof(string)) { switch (m.Member.Name) { case "Length": sb.Append("LEN("); Visit(m.Expression); sb.Append(")"); return m; } } else if (m.Member.DeclaringType == typeof(DateTime) || m.Member.DeclaringType == typeof(DateTimeOffset)) { // this is complex IsComplex = true; // this is a DateProperty hanging off the property - clip the last 2 elements var fixedName = fullName.Skip(1).Take(fullName.Length - 2).ToArray(); var propName = string.Join(".", fixedName); // now we get to do some tricky fun with javascript switch (m.Member.Name) { case "Day": Visit(m.Expression); sb.Append(".getDate()"); return m; case "Month": Visit(m.Expression); sb.Append(".getMonth()"); return m; case "Year": Visit(m.Expression); sb.Append(".getFullYear()"); return m; case "Hour": Visit(m.Expression); sb.Append(".getHours()"); return m; case "Minute": Visit(m.Expression); sb.Append(".getMinutes()"); return m; case "Second": Visit(m.Expression); sb.Append(".getSeconds()"); return m; case "DayOfWeek": Visit(m.Expression); sb.Append(".getDay()"); return m; } } else { // this supports the "deep graph" name - "Product.Address.City" var fixedName = fullName.Skip(1).Take(fullName.Length - 1).ToArray(); var expressionRootType = GetParameterExpression((MemberExpression)m.Expression); if (expressionRootType != null) { fixedName = GetDeepAlias(expressionRootType.Type, fixedName); } var result = string.Join(".", fixedName); sb.Append("this." + result); lastFlyProperty = result; return m; } // if this is a property NOT on the object... throw new NotSupportedException(string.Format("The member '{0}' is not supported", m.Member.Name)); }
internal override Expression VisitMemberAccess(MemberExpression m) { Debug.Assert(m != null, "m != null"); this.leafExpressionIsMemberAccess = true; // Only allowed to project entities if (!ClientTypeUtil.TypeOrElementTypeIsEntity(m.Expression.Type) || IsCollectionProducingExpression(m.Expression)) { throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjectionToEntity(this.type, m.ToString())); } PropertyInfo pi; Expression boundTarget; if (ResourceBinder.PatternRules.MatchNonPrivateReadableProperty(m, out pi, out boundTarget)) { Expression e = base.VisitMemberAccess(m); Type convertedType; ResourceBinder.StripTo<Expression>(m.Expression, out convertedType); this.builder.AppendPropertyToPath(pi, convertedType, this.context); this.leafExpressionIsMemberAccess = false; return e; } throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjectionToEntity(this.type, m.ToString())); }
private string TranslateMember(MemberExpression node) { if (node.Expression.Type == typeof(string) && node.Member.Name == "Length") { string fnName = _sqlDialect.SqlFunction(SqlDialect.Function.StringLength, Translate(node.Expression)); if (fnName != null) return fnName; } if (Translate(node.Expression) != null) throw new SqlExpressionTranslatorException(node.ToString()); var memberName = node.Member.Name; var field = _schema.FieldsByFieldName[memberName]; if (field != null && !String.IsNullOrEmpty(field.MappedName)) { memberName = field.MappedName; } string sql = ProcessRelation(node, node.Expression, memberName); if (sql != null) { if (node.Type == typeof (bool)) { return TranslateTrue(_sqlDialect.QuoteField(sql)); } else return _sqlDialect.QuoteField(sql); } return null; }
/// <summary> /// Visits a member access expression in non-entity projections, validating that /// it's correct and recording the path visit to include in a projection if necessary. /// </summary> /// <param name="m">Expression to visit.</param> /// <returns>The same expression.</returns> /// <remarks> /// The projection analyzer runs after funcletization, so a member expression /// rather than a constant expression implies that this is correlated to /// a parameter, by dotting through the argument in valid cases, and possibly /// more complex cases in others like new DSC(p.Orders)*.Var1* <- .Var1 is invalid. /// </remarks> internal override Expression VisitMemberAccess(MemberExpression m) { Debug.Assert(m != null, "m != null"); Type expressionType = m.Expression.Type; this.leafExpressionIsMemberAccess = true; // if primitive or nullable primitive, allow member access... i.e. calling Value on nullable<int> if (PrimitiveType.IsKnownNullableType(expressionType)) { this.leafExpressionIsMemberAccess = false; return base.VisitMemberAccess(m); } // Only allowed to project entities, also it is ok to do client side projections on complex types. // Details on the fix for "Inconsistency between Count() method call and Count property projection on clr type collections": // Relax check to only throw if IsCollectionProducingExpression returns true. // This enables client side projections (for example "Count") on Clr type collections, like ReadOnlyCollection (which is used in spatial types), ICollection, IList, etc. // We already allow client side method calls (like Linq extension method "Count()") on clr type collections, so it makes client side projections consistent. // Note: it will still throw for List<T> (because IsCollectionProducingExpression returns true for List<T>), // however this is consistent with how we handle MethodCallExpression on clr type collections // and changing IsCollectionProducingExpression seems risky at this point as it's used in a lot of places. if (IsCollectionProducingExpression(m.Expression)) { throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjection(this.type, m.ToString())); } PropertyInfo pi; Expression boundTarget; if (ResourceBinder.PatternRules.MatchNonPrivateReadableProperty(m, out pi, out boundTarget)) { Expression e = base.VisitMemberAccess(m); if (ClientTypeUtil.TypeOrElementTypeIsEntity(expressionType)) { Type convertedType; ResourceBinder.StripTo<Expression>(m.Expression, out convertedType); this.builder.AppendPropertyToPath(pi, convertedType, this.context); this.leafExpressionIsMemberAccess = false; } return e; } throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjection(this.type, m.ToString())); }
/// <summary> /// Process member references. /// </summary> /// <param name="expression">The expression to visit.</param> /// <returns>The visited expression.</returns> protected override Expression VisitMember(MemberExpression expression) { // Lookup the Mobile Services name of the member and use that SerializableMember member = GetTableMember(expression); if (member != null) { this.filter.Append(member.Name); this.MarkVisited(); return expression; } // Check if this member is actually a function that looks like a // property (like string.Length, etc.) string methodName = null; if (instanceProperties.TryGetValue(expression.Member, out methodName)) { this.filter.Append(methodName); this.filter.Append("("); this.Visit(expression.Expression); this.filter.Append(")"); this.MarkVisited(); return expression; } // Otherwise we can't process the member. throw new NotSupportedException( string.Format( CultureInfo.InvariantCulture, Resources.FilterBuildingExpressionVisitor_VisitMember_Unsupported, expression != null && expression.Member != null ? expression.Member.Name : null, expression != null ? expression.ToString() : null)); }
private string GetMemberNameFromMemberAccess(MemberExpression memberExpression, ParameterExpression[] parameters) { if (memberExpression == null) { throw new NotSupportedException(); } var expressionName = memberExpression.ToString(); var subStrings = expressionName.Split('.'); var isDeepParameter = false; if (subStrings.Length > 0 && parameters != null && parameters.Length > 0) { isDeepParameter = parameters[0].ToString() == subStrings[0]; } if (memberExpression.NodeType == ExpressionType.MemberAccess && isDeepParameter) { var name = FindDeepParameter(memberExpression); if (name.ToLower() == "id") { name = "_id"; } return name; } throw new NotSupportedException(string.Format("Cannot OrderBy {0}", memberExpression.NodeType)); }