Mercurial > pub > bltoolkit
comparison Source/Data/Linq/Builder/SelectManyBuilder.cs @ 0:f990fcb411a9
Копия текущей версии из github
| author | cin |
|---|---|
| date | Thu, 27 Mar 2014 21:46:09 +0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:f990fcb411a9 |
|---|---|
| 1 using System; | |
| 2 using System.Collections.Generic; | |
| 3 using System.Linq.Expressions; | |
| 4 | |
| 5 namespace BLToolkit.Data.Linq.Builder | |
| 6 { | |
| 7 using BLToolkit.Linq; | |
| 8 using Data.Sql; | |
| 9 | |
| 10 class SelectManyBuilder : MethodCallBuilder | |
| 11 { | |
| 12 protected override bool CanBuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) | |
| 13 { | |
| 14 return | |
| 15 methodCall.IsQueryable("SelectMany") && | |
| 16 methodCall.Arguments.Count == 3 && | |
| 17 ((LambdaExpression)methodCall.Arguments[1].Unwrap()).Parameters.Count == 1; | |
| 18 } | |
| 19 | |
| 20 protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) | |
| 21 { | |
| 22 var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0])); | |
| 23 var collectionSelector = (LambdaExpression)methodCall.Arguments[1].Unwrap(); | |
| 24 var resultSelector = (LambdaExpression)methodCall.Arguments[2].Unwrap(); | |
| 25 | |
| 26 if (!sequence.SqlQuery.GroupBy.IsEmpty) | |
| 27 { | |
| 28 sequence = new SubQueryContext(sequence); | |
| 29 } | |
| 30 | |
| 31 var context = new SelectManyContext(buildInfo.Parent, collectionSelector, sequence); | |
| 32 var expr = collectionSelector.Body.Unwrap(); | |
| 33 | |
| 34 var collectionInfo = new BuildInfo(context, expr, new SqlQuery()); | |
| 35 var collection = builder.BuildSequence(collectionInfo); | |
| 36 var leftJoin = collection is DefaultIfEmptyBuilder.DefaultIfEmptyContext; | |
| 37 var sql = collection.SqlQuery; | |
| 38 | |
| 39 var sequenceTables = new HashSet<ISqlTableSource>(sequence.SqlQuery.From.Tables[0].GetTables()); | |
| 40 var newQuery = null != new QueryVisitor().Find(sql, e => e == collectionInfo.SqlQuery); | |
| 41 var crossApply = null != new QueryVisitor().Find(sql, e => | |
| 42 e.ElementType == QueryElementType.TableSource && sequenceTables.Contains((ISqlTableSource)e) || | |
| 43 e.ElementType == QueryElementType.SqlField && sequenceTables.Contains(((SqlField)e).Table) || | |
| 44 e.ElementType == QueryElementType.Column && sequenceTables.Contains(((SqlQuery.Column)e).Parent)); | |
| 45 | |
| 46 if (collection is JoinBuilder.GroupJoinSubQueryContext) | |
| 47 { | |
| 48 var groupJoin = ((JoinBuilder.GroupJoinSubQueryContext)collection).GroupJoin; | |
| 49 | |
| 50 groupJoin.SqlQuery.From.Tables[0].Joins[0].JoinType = SqlQuery.JoinType.Inner; | |
| 51 groupJoin.SqlQuery.From.Tables[0].Joins[0].IsWeak = false; | |
| 52 } | |
| 53 | |
| 54 if (!newQuery) | |
| 55 { | |
| 56 context.Collection = new SubQueryContext(collection, sequence.SqlQuery, false); | |
| 57 return new SelectContext(buildInfo.Parent, resultSelector, sequence, context); | |
| 58 } | |
| 59 | |
| 60 if (!crossApply) | |
| 61 { | |
| 62 if (!leftJoin) | |
| 63 { | |
| 64 context.Collection = new SubQueryContext(collection, sequence.SqlQuery, true); | |
| 65 return new SelectContext(buildInfo.Parent, resultSelector, sequence, context); | |
| 66 } | |
| 67 else | |
| 68 { | |
| 69 var join = SqlQuery.OuterApply(sql); | |
| 70 sequence.SqlQuery.From.Tables[0].Joins.Add(join.JoinedTable); | |
| 71 context.Collection = new SubQueryContext(collection, sequence.SqlQuery, false); | |
| 72 | |
| 73 return new SelectContext(buildInfo.Parent, resultSelector, sequence, context); | |
| 74 } | |
| 75 } | |
| 76 | |
| 77 if (collection is TableBuilder.TableContext) | |
| 78 { | |
| 79 var table = (TableBuilder.TableContext)collection; | |
| 80 var join = table.SqlTable.TableArguments != null && table.SqlTable.TableArguments.Length > 0 ? | |
| 81 (leftJoin ? SqlQuery.OuterApply(sql) : SqlQuery.CrossApply(sql)) : | |
| 82 (leftJoin ? SqlQuery.LeftJoin (sql) : SqlQuery.InnerJoin (sql)); | |
| 83 | |
| 84 join.JoinedTable.Condition.Conditions.AddRange(sql.Where.SearchCondition.Conditions); | |
| 85 join.JoinedTable.CanConvertApply = false; | |
| 86 | |
| 87 sql.Where.SearchCondition.Conditions.Clear(); | |
| 88 | |
| 89 var collectionParent = collection.Parent as TableBuilder.TableContext; | |
| 90 | |
| 91 // Association. | |
| 92 // | |
| 93 if (collectionParent != null && collectionInfo.IsAssociationBuilt) | |
| 94 { | |
| 95 var ts = (SqlQuery.TableSource)new QueryVisitor().Find(sequence.SqlQuery.From, e => | |
| 96 { | |
| 97 if (e.ElementType == QueryElementType.TableSource) | |
| 98 { | |
| 99 var t = (SqlQuery.TableSource)e; | |
| 100 return t.Source == collectionParent.SqlTable; | |
| 101 } | |
| 102 | |
| 103 return false; | |
| 104 }); | |
| 105 | |
| 106 ts.Joins.Add(join.JoinedTable); | |
| 107 } | |
| 108 else | |
| 109 { | |
| 110 sequence.SqlQuery.From.Tables[0].Joins.Add(join.JoinedTable); | |
| 111 } | |
| 112 | |
| 113 context.Collection = new SubQueryContext(collection, sequence.SqlQuery, false); | |
| 114 return new SelectContext(buildInfo.Parent, resultSelector, sequence, context); | |
| 115 } | |
| 116 else | |
| 117 { | |
| 118 var join = leftJoin ? SqlQuery.OuterApply(sql) : SqlQuery.CrossApply(sql); | |
| 119 sequence.SqlQuery.From.Tables[0].Joins.Add(join.JoinedTable); | |
| 120 | |
| 121 context.Collection = new SubQueryContext(collection, sequence.SqlQuery, false); | |
| 122 return new SelectContext(buildInfo.Parent, resultSelector, sequence, context); | |
| 123 } | |
| 124 } | |
| 125 | |
| 126 protected override SequenceConvertInfo Convert( | |
| 127 ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo, ParameterExpression param) | |
| 128 { | |
| 129 return null; | |
| 130 } | |
| 131 | |
| 132 public class SelectManyContext : SelectContext | |
| 133 { | |
| 134 public SelectManyContext(IBuildContext parent, LambdaExpression lambda, IBuildContext sequence) | |
| 135 : base(parent, lambda, sequence) | |
| 136 { | |
| 137 } | |
| 138 | |
| 139 private IBuildContext _collection; | |
| 140 public IBuildContext Collection | |
| 141 { | |
| 142 get { return _collection; } | |
| 143 set | |
| 144 { | |
| 145 _collection = value; | |
| 146 _collection.Parent = this; | |
| 147 } | |
| 148 } | |
| 149 | |
| 150 public override Expression BuildExpression(Expression expression, int level) | |
| 151 { | |
| 152 if (expression == null) | |
| 153 return Collection.BuildExpression(expression, level); | |
| 154 | |
| 155 var root = expression.GetRootObject(); | |
| 156 | |
| 157 if (root == Lambda.Parameters[0]) | |
| 158 return base.BuildExpression(expression, level); | |
| 159 | |
| 160 return Collection.BuildExpression(expression, level); | |
| 161 } | |
| 162 | |
| 163 public override void BuildQuery<T>(Query<T> query, ParameterExpression queryParameter) | |
| 164 { | |
| 165 if (Collection == null) | |
| 166 base.BuildQuery(query, queryParameter); | |
| 167 | |
| 168 throw new InvalidOperationException(); | |
| 169 } | |
| 170 | |
| 171 public override SqlInfo[] ConvertToIndex(Expression expression, int level, ConvertFlags flags) | |
| 172 { | |
| 173 if (Collection != null) | |
| 174 { | |
| 175 if (expression == null) | |
| 176 return Collection.ConvertToIndex(expression, level, flags); | |
| 177 | |
| 178 var root = expression.GetRootObject(); | |
| 179 | |
| 180 if (root != Lambda.Parameters[0]) | |
| 181 return Collection.ConvertToIndex(expression, level, flags); | |
| 182 } | |
| 183 | |
| 184 return base.ConvertToIndex(expression, level, flags); | |
| 185 } | |
| 186 | |
| 187 /* | |
| 188 public override int ConvertToParentIndex(int index, IBuildContext context) | |
| 189 { | |
| 190 if (Collection == null) | |
| 191 return base.ConvertToParentIndex(index, context); | |
| 192 | |
| 193 throw new NotImplementedException(); | |
| 194 } | |
| 195 */ | |
| 196 | |
| 197 public override SqlInfo[] ConvertToSql(Expression expression, int level, ConvertFlags flags) | |
| 198 { | |
| 199 if (Collection != null) | |
| 200 { | |
| 201 if (expression == null) | |
| 202 return Collection.ConvertToSql(expression, level, flags); | |
| 203 | |
| 204 var root = expression.GetRootObject(); | |
| 205 | |
| 206 if (root != Lambda.Parameters[0]) | |
| 207 return Collection.ConvertToSql(expression, level, flags); | |
| 208 } | |
| 209 | |
| 210 return base.ConvertToSql(expression, level, flags); | |
| 211 } | |
| 212 | |
| 213 public override IBuildContext GetContext(Expression expression, int level, BuildInfo buildInfo) | |
| 214 { | |
| 215 if (Collection != null) | |
| 216 { | |
| 217 if (expression == null) | |
| 218 return Collection.GetContext(expression, level, buildInfo); | |
| 219 | |
| 220 var root = expression.GetRootObject(); | |
| 221 | |
| 222 if (root != Lambda.Parameters[0]) | |
| 223 return Collection.GetContext(expression, level, buildInfo); | |
| 224 } | |
| 225 | |
| 226 return base.GetContext(expression, level, buildInfo); | |
| 227 } | |
| 228 | |
| 229 public override IsExpressionResult IsExpression(Expression expression, int level, RequestFor requestFlag) | |
| 230 { | |
| 231 if (Collection != null) | |
| 232 { | |
| 233 if (expression == null) | |
| 234 return Collection.IsExpression(expression, level, requestFlag); | |
| 235 | |
| 236 var root = expression.GetRootObject(); | |
| 237 | |
| 238 if (root != Lambda.Parameters[0]) | |
| 239 return Collection.IsExpression(expression, level, requestFlag); | |
| 240 } | |
| 241 | |
| 242 return base.IsExpression(expression, level, requestFlag); | |
| 243 } | |
| 244 } | |
| 245 } | |
| 246 } |
