protected override Expression VisitMember(MemberExpression expression) { // Field hierarchy is flattened (Person.Address.Street is just Street), append as is, do not call Visit. // Property call (string.Length, DateTime.Month, etc). if (MethodVisitor.VisitPropertyCall(expression, this)) { return(expression); } // Special case: grouping if (VisitGroupByMember(expression.Expression)) { return(expression); } var queryable = ExpressionWalker.GetCacheQueryable(expression, false); if (queryable != null) { // Find where the projection comes from. expression = ExpressionWalker.GetProjectedMember(expression.Expression, expression.Member) ?? expression; var fieldName = GetEscapedFieldName(expression, queryable); ResultBuilder.AppendFormat("{0}.{1}", Aliases.GetTableAlias(expression), fieldName); } else { AppendParameter(ExpressionWalker.EvaluateExpression <object>(expression)); } return(expression); }
/// <summary> /// Visists Join clause in case of join with local collection /// </summary> private void VisitJoinWithLocalCollectionClause(JoinClause joinClause) { var type = joinClause.InnerSequence.Type; var itemType = EnumerableHelper.GetIEnumerableItemType(type); var sqlTypeName = SqlTypes.GetSqlTypeName(itemType); if (string.IsNullOrWhiteSpace(sqlTypeName)) { throw new NotSupportedException("Not supported item type for Join with local collection: " + type.Name); } var isOuter = false; var sequenceExpression = joinClause.InnerSequence; object values; var subQuery = sequenceExpression as SubQueryExpression; if (subQuery != null) { isOuter = subQuery.QueryModel.ResultOperators.OfType <DefaultIfEmptyResultOperator>().Any(); sequenceExpression = subQuery.QueryModel.MainFromClause.FromExpression; } switch (sequenceExpression.NodeType) { case ExpressionType.Constant: var constantValueType = ((ConstantExpression)sequenceExpression).Value.GetType(); if (constantValueType.IsGenericType) { isOuter = DefaultIfEmptyEnumeratorType == constantValueType.GetGenericTypeDefinition(); } values = ExpressionWalker.EvaluateEnumerableValues(sequenceExpression); break; case ExpressionType.Parameter: values = ExpressionWalker.EvaluateExpression <object>(sequenceExpression); break; default: throw new NotSupportedException("Expression not supported for Join with local collection: " + sequenceExpression); } var tableAlias = _aliases.GetTableAlias(joinClause); var fieldAlias = _aliases.GetFieldAlias(joinClause.InnerKeySelector); _builder.AppendFormat("{0} join table ({1} {2} = ?) {3} on (", isOuter ? "left outer" : "inner", fieldAlias, sqlTypeName, tableAlias); Parameters.Add(values); }
/// <summary> /// Visits the SQL like expression. /// </summary> private static void VisitSqlLike(MethodCallExpression expression, CacheQueryExpressionVisitor visitor, string likeFormat) { visitor.ResultBuilder.Append("("); visitor.Visit(expression.Object); visitor.ResultBuilder.AppendFormat(" like {0}) ", likeFormat); var arg = expression.Arguments[0] as ConstantExpression; var paramValue = arg != null ? arg.Value : ExpressionWalker.EvaluateExpression <object>(expression.Arguments[0]); visitor.Parameters.Add(paramValue); }
/// <summary> /// Gets values for IN expression. /// </summary> private static IEnumerable <object> GetInValues(Expression fromExpression) { IEnumerable result; switch (fromExpression.NodeType) { case ExpressionType.MemberAccess: var memberExpression = (MemberExpression)fromExpression; result = ExpressionWalker.EvaluateExpression <IEnumerable>(memberExpression); break; case ExpressionType.ListInit: var listInitExpression = (ListInitExpression)fromExpression; result = listInitExpression.Initializers .SelectMany(init => init.Arguments) .Select(ExpressionWalker.EvaluateExpression <object>); break; case ExpressionType.NewArrayInit: var newArrayExpression = (NewArrayExpression)fromExpression; result = newArrayExpression.Expressions .Select(ExpressionWalker.EvaluateExpression <object>); break; case ExpressionType.Parameter: // This should happen only when 'IEnumerable.Contains' is called on parameter of compiled query throw new NotSupportedException("'Contains' clause coming from compiled query parameter is not supported."); default: result = Expression.Lambda(fromExpression).Compile().DynamicInvoke() as IEnumerable; break; } result = result ?? Enumerable.Empty <object>(); return(result .Cast <object>() .ToArray()); }
/// <summary> /// Registers query parameter that is evaluated from a lambda expression argument. /// </summary> public object RegisterEvaluatedParameter(Expression expression) { _modelVisitor.ParameterExpressions.Add(expression); return(ExpressionWalker.EvaluateExpression <object>(expression)); }