Mercurial > pub > bltoolkit
comparison Source/Data/Linq/Builder/SubQueryContext.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; | |
4 using System.Linq.Expressions; | |
5 | |
6 namespace BLToolkit.Data.Linq.Builder | |
7 { | |
8 using BLToolkit.Linq; | |
9 using Data.Sql; | |
10 | |
11 class SubQueryContext : PassThroughContext | |
12 { | |
13 public readonly IBuildContext SubQuery; | |
14 | |
15 public SubQueryContext(IBuildContext subQuery, SqlQuery sqlQuery, bool addToSql) | |
16 : base(subQuery) | |
17 { | |
18 if (sqlQuery == subQuery.SqlQuery) | |
19 throw new ArgumentException("Wrong subQuery argument.", "subQuery"); | |
20 | |
21 SubQuery = subQuery; | |
22 SubQuery.Parent = this; | |
23 | |
24 SqlQuery = sqlQuery; | |
25 | |
26 if (addToSql) | |
27 sqlQuery.From.Table(SubQuery.SqlQuery); | |
28 } | |
29 | |
30 public SubQueryContext(IBuildContext subQuery, bool addToSql) | |
31 : this(subQuery, new SqlQuery { ParentSql = subQuery.SqlQuery.ParentSql }, addToSql) | |
32 { | |
33 } | |
34 | |
35 public SubQueryContext(IBuildContext subQuery) | |
36 : this(subQuery, true) | |
37 { | |
38 } | |
39 | |
40 public override SqlQuery SqlQuery { get; set; } | |
41 public override IBuildContext Parent { get; set; } | |
42 | |
43 public override void BuildQuery<T>(Query<T> query, ParameterExpression queryParameter) | |
44 { | |
45 if (Expression.NodeType == ExpressionType.Lambda) | |
46 { | |
47 var le = (LambdaExpression)Expression; | |
48 | |
49 if (le.Parameters.Count == 1 && null != Expression.Find( | |
50 e => e.NodeType == ExpressionType.Call && ((MethodCallExpression)e).IsQueryable())) | |
51 { | |
52 if (le.Body.NodeType == ExpressionType.New) | |
53 { | |
54 var ne = (NewExpression)le.Body; | |
55 var p = Expression.Parameter(ne.Type, "p"); | |
56 | |
57 var seq = new SelectContext( | |
58 Parent, | |
59 Expression.Lambda( | |
60 Expression.New( | |
61 ne.Constructor, | |
62 ne.Members.Select(m => Expression.MakeMemberAccess(p, m)).ToArray(), | |
63 ne.Members), | |
64 p), | |
65 this); | |
66 | |
67 seq.BuildQuery(query, queryParameter); | |
68 | |
69 return; | |
70 } | |
71 | |
72 if (le.Body.NodeType == ExpressionType.MemberInit) | |
73 { | |
74 var mi = (MemberInitExpression)le.Body; | |
75 | |
76 if (mi.NewExpression.Arguments.Count == 0 && mi.Bindings.All(b => b is MemberAssignment)) | |
77 { | |
78 var p = Expression.Parameter(mi.Type, "p"); | |
79 | |
80 var seq = new SelectContext( | |
81 Parent, | |
82 Expression.Lambda( | |
83 Expression.MemberInit( | |
84 mi.NewExpression, | |
85 mi.Bindings | |
86 .OfType<MemberAssignment>() | |
87 .Select(ma => Expression.Bind(ma.Member, Expression.MakeMemberAccess(p, ma.Member))) | |
88 .ToArray()), | |
89 p), | |
90 this); | |
91 | |
92 seq.BuildQuery(query, queryParameter); | |
93 | |
94 return; | |
95 } | |
96 } | |
97 } | |
98 } | |
99 | |
100 base.BuildQuery(query, queryParameter); | |
101 } | |
102 | |
103 public override SqlInfo[] ConvertToSql(Expression expression, int level, ConvertFlags flags) | |
104 { | |
105 return SubQuery | |
106 .ConvertToIndex(expression, level, flags) | |
107 .Select(idx => new SqlInfo(idx.Members) { Sql = SubQuery.SqlQuery.Select.Columns[idx.Index] }) | |
108 .ToArray(); | |
109 } | |
110 | |
111 // JoinContext has similar logic. Consider to review it. | |
112 // | |
113 public override SqlInfo[] ConvertToIndex(Expression expression, int level, ConvertFlags flags) | |
114 { | |
115 return ConvertToSql(expression, level, flags) | |
116 .Select(idx => | |
117 { | |
118 idx.Query = SqlQuery; | |
119 idx.Index = GetIndex((SqlQuery.Column)idx.Sql); | |
120 | |
121 return idx; | |
122 }) | |
123 .ToArray(); | |
124 } | |
125 | |
126 public override IsExpressionResult IsExpression(Expression expression, int level, RequestFor testFlag) | |
127 { | |
128 switch (testFlag) | |
129 { | |
130 case RequestFor.SubQuery : return IsExpressionResult.True; | |
131 } | |
132 | |
133 return base.IsExpression(expression, level, testFlag); | |
134 } | |
135 | |
136 internal protected readonly Dictionary<ISqlExpression,int> ColumnIndexes = new Dictionary<ISqlExpression,int>(); | |
137 | |
138 protected virtual int GetIndex(SqlQuery.Column column) | |
139 { | |
140 int idx; | |
141 | |
142 if (!ColumnIndexes.TryGetValue(column, out idx)) | |
143 { | |
144 idx = SqlQuery.Select.Add(column); | |
145 ColumnIndexes.Add(column, idx); | |
146 } | |
147 | |
148 return idx; | |
149 } | |
150 | |
151 public override int ConvertToParentIndex(int index, IBuildContext context) | |
152 { | |
153 var idx = GetIndex(context.SqlQuery.Select.Columns[index]); | |
154 return Parent == null ? idx : Parent.ConvertToParentIndex(idx, this); | |
155 } | |
156 | |
157 public override void SetAlias(string alias) | |
158 { | |
159 if (alias.Contains('<')) | |
160 return; | |
161 | |
162 if (SqlQuery.From.Tables[0].Alias == null) | |
163 SqlQuery.From.Tables[0].Alias = alias; | |
164 } | |
165 | |
166 public override ISqlExpression GetSubQuery(IBuildContext context) | |
167 { | |
168 return null; | |
169 } | |
170 } | |
171 } |