private static Expression ChangeSource_VisitMethodCall(MethodCallExpression node, Dictionary <Type, Type> typeMap, Dictionary <string, ParameterExpression> paramters = null) { var theMethod = node; var args = theMethod.Arguments.ToList(); for (int i = 0; i < args.Count; i++) { args[i] = new ArgumentVisitor(paramters ?? ChangeSource_BuildParamters(args[i], typeMap), typeMap).Visit(args[i]); } var genericArguments = theMethod.Method.GetGenericArguments().ToList(); for (int i = 0; i < genericArguments.Count; i++) { if (typeMap.ContainsKey(genericArguments[i])) { genericArguments[i] = typeMap[genericArguments[i]]; } } return(Expression.Call( node.Method.DeclaringType, node.Method.Name, genericArguments.ToArray(), args.ToArray())); }
/// <summary> /// 切换数据源,保留原数据源中的Expression /// </summary> /// <param name="source">原数据源</param> /// <param name="targetSource">目标数据源</param> /// <returns></returns> public static IQueryable ChangeSource(this IQueryable source, IQueryable targetSource) { if (!(source is IQueryable && targetSource is IQueryable)) { throw new Exception("仅支持EF的IQueryable!"); } Dictionary <Type, Type> typeMap = new Dictionary <Type, Type>(); var oldQuery = source.GetObjQuery() as IQueryable; var newQuery = targetSource.GetObjQuery() as IQueryable; typeMap[oldQuery.ElementType] = newQuery.ElementType; var methods = GetMethods(source.Expression); Expression newExpression = newQuery.Expression; Expression oldExpression = oldQuery.Expression; while (true) { if (methods.Count == 0) { break; } var theMethod = methods.Pop(); string methodName = theMethod.Method.Name; if (theMethod.Method.Name == "AsNoTracking") { continue; } var args = theMethod.Arguments.ToList(); args[0] = newExpression; for (int i = 1; i < args.Count; i++) { args[i] = new ArgumentVisitor(ChangeSource_BuildParamters(args[i], typeMap), typeMap).Visit(args[i]); } var genericArguments = theMethod.Method.GetGenericArguments().ToList(); for (int i = 0; i < genericArguments.Count; i++) { if (typeMap.ContainsKey(genericArguments[i])) { genericArguments[i] = typeMap[genericArguments[i]]; } } newExpression = Expression.Call( typeof(Queryable), methodName, genericArguments.ToArray(), args.ToArray()); newQuery = newQuery.Provider.CreateQuery(newExpression); oldExpression = Expression.Call( typeof(Queryable), methodName, theMethod.Method.GetGenericArguments(), theMethod.Arguments.ToArray()); oldQuery = oldQuery.Provider.CreateQuery(oldExpression); typeMap[oldQuery.ElementType] = newQuery.ElementType; } return(targetSource.Provider.CreateQuery(newExpression)); Stack <MethodCallExpression> GetMethods(Expression expression) { Stack <MethodCallExpression> resList = new Stack <MethodCallExpression>(); Expression next = expression; while (true) { if (next is MethodCallExpression methodCall) { resList.Push(methodCall); next = methodCall.Arguments[0]; } else { break; } } return(resList); } }