private object ResolveProjection(ParameterBuilder builder, LambdaExpression lambdaExpression, Type sourceType) { Contract.Requires(lambdaExpression != null); var selectFunction = lambdaExpression.Body as NewExpression; if (selectFunction != null) { var properties = sourceType.GetProperties(); var members = selectFunction.Members .Select(x => properties.FirstOrDefault(y => y.Name == x.Name) ?? x) .Select(x => _memberNameResolver.ResolveName(x)) .ToArray(); var args = selectFunction.Arguments.OfType <MemberExpression>() .Select(x => properties.FirstOrDefault(y => y.Name == x.Member.Name) ?? x.Member) .Select(x => _memberNameResolver.ResolveName(x)) .ToArray(); if (members.Intersect(args).Count() != members.Length) { throw new InvalidOperationException("Projection into new member names is not supported."); } builder.SelectParameter = string.Join(",", args); } var propertyExpression = lambdaExpression.Body as MemberExpression; if (propertyExpression != null) { builder.SelectParameter = string.IsNullOrWhiteSpace(builder.SelectParameter) ? _memberNameResolver.ResolveName(propertyExpression.Member) : builder.SelectParameter + "," + _memberNameResolver.ResolveName(propertyExpression.Member); } return(null); }
public object ProcessMethodCall <T>(MethodCallExpression methodCall, ParameterBuilder builder, Func <ParameterBuilder, IEnumerable <T> > resultLoader, Func <Type, ParameterBuilder, IEnumerable> intermediateResultLoader) { if (methodCall == null) { return(null); } var method = methodCall.Method.Name; switch (method) { case "First": case "FirstOrDefault": builder.TakeParameter = "1"; return(methodCall.Arguments.Count >= 2 ? GetMethodResult(methodCall, builder, resultLoader, intermediateResultLoader) : GetResult(methodCall, builder, resultLoader, intermediateResultLoader)); case "Single": case "SingleOrDefault": case "Last": case "LastOrDefault": case "Count": case "LongCount": return(methodCall.Arguments.Count >= 2 ? GetMethodResult(methodCall, builder, resultLoader, intermediateResultLoader) : GetResult(methodCall, builder, resultLoader, intermediateResultLoader)); case "Where": Contract.Assume(methodCall.Arguments.Count >= 2); { var result = ProcessMethodCall(methodCall.Arguments[0] as MethodCallExpression, builder, resultLoader, intermediateResultLoader); if (result != null) { return(InvokeEager(methodCall, result)); } var newFilter = _writer.Write(methodCall.Arguments[1], builder.SourceType); builder.FilterParameter = string.IsNullOrWhiteSpace(builder.FilterParameter) ? newFilter : string.Format("({0}) and ({1})", builder.FilterParameter, newFilter); } break; case "Select": Contract.Assume(methodCall.Arguments.Count >= 2); { var result = ProcessMethodCall(methodCall.Arguments[0] as MethodCallExpression, builder, resultLoader, intermediateResultLoader); if (result != null) { return(InvokeEager(methodCall, result)); } if (!string.IsNullOrWhiteSpace(builder.SelectParameter)) { return(ExecuteMethod(methodCall, builder, resultLoader, intermediateResultLoader)); } var unaryExpression = methodCall.Arguments[1] as UnaryExpression; if (unaryExpression != null) { var lambdaExpression = unaryExpression.Operand as LambdaExpression; if (lambdaExpression != null) { var sourceType = builder.SourceType; return(ResolveProjection(builder, lambdaExpression, sourceType)); } } } break; case "OrderBy": case "ThenBy": Contract.Assume(methodCall.Arguments.Count >= 2); { var methodCallExpression = methodCall.Arguments[0] as MethodCallExpression; var result = ProcessMethodCall(methodCallExpression, builder, resultLoader, intermediateResultLoader); if (result != null) { return(InvokeEager(methodCall, result)); } var sourceType = builder.SourceType; var sortProperty = methodCall.Arguments[1]; var item = _writer.Write(sortProperty, sourceType); builder.OrderByParameter.Add(item); } break; case "OrderByDescending": case "ThenByDescending": Contract.Assume(methodCall.Arguments.Count >= 2); { var result = ProcessMethodCall(methodCall.Arguments[0] as MethodCallExpression, builder, resultLoader, intermediateResultLoader); if (result != null) { return(InvokeEager(methodCall, result)); } var visit = _writer.Write(methodCall.Arguments[1], builder.SourceType); builder.OrderByParameter.Add(visit + " desc"); } break; case "Take": Contract.Assume(methodCall.Arguments.Count >= 2); { var result = ProcessMethodCall(methodCall.Arguments[0] as MethodCallExpression, builder, resultLoader, intermediateResultLoader); if (result != null) { return(InvokeEager(methodCall, result)); } builder.TakeParameter = _writer.Write(methodCall.Arguments[1], builder.SourceType); } break; case "Skip": Contract.Assume(methodCall.Arguments.Count >= 2); { var result = ProcessMethodCall(methodCall.Arguments[0] as MethodCallExpression, builder, resultLoader, intermediateResultLoader); if (result != null) { return(InvokeEager(methodCall, result)); } builder.SkipParameter = _writer.Write(methodCall.Arguments[1], builder.SourceType); } break; case "Expand": Contract.Assume(methodCall.Arguments.Count >= 2); { var result = ProcessMethodCall(methodCall.Arguments[0] as MethodCallExpression, builder, resultLoader, intermediateResultLoader); if (result != null) { return(InvokeEager(methodCall, result)); } var expression = methodCall.Arguments[1]; Contract.Assume(expression != null); var objectMember = Expression.Convert(expression, typeof(object)); var getterLambda = Expression.Lambda <Func <object> >(objectMember).Compile(); builder.ExpandParameter = getterLambda().ToString(); } break; default: return(ExecuteMethod(methodCall, builder, resultLoader, intermediateResultLoader)); } return(null); }
protected abstract IEnumerable GetIntermediateResults(Type type, ParameterBuilder builder);
protected override IEnumerable GetIntermediateResults(Type type, ParameterBuilder builder) { CustomContract.Requires(builder != null); throw new NotImplementedException(); }
protected abstract IEnumerable <T> GetResults(ParameterBuilder builder);