protected override Expression VisitMemberAccess(MemberExpression m) { Expression source = this.Visit(m.Expression); if (this.mapping.IsRelationship(m.Member)) { ProjectionExpression projection = (ProjectionExpression)this.Visit(this.mapping.GetMemberExpression(source, m.Member)); if (this.currentFrom != null && this.mapping.IsSingletonRelationship(m.Member)) { // convert singleton associations directly to OUTER APPLY projection = projection.AddOuterJoinTest(); Expression newFrom = new JoinExpression(JoinType.OuterApply, this.currentFrom, projection.Source, null); this.currentFrom = newFrom; return(projection.Projector); } return(projection); } else { Expression result = QueryBinder.BindMember(source, m.Member); MemberExpression mex = result as MemberExpression; if (mex != null && mex.Member == m.Member && mex.Expression == m.Expression) { return(m); } return(result); } }
protected virtual Expression BindSelectMany(Type resultType, Expression source, LambdaExpression collectionSelector, LambdaExpression resultSelector) { ProjectionExpression projection = VisitSequence(source); map[collectionSelector.Parameters[0]] = projection.Projector; Expression collection = collectionSelector.Body; // check for DefaultIfEmpty bool defaultIfEmpty = false; MethodCallExpression mcs = collection as MethodCallExpression; if (mcs != null && mcs.Method.Name == "DefaultIfEmpty" && mcs.Arguments.Count == 1 && (mcs.Method.DeclaringType == typeof(Queryable) || mcs.Method.DeclaringType == typeof(Enumerable))) { collection = mcs.Arguments[0]; defaultIfEmpty = true; } ProjectionExpression collectionProjection = VisitSequence(collection); bool isTable = collectionProjection.Source.From is TableExpression; JoinType joinType = isTable ? JoinType.CrossJoin : defaultIfEmpty ? JoinType.OuterApply : JoinType.CrossApply; if (joinType == JoinType.OuterApply) { collectionProjection = collectionProjection.AddOuterJoinTest(); } JoinExpression join = new JoinExpression(joinType, projection.Source, collectionProjection.Source, null); var alias = GetNextAlias(); ProjectedColumns pc; if (resultSelector == null) { pc = ProjectColumns(collectionProjection.Projector, alias, projection.Source.Alias, collectionProjection.Source.Alias); } else { map[resultSelector.Parameters[0]] = projection.Projector; map[resultSelector.Parameters[1]] = collectionProjection.Projector; Expression result = Visit(resultSelector.Body); pc = ProjectColumns(result, alias, projection.Source.Alias, collectionProjection.Source.Alias); } return(new ProjectionExpression( new SelectExpression(alias, pc.Columns, join, null), pc.Projector )); }