Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / System.Web.Entity / System / Data / WebControls / EntityDataSourceQueryBuilder.cs
1 //---------------------------------------------------------------------
2 // <copyright file="EntityDataSourceQueryBuilder.cs" company="Microsoft">
3 //      Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //
6 // @owner       [....]
7 // @backupOwner [....]
8 //---------------------------------------------------------------------
9
10 namespace System.Web.UI.WebControls
11 {
12     using System.Collections;
13     using System.ComponentModel;
14     using System.Data.Common;
15     using System.Data.Metadata.Edm;
16     using System.Data.Objects;
17     using System.Diagnostics;
18     using System.Globalization;
19     using System.Linq;
20
21     internal abstract class EntityDataSourceQueryBuilder<T>
22     {
23         private readonly DataSourceSelectArguments _arguments;
24         private readonly string _commandText;
25         private readonly ObjectParameter[] _commandParameters;
26         private readonly string _whereExpression;
27         private readonly ObjectParameter[] _whereParameters;
28         private readonly string _entitySetQueryExpression;
29         private readonly OrderByBuilder _orderByBuilder;
30         private string _includePaths;
31         private TypeUsage _resultType;
32         private Nullable<int> _count;
33
34         protected EntityDataSourceQueryBuilder(DataSourceSelectArguments arguments,
35                                               string commandText, ObjectParameter[] commandParameters,
36                                               string whereExpression, ObjectParameter[] whereParameters, string entitySetQueryExpression,
37                                               string selectExpression, string groupByExpression, ObjectParameter[] selectParameters,
38                                               OrderByBuilder orderByBuilder,
39                                               string includePaths)
40         {
41             _arguments = arguments;
42             _commandText = commandText;
43             _commandParameters = commandParameters;
44             _whereExpression = whereExpression;
45             _whereParameters = whereParameters;
46             _entitySetQueryExpression = entitySetQueryExpression;
47             _orderByBuilder = orderByBuilder;
48             _includePaths = includePaths;
49         }
50
51         internal delegate EntityDataSourceQueryBuilder<T> Creator(DataSourceSelectArguments arguments,
52                                       string commandText, ObjectParameter[] commandParameters,
53                                       string whereExpression, ObjectParameter[] whereParameters, string entitySetQueryExpression,
54                                       string selectExpression, string groupByExpression, ObjectParameter[] selectParameters,
55                                       OrderByBuilder orderByBuilder,
56                                       string includePaths);
57
58         internal TypeUsage ResultType
59         {
60             get
61             {
62                 Debug.Assert(_resultType != null, "ResultType is only valid after Build()");
63                 return _resultType;
64             }
65         }
66         internal int TotalCount
67         {
68             get
69             {
70                 Debug.Assert(_count.HasValue, "Count is not valid until after Build. And only then if computeCount is true");
71                 return _count.Value;
72             }
73         }
74         internal IEnumerable Execute(ObjectQuery<T> queryT)
75         {
76             return (IEnumerable)(((IListSource)(queryT)).GetList());
77         }
78
79         internal ObjectQuery<T> BuildBasicQuery(ObjectContext context, bool computeCount)
80         {
81             ObjectQuery<T> queryT = QueryBuilderUtils.ConstructQuery<T>(context, _entitySetQueryExpression, _commandText, _commandParameters);
82             queryT = ApplyWhere(queryT);
83             queryT = ApplySelect(queryT); // Select and/or GroupBy application
84             _resultType = queryT.GetResultType();
85             return queryT;
86         }
87
88         internal ObjectQuery<T> CompleteBuild(ObjectQuery<T> queryT, ObjectContext context, bool computeCount, bool wasExtended)
89         {
90             if (computeCount)
91             {
92                 _count = queryT.Count();
93             }
94
95             queryT = wasExtended ? ApplyQueryableOrderByAndPaging(queryT) : ApplyOrderByAndPaging(queryT);
96             queryT = ApplyIncludePaths(queryT);
97
98             return queryT;
99         }
100
101         private ObjectQuery<T> ApplyWhere(ObjectQuery<T> queryT)
102         {
103             if (!String.IsNullOrEmpty(_whereExpression))
104             {
105                 queryT = queryT.Where(_whereExpression, _whereParameters);
106             }
107             return queryT;
108         }
109
110         protected abstract ObjectQuery<T> ApplySelect(ObjectQuery<T> queryT);
111
112         internal ObjectQuery<T> ApplyOrderBy(ObjectQuery<T> queryT)
113         {
114             string orderByClause;
115             ObjectParameter[] orderByParameters;
116             // Apply all possible ordering except the sort expression, because it might only be valid after the query has been extended
117             _orderByBuilder.Generate(_resultType, out orderByClause, out orderByParameters, false /*applySortExpression*/);
118
119             return String.IsNullOrEmpty(orderByClause) ? queryT : queryT.OrderBy(orderByClause, orderByParameters);
120         }
121
122         private ObjectQuery<T> ApplyOrderByAndPaging(ObjectQuery<T> queryT)
123         {
124             // This re-applys the order-by as part of the skip
125             string orderByClause;
126             ObjectParameter[] orderByParameters;
127             _orderByBuilder.Generate(_resultType, out orderByClause, out orderByParameters, true /*applySortExpression*/);
128             bool paging = _arguments.MaximumRows > 0 && _arguments.StartRowIndex >= 0;
129             var hasOrderByClause = !String.IsNullOrEmpty(orderByClause);
130
131             if (paging)
132             {
133                 if (!hasOrderByClause)
134                 {
135                     throw new InvalidOperationException(Strings.EntityDataSourceQueryBuilder_PagingRequiresOrderBy);
136                 }
137                 queryT = queryT.Skip(orderByClause, _arguments.StartRowIndex.ToString(CultureInfo.InvariantCulture), orderByParameters).Top(_arguments.MaximumRows.ToString(CultureInfo.InvariantCulture), QueryBuilderUtils.EmptyObjectParameters);
138             }
139             else
140             {
141                 if (hasOrderByClause)
142                 {
143                     queryT = queryT.OrderBy(orderByClause, orderByParameters);
144                 }
145             }
146             
147             return queryT;
148         }
149
150         private ObjectQuery<T> ApplyQueryableOrderByAndPaging(ObjectQuery<T> queryT)
151         {
152             queryT = _orderByBuilder.BuildQueryableOrderBy(queryT) as ObjectQuery<T>;
153             bool paging = _arguments.MaximumRows > 0 && _arguments.StartRowIndex >= 0;
154             if (paging)
155             {
156                 queryT = queryT.Skip(_arguments.StartRowIndex).Take(_arguments.MaximumRows) as ObjectQuery<T>;
157             }
158
159             return queryT;
160         }
161
162         private ObjectQuery<T> ApplyIncludePaths(ObjectQuery<T> objectQuery)
163         {
164             if (!string.IsNullOrEmpty(_includePaths))
165             {
166                 foreach (string include in _includePaths.Split(','))
167                 {
168                     string trimmedInclude = include.Trim();
169                     if (!string.IsNullOrEmpty(trimmedInclude))
170                     {
171                         objectQuery = objectQuery.Include(trimmedInclude);
172                     }
173                 }
174             }
175             return objectQuery;
176         }
177     }
178
179     internal class EntityDataSourceObjectQueryBuilder<T> : EntityDataSourceQueryBuilder<T>
180     {
181         private EntityDataSourceObjectQueryBuilder(DataSourceSelectArguments arguments,
182                                                     string commandText, ObjectParameter[] commandParameters,
183                                                     string whereExpression, ObjectParameter[] whereParameters, string entitySetQueryExpression,
184                                                     string selectExpression, string groupByExpression, ObjectParameter[] selectParameters,
185                                                     OrderByBuilder orderByBuilder,
186                                                     string includePaths)
187             : base(arguments,
188                    commandText, commandParameters,
189                    whereExpression, whereParameters, entitySetQueryExpression,
190                    selectExpression, groupByExpression, selectParameters,
191                    orderByBuilder,
192                    includePaths)
193         {
194         }
195
196         static internal EntityDataSourceQueryBuilder<T>.Creator GetCreator()
197         {
198             return Create;
199         }
200
201         static internal EntityDataSourceQueryBuilder<T> Create(DataSourceSelectArguments arguments,
202                               string commandText, ObjectParameter[] commandParameters,
203                               string whereExpression, ObjectParameter[] whereParameters, string entitySetQueryExpression,
204                               string selectExpression, string groupByExpression, ObjectParameter[] selectParameters,
205                               OrderByBuilder orderByBuilder,
206                               string includePaths)
207         {
208             return new EntityDataSourceObjectQueryBuilder<T>(arguments,
209                    commandText, commandParameters,
210                    whereExpression, whereParameters, entitySetQueryExpression,
211                    selectExpression, groupByExpression, selectParameters,
212                    orderByBuilder,
213                    includePaths);
214         }
215
216         protected override ObjectQuery<T> ApplySelect(ObjectQuery<T> queryT)
217         {
218             return queryT;
219         }
220     }
221
222
223     internal class EntityDataSourceRecordQueryBuilder : EntityDataSourceQueryBuilder<DbDataRecord>
224     {
225         private readonly string _selectExpression;
226         private readonly string _groupByExpression;
227         private readonly ObjectParameter[] _selectParameters;
228
229         private EntityDataSourceRecordQueryBuilder(DataSourceSelectArguments arguments,
230                                                     string commandText, ObjectParameter[] commandParameters,
231                                                     string whereExpression, ObjectParameter[] whereParameters, string entitySetQueryExpression,
232                                                     string selectExpression, string groupByExpression, ObjectParameter[] selectParameters,
233                                                     OrderByBuilder orderByBuilder,
234                                                     string includePaths)
235             : base(arguments,
236                    commandText, commandParameters,
237                    whereExpression, whereParameters, entitySetQueryExpression,
238                    selectExpression, groupByExpression, selectParameters,
239                    orderByBuilder,
240                    includePaths)
241         {
242             _selectExpression = selectExpression;
243             _groupByExpression = groupByExpression;
244             _selectParameters = selectParameters;
245         }
246
247         static internal EntityDataSourceQueryBuilder<DbDataRecord> Create(DataSourceSelectArguments arguments,
248                       string commandText, ObjectParameter[] commandParameters,
249                       string whereExpression, ObjectParameter[] whereParameters, string entitySetQueryExpression,
250                       string selectExpression, string groupByExpression, ObjectParameter[] selectParameters,
251                       OrderByBuilder orderByBuilder,
252                       string includePaths)
253         {
254             return new EntityDataSourceRecordQueryBuilder(arguments,
255                    commandText, commandParameters,
256                    whereExpression, whereParameters, entitySetQueryExpression,
257                    selectExpression, groupByExpression, selectParameters,
258                    orderByBuilder,
259                    includePaths);
260         }
261
262         protected override ObjectQuery<DbDataRecord> ApplySelect(ObjectQuery<DbDataRecord> queryT)
263         {
264             Debug.Assert(!String.IsNullOrEmpty(_selectExpression), "Select expression should not be of zero length.");
265
266             if (!string.IsNullOrEmpty(_groupByExpression))
267             {
268                 queryT = queryT.GroupBy(_groupByExpression, _selectExpression, _selectParameters);
269             }
270             else
271             {
272                 queryT = queryT.Select(_selectExpression, _selectParameters);
273             }
274             return queryT;
275         }
276     }
277
278     internal static class QueryBuilderUtils
279     {
280         internal static readonly ObjectParameter[] EmptyObjectParameters = new ObjectParameter[] { };
281
282         internal static ObjectQuery<T> ConstructQuery<T>(ObjectContext context,
283                                                   string entitySetQueryExpression,
284                                                   string commandText,
285                                                   ObjectParameter[] commandParameters)
286         {
287             string queryExpression;
288             ObjectParameter[] queryParameters;
289             if (!string.IsNullOrEmpty(commandText))
290             {
291                 queryExpression = commandText;
292                 queryParameters = commandParameters;
293             }
294             else
295             {
296                 queryExpression = entitySetQueryExpression;
297                 queryParameters = QueryBuilderUtils.EmptyObjectParameters;
298             }
299
300             return context.CreateQuery<T>(queryExpression, queryParameters);
301         }
302     }
303 }