예제 #1
0
        private static Func <TFrom, TTo> CreateConversion <TFrom, TTo>(
            IKeyInfo <TFrom> fromKeyInfo,
            IKeyInfo <TTo> toKeyInfo,
            int[] mapping)
        {
            IKeyInfoHelper from = GetKeyInfoHelper(fromKeyInfo);
            IKeyInfoHelper to   = GetKeyInfoHelper(toKeyInfo);

            ParameterExpression keyParam = Expression.Parameter(fromKeyInfo.KeyType);

            Expression body =
                KeyExpressionHelper.CreateKeyConversionExpression(
                    keyParam,
                    toKeyInfo.EntityKeyMembers,
                    mapping,
                    from,
                    to);

            return(Expression.Lambda <Func <TFrom, TTo> >(body, keyParam).Compile());
        }
예제 #2
0
        protected override Expression VisitMethodCall(MethodCallExpression node)
        {
            if (!node.Method.IsGenericMethod ||
                node.Method.GetGenericMethodDefinition() != this.Original)
            {
                // Not GroupJoin
                return(base.VisitMethodCall(node));
            }

            ConstantExpression secondExpression = node.Arguments[1] as ConstantExpression;

            if (secondExpression == null)
            {
                // Not constant expression
                return(base.VisitMethodCall(node));
            }

            ITable table = secondExpression.Value as ITable;

            if (table == null)
            {
                // Not table
                return(base.VisitMethodCall(node));
            }

            LambdaExpression secondKeySelector =
                ExpressionHelper.SkipQuoteNode(node.Arguments[3]) as LambdaExpression;

            Type           keyType = secondKeySelector.Body.Type;
            IKeyInfoHelper helper  = this.GetKeyInfoHelper(keyType);

            if (helper == null)
            {
                // Cannot detect key type
                return(base.VisitMethodCall(node));
            }

            // Try to parse expression
            MemberInfo[] keyMembers;

            if (!helper.TryParseKeySelectorExpression(
                    secondKeySelector.Body,
                    false,
                    out keyMembers))
            {
                // Cannot parse key
                return(base.VisitMethodCall(node));
            }

            IIndex matchedIndex = null;

            int[] mapping = null;

            foreach (IIndex index in table.Indexes)
            {
                if (KeyExpressionHelper.TryGetMemberMapping(
                        index.KeyInfo.EntityKeyMembers,
                        keyMembers,
                        out mapping))
                {
                    matchedIndex = index;
                    break;
                }
            }

            if (matchedIndex == null)
            {
                // No matched index was found
                return(base.VisitMethodCall(node));
            }

            var indexServices = GetKeyInfoHelper(matchedIndex.KeyInfo);

            if (indexServices == null)
            {
                return(base.VisitMethodCall(node));
            }

            // Create key converter
            ParameterExpression keyConverterParam = Expression.Parameter(keyType, "x");

            LambdaExpression keyConverter =
                Expression.Lambda(
                    KeyExpressionHelper.CreateKeyConversionExpression(keyConverterParam, matchedIndex.KeyInfo.EntityKeyMembers, mapping, helper, indexServices),
                    keyConverterParam);

            // Create key emptyness detector
            ParameterExpression keyEmptinessDetectorParam = Expression.Parameter(keyType, "x");

            LambdaExpression keyEmptinessDetector =
                Expression.Lambda(
                    KeyExpressionHelper.CreateKeyEmptinessDetector(
                        keyEmptinessDetectorParam,
                        helper),
                    keyEmptinessDetectorParam);

            Type[] generics = node.Method.GetGenericArguments();

            // GroupJoinIndexed call
            MethodInfo indexedMethod = this.Indexed
                                       .MakeGenericMethod(
                generics[0],
                generics[1],
                generics[2],
                matchedIndex.KeyInfo.KeyType,
                generics[3]);

            Expression indexedCall =
                Expression.Call(
                    node.Object,
                    indexedMethod,
                    this.Visit(node.Arguments[0]),
                    Expression.Constant(matchedIndex),
                    ExpressionHelper.SkipQuoteNode(node.Arguments[2]),
                    keyEmptinessDetector,
                    keyConverter,
                    ExpressionHelper.SkipQuoteNode(node.Arguments[4]));

            Type elementType = ReflectionHelper.GetElementType(indexedCall.Type);

            // AsQueryable call
            return(Expression.Call(
                       null,
                       QueryMethods.AsQueryable.MakeGenericMethod(elementType),
                       indexedCall));
        }