Mercurial > pub > bltoolkit
view Source/Data/Linq/Builder/SelectManyBuilder.cs @ 9:1e85f66cf767 default tip
update bltoolkit
author | nickolay |
---|---|
date | Thu, 05 Apr 2018 20:53:26 +0300 |
parents | f990fcb411a9 |
children |
line wrap: on
line source
using System; using System.Collections.Generic; using System.Linq.Expressions; namespace BLToolkit.Data.Linq.Builder { using BLToolkit.Linq; using Data.Sql; class SelectManyBuilder : MethodCallBuilder { protected override bool CanBuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) { return methodCall.IsQueryable("SelectMany") && methodCall.Arguments.Count == 3 && ((LambdaExpression)methodCall.Arguments[1].Unwrap()).Parameters.Count == 1; } protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) { var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0])); var collectionSelector = (LambdaExpression)methodCall.Arguments[1].Unwrap(); var resultSelector = (LambdaExpression)methodCall.Arguments[2].Unwrap(); if (!sequence.SqlQuery.GroupBy.IsEmpty) { sequence = new SubQueryContext(sequence); } var context = new SelectManyContext(buildInfo.Parent, collectionSelector, sequence); var expr = collectionSelector.Body.Unwrap(); var collectionInfo = new BuildInfo(context, expr, new SqlQuery()); var collection = builder.BuildSequence(collectionInfo); var leftJoin = collection is DefaultIfEmptyBuilder.DefaultIfEmptyContext; var sql = collection.SqlQuery; var sequenceTables = new HashSet<ISqlTableSource>(sequence.SqlQuery.From.Tables[0].GetTables()); var newQuery = null != new QueryVisitor().Find(sql, e => e == collectionInfo.SqlQuery); var crossApply = null != new QueryVisitor().Find(sql, e => e.ElementType == QueryElementType.TableSource && sequenceTables.Contains((ISqlTableSource)e) || e.ElementType == QueryElementType.SqlField && sequenceTables.Contains(((SqlField)e).Table) || e.ElementType == QueryElementType.Column && sequenceTables.Contains(((SqlQuery.Column)e).Parent)); if (collection is JoinBuilder.GroupJoinSubQueryContext) { var groupJoin = ((JoinBuilder.GroupJoinSubQueryContext)collection).GroupJoin; groupJoin.SqlQuery.From.Tables[0].Joins[0].JoinType = SqlQuery.JoinType.Inner; groupJoin.SqlQuery.From.Tables[0].Joins[0].IsWeak = false; } if (!newQuery) { context.Collection = new SubQueryContext(collection, sequence.SqlQuery, false); return new SelectContext(buildInfo.Parent, resultSelector, sequence, context); } if (!crossApply) { if (!leftJoin) { context.Collection = new SubQueryContext(collection, sequence.SqlQuery, true); return new SelectContext(buildInfo.Parent, resultSelector, sequence, context); } else { var join = SqlQuery.OuterApply(sql); sequence.SqlQuery.From.Tables[0].Joins.Add(join.JoinedTable); context.Collection = new SubQueryContext(collection, sequence.SqlQuery, false); return new SelectContext(buildInfo.Parent, resultSelector, sequence, context); } } if (collection is TableBuilder.TableContext) { var table = (TableBuilder.TableContext)collection; var join = table.SqlTable.TableArguments != null && table.SqlTable.TableArguments.Length > 0 ? (leftJoin ? SqlQuery.OuterApply(sql) : SqlQuery.CrossApply(sql)) : (leftJoin ? SqlQuery.LeftJoin (sql) : SqlQuery.InnerJoin (sql)); join.JoinedTable.Condition.Conditions.AddRange(sql.Where.SearchCondition.Conditions); join.JoinedTable.CanConvertApply = false; sql.Where.SearchCondition.Conditions.Clear(); var collectionParent = collection.Parent as TableBuilder.TableContext; // Association. // if (collectionParent != null && collectionInfo.IsAssociationBuilt) { var ts = (SqlQuery.TableSource)new QueryVisitor().Find(sequence.SqlQuery.From, e => { if (e.ElementType == QueryElementType.TableSource) { var t = (SqlQuery.TableSource)e; return t.Source == collectionParent.SqlTable; } return false; }); ts.Joins.Add(join.JoinedTable); } else { sequence.SqlQuery.From.Tables[0].Joins.Add(join.JoinedTable); } context.Collection = new SubQueryContext(collection, sequence.SqlQuery, false); return new SelectContext(buildInfo.Parent, resultSelector, sequence, context); } else { var join = leftJoin ? SqlQuery.OuterApply(sql) : SqlQuery.CrossApply(sql); sequence.SqlQuery.From.Tables[0].Joins.Add(join.JoinedTable); context.Collection = new SubQueryContext(collection, sequence.SqlQuery, false); return new SelectContext(buildInfo.Parent, resultSelector, sequence, context); } } protected override SequenceConvertInfo Convert( ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo, ParameterExpression param) { return null; } public class SelectManyContext : SelectContext { public SelectManyContext(IBuildContext parent, LambdaExpression lambda, IBuildContext sequence) : base(parent, lambda, sequence) { } private IBuildContext _collection; public IBuildContext Collection { get { return _collection; } set { _collection = value; _collection.Parent = this; } } public override Expression BuildExpression(Expression expression, int level) { if (expression == null) return Collection.BuildExpression(expression, level); var root = expression.GetRootObject(); if (root == Lambda.Parameters[0]) return base.BuildExpression(expression, level); return Collection.BuildExpression(expression, level); } public override void BuildQuery<T>(Query<T> query, ParameterExpression queryParameter) { if (Collection == null) base.BuildQuery(query, queryParameter); throw new InvalidOperationException(); } public override SqlInfo[] ConvertToIndex(Expression expression, int level, ConvertFlags flags) { if (Collection != null) { if (expression == null) return Collection.ConvertToIndex(expression, level, flags); var root = expression.GetRootObject(); if (root != Lambda.Parameters[0]) return Collection.ConvertToIndex(expression, level, flags); } return base.ConvertToIndex(expression, level, flags); } /* public override int ConvertToParentIndex(int index, IBuildContext context) { if (Collection == null) return base.ConvertToParentIndex(index, context); throw new NotImplementedException(); } */ public override SqlInfo[] ConvertToSql(Expression expression, int level, ConvertFlags flags) { if (Collection != null) { if (expression == null) return Collection.ConvertToSql(expression, level, flags); var root = expression.GetRootObject(); if (root != Lambda.Parameters[0]) return Collection.ConvertToSql(expression, level, flags); } return base.ConvertToSql(expression, level, flags); } public override IBuildContext GetContext(Expression expression, int level, BuildInfo buildInfo) { if (Collection != null) { if (expression == null) return Collection.GetContext(expression, level, buildInfo); var root = expression.GetRootObject(); if (root != Lambda.Parameters[0]) return Collection.GetContext(expression, level, buildInfo); } return base.GetContext(expression, level, buildInfo); } public override IsExpressionResult IsExpression(Expression expression, int level, RequestFor requestFlag) { if (Collection != null) { if (expression == null) return Collection.IsExpression(expression, level, requestFlag); var root = expression.GetRootObject(); if (root != Lambda.Parameters[0]) return Collection.IsExpression(expression, level, requestFlag); } return base.IsExpression(expression, level, requestFlag); } } } }