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()));
        }
示例#2
0
        /// <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);
            }
        }