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()); }
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)); }