private static MethodCallExpression GetJoin(Expression outerSource, Expression innerSource, IEdmNavigationProperty navigationProperty) { Type innerType = OeExpressionHelper.GetCollectionItemType(innerSource.Type); var joinBuilder = new OeJoinBuilder(new OeQueryNodeVisitor(Expression.Parameter(typeof(Object)))); (LambdaExpression outerKeySelector, LambdaExpression innerKeySelector) = joinBuilder.GetJoinKeySelector(outerSource.Type, innerType, Array.Empty <IEdmNavigationProperty>(), navigationProperty); var replaceParameterVisitor = new ReplaceParameterVisitor(outerSource, outerKeySelector.Parameters[0]); Expression outerKeyExpression = replaceParameterVisitor.Visit(outerKeySelector.Body); IReadOnlyList <MemberExpression> outerKeyProperties; IReadOnlyList <MemberExpression> innerKeyProperties; if (OeExpressionHelper.IsTupleType(outerKeySelector.ReturnType)) { outerKeyProperties = OeExpressionHelper.GetPropertyExpressions(outerKeyExpression); innerKeyProperties = OeExpressionHelper.GetPropertyExpressions(innerKeySelector.Body); } else { outerKeyProperties = new MemberExpression[] { (MemberExpression)outerKeyExpression }; innerKeyProperties = new MemberExpression[] { (MemberExpression)innerKeySelector.Body }; } BinaryExpression?joinExpression = null; for (int i = 0; i < outerKeyProperties.Count; i++) { if (joinExpression == null) { joinExpression = Expression.MakeBinary(ExpressionType.Equal, outerKeyProperties[i], innerKeyProperties[i]); } else { BinaryExpression equal = Expression.MakeBinary(ExpressionType.Equal, outerKeyProperties[i], innerKeyProperties[i]); joinExpression = Expression.MakeBinary(ExpressionType.AndAlso, joinExpression, equal); } } MethodInfo firstMethodInfo = OeMethodInfoHelper.GetFirstMethodInfo(innerType); LambdaExpression joinLambda = Expression.Lambda(joinExpression !, innerKeySelector.Parameters); return(Expression.Call(firstMethodInfo, innerSource, joinLambda)); }