Updates referencesource to .NET 4.7
[mono-project.git] / mcs / class / referencesource / System.Data.Entity / System / Data / Common / CommandTrees / ExpressionBuilder / DbExpressionBuilder.cs
blob6db0404e3d4e2bf315a104e4b3b1c2f34fe5f457
1 //---------------------------------------------------------------------
2 // <copyright file="DbExpressionBuilder.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 // </copyright>
5 //
6 // @owner Microsoft
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
10 namespace System.Data.Common.CommandTrees.ExpressionBuilder
12 using System;
13 using System.Collections.Generic;
14 using System.Data.Common;
15 using System.Data.Common.CommandTrees.ExpressionBuilder.Internal;
16 using System.Data.Common.CommandTrees.Internal;
17 using System.Data.Common.Utils;
18 using System.Data.Entity;
19 using System.Data.Metadata.Edm;
20 using System.Diagnostics;
21 using System.Globalization;
22 using System.Linq;
23 using System.Reflection;
24 using System.Runtime.CompilerServices;
26 /// <summary>
27 /// Provides an API to construct <see cref="DbExpression"/>s and allows that API to be accessed as extension methods on the expression type itself.
28 /// </summary>
29 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Db")]
30 public static class DbExpressionBuilder
32 #region Private Implementation
34 private static readonly AliasGenerator _bindingAliases = new AliasGenerator("Var_", 0);
36 private static readonly DbNullExpression _binaryNull = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.Binary));
37 private static readonly DbNullExpression _boolNull = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.Boolean));
38 private static readonly DbNullExpression _byteNull = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.Byte));
39 private static readonly DbNullExpression _dateTimeNull = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.DateTime));
40 private static readonly DbNullExpression _dateTimeOffsetNull = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.DateTimeOffset));
41 private static readonly DbNullExpression _decimalNull = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.Decimal));
42 private static readonly DbNullExpression _doubleNull = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.Double));
43 private static readonly DbNullExpression _geographyNull = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.Geography));
44 private static readonly DbNullExpression _geometryNull = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.Geometry));
45 private static readonly DbNullExpression _guidNull = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.Guid));
46 private static readonly DbNullExpression _int16Null = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.Int16));
47 private static readonly DbNullExpression _int32Null = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.Int32));
48 private static readonly DbNullExpression _int64Null = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.Int64));
49 private static readonly DbNullExpression _sbyteNull = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.SByte));
50 private static readonly DbNullExpression _singleNull = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.Single));
51 private static readonly DbNullExpression _stringNull = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.String));
52 private static readonly DbNullExpression _timeNull = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.Time));
54 private static readonly DbConstantExpression _boolTrue = Constant(true);
55 private static readonly DbConstantExpression _boolFalse = Constant(false);
57 #endregion
59 #region Helpers (not strictly Command Tree API)
61 public static KeyValuePair<string, DbExpression> As(this DbExpression value, string alias)
63 return new KeyValuePair<string, DbExpression>(alias, value);
66 public static KeyValuePair<string, DbAggregate> As(this DbAggregate value, string alias)
68 return new KeyValuePair<string, DbAggregate>(alias, value);
71 #endregion
73 #region Bindings - Expression and Group
75 /// <summary>
76 /// Creates a new <see cref="DbExpressionBinding"/> that uses a generated variable name to bind the given expression
77 /// </summary>
78 /// <param name="input">The expression to bind</param>
79 /// <returns>A new expression binding with the specified expression and a generated variable name</returns>
80 /// <exception cref="ArgumentNullException"><paramref name="input"/> is null</exception>
81 /// <exception cref="ArgumentException"><paramref name="input"/> does not have a collection result type</exception>
82 public static DbExpressionBinding Bind(this DbExpression input)
84 return DbExpressionBuilder.BindAs(input, _bindingAliases.Next());
87 /// <summary>
88 /// Creates a new <see cref="DbExpressionBinding"/> that uses the specified variable name to bind the given expression
89 /// </summary>
90 /// <param name="input">The expression to bind</param>
91 /// <param name="varName">The variable name that should be used for the binding</param>
92 /// <returns>A new expression binding with the specified expression and variable name</returns>
93 /// <exception cref="ArgumentNullException"><paramref name="input"/> or <paramref name="varName"/> is null</exception>
94 /// <exception cref="ArgumentException"><paramref name="input"/> does not have a collection result type</exception>
95 public static DbExpressionBinding BindAs(this DbExpression input, string varName)
97 TypeUsage elementType = ArgumentValidation.ValidateBindAs(input, varName);
98 DbVariableReferenceExpression inputRef = new DbVariableReferenceExpression(elementType, varName);
99 return new DbExpressionBinding(input, inputRef);
102 /// <summary>
103 /// Creates a new group expression binding that uses generated variable and group variable names to bind the given expression
104 /// </summary>
105 /// <param name="input">The expression to bind</param>
106 /// <returns>A new group expression binding with the specified expression and a generated variable name and group variable name</returns>
107 /// <exception cref="ArgumentNullException"><paramref name="input"/> is null</exception>
108 /// <exception cref="ArgumentException"><paramref name="input"/> does not have a collection result type</exception>
109 public static DbGroupExpressionBinding GroupBind(this DbExpression input)
111 string alias = _bindingAliases.Next();
112 return DbExpressionBuilder.GroupBindAs(input, alias, string.Format(CultureInfo.InvariantCulture, "Group{0}", alias));
115 /// <summary>
116 /// Creates a new <see cref="DbGroupExpressionBinding"/> that uses the specified variable name and group variable names to bind the given expression
117 /// </summary>
118 /// <param name="input">The expression to bind</param>
119 /// <param name="varName">The variable name that should be used for the binding</param>
120 /// <param name="groupVarName">The variable name that should be used to refer to the group when the new group expression binding is used in a group-by expression</param>
121 /// <returns>A new group expression binding with the specified expression, variable name and group variable name</returns>
122 /// <exception cref="ArgumentNullException"><paramref name="input"/>, <paramref name="varName"/> or <paramref name="groupVarName"/> is null</exception>
123 /// <exception cref="ArgumentException"><paramref name="input"/> does not have a collection result type</exception>
124 public static DbGroupExpressionBinding GroupBindAs(this DbExpression input, string varName, string groupVarName)
126 TypeUsage elementType = ArgumentValidation.ValidateGroupBindAs(input, varName, groupVarName);
127 DbVariableReferenceExpression inputRef = new DbVariableReferenceExpression(elementType, varName);
128 DbVariableReferenceExpression groupRef = new DbVariableReferenceExpression(elementType, groupVarName);
129 return new DbGroupExpressionBinding(input, inputRef, groupRef);
132 #endregion
134 #region Aggregates and SortClauses are required only for Binding-based method support - replaced by OrderBy[Descending]/ThenBy[Descending] and Aggregate[Distinct] methods in new API
136 /// <summary>
137 /// Creates a new <see cref="DbFunctionAggregate"/>.
138 /// </summary>
139 /// <param name="function">The function that defines the aggregate operation.</param>
140 /// <param name="argument">The argument over which the aggregate function should be calculated.</param>
141 /// <returns>A new function aggregate with a reference to the given function and argument. The function aggregate's Distinct property will have the value false</returns>
142 /// <exception cref="ArgumentNullException"><paramref name="function"/> or <paramref name="argument"/> is null</exception>
143 /// <exception cref="ArgumentException">
144 /// <paramref name="function"/> is not an aggregate function or has more than one argument, or
145 /// the result type of <paramref name="argument"/> is not equal or promotable to
146 /// the parameter type of <paramref name="function"/>
147 /// </exception>
148 public static DbFunctionAggregate Aggregate(this EdmFunction function, DbExpression argument)
150 return CreateFunctionAggregate(function, argument, false);
153 /// <summary>
154 /// Creates a new <see cref="DbFunctionAggregate"/> that is applied in a distinct fashion.
155 /// </summary>
156 /// <param name="function">The function that defines the aggregate operation.</param>
157 /// <param name="argument">The argument over which the aggregate function should be calculated.</param>
158 /// <returns>A new function aggregate with a reference to the given function and argument. The function aggregate's Distinct property will have the value true</returns>
159 /// <exception cref="ArgumentNullException"><paramref name="function"/> or <paramref name="argument"/> is null</exception>
160 /// <exception cref="ArgumentException">
161 /// <paramref name="function"/> is not an aggregate function or has more than one argument, or
162 /// the result type of <paramref name="argument"/> is not equal or promotable to
163 /// the parameter type of <paramref name="function"/>
164 /// </exception>
165 public static DbFunctionAggregate AggregateDistinct(this EdmFunction function, DbExpression argument)
167 return CreateFunctionAggregate(function, argument, true);
170 private static DbFunctionAggregate CreateFunctionAggregate(EdmFunction function, DbExpression argument, bool isDistinct)
172 EntityUtil.CheckArgumentNull(argument, "argument");
173 DbExpressionList funcArgs = ArgumentValidation.ValidateFunctionAggregate(function, new[] { argument });
174 TypeUsage resultType = function.ReturnParameter.TypeUsage;
175 return new DbFunctionAggregate(resultType, funcArgs, function, isDistinct);
178 /// <summary>
179 /// Creates a new <see cref="DbGroupAggregate"/> over the specified argument
180 /// </summary>
181 /// <param name="argument">The argument over which to perform the nest operation</param>
182 /// <returns>A new group aggregate representing the elements of the group referenced by the given argument.</returns>
183 /// <exception cref="ArgumentNullException"><paramref name="argument"/> is null</exception>
184 /*ENABLE_ELEMENT_SELECTOR(*/internal/*)*/ static DbGroupAggregate GroupAggregate(DbExpression argument)
186 DbExpressionList arguments = ArgumentValidation.ValidateGroupAggregate(argument);
187 TypeUsage resultType = TypeHelpers.CreateCollectionTypeUsage(argument.ResultType);
188 return new DbGroupAggregate(resultType, arguments);
191 /// <summary>
192 /// Creates a <see cref="DbLambda"/> with the specified inline Lambda function implementation and formal parameters.
193 /// </summary>
194 /// <param name="body">An expression that defines the logic of the Lambda function</param>
195 /// <param name="variables">
196 /// A <see cref="DbVariableReferenceExpression"/> collection that represents the formal parameters to the Lambda function.
197 /// These variables are valid for use in the <paramref name="body"/> expression.
198 /// </param>
199 /// <returns>A new DbLambda that describes an inline Lambda function with the specified body and formal parameters</returns>
200 /// <exception cref="ArgumentNullException">
201 /// <paramref name="variables"/> is null or contains null, or <paramref name="body"/> is null
202 /// </exception>.
203 /// <exception cref="ArgumentException">
204 /// <paramref name="variables"/> contains more than one element with the same variable name.
205 /// </exception>
206 public static DbLambda Lambda(DbExpression body, IEnumerable<DbVariableReferenceExpression> variables)
208 return CreateLambda(body, variables);
211 /// <summary>
212 /// Creates a <see cref="DbLambda"/> with the specified inline Lambda function implementation and formal parameters.
213 /// </summary>
214 /// <param name="body">An expression that defines the logic of the Lambda function</param>
215 /// <param name="variables">
216 /// A <see cref="DbVariableReferenceExpression"/> collection that represents the formal parameters to the Lambda function.
217 /// These variables are valid for use in the <paramref name="body"/> expression.
218 /// </param>
219 /// <returns>A new DbLambda that describes an inline Lambda function with the specified body and formal parameters</returns>
220 /// <exception cref="ArgumentNullException">
221 /// <paramref name="variables"/> is null or contains null, or <paramref name="body"/> is null
222 /// </exception>.
223 /// <exception cref="ArgumentException">
224 /// <paramref name="variables"/> contains more than one element with the same variable name.
225 /// </exception>
226 public static DbLambda Lambda(DbExpression body, params DbVariableReferenceExpression[] variables)
228 return CreateLambda(body, variables);
231 private static DbLambda CreateLambda(DbExpression body, IEnumerable<DbVariableReferenceExpression> variables)
233 var validVars = ArgumentValidation.ValidateLambda(variables, body);
234 return new DbLambda(validVars, body);
237 /// <summary>
238 /// Creates a new <see cref="DbSortClause"/> with an ascending sort order and default collation
239 /// </summary>
240 /// <param name="key">The expression that defines the sort key</param>
241 /// <returns>A new sort clause with the given sort key and ascending sort order</returns>
242 /// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
243 /// <exception cref="ArgumentException"><paramref name="key"/> does not have an order-comparable result type</exception>
244 public static DbSortClause ToSortClause(this DbExpression key)
246 ArgumentValidation.ValidateSortClause(key);
247 return new DbSortClause(key, true, String.Empty);
250 /// <summary>
251 /// Creates a new <see cref="DbSortClause"/> with a descending sort order and default collation
252 /// </summary>
253 /// <param name="key">The expression that defines the sort key</param>
254 /// <returns>A new sort clause with the given sort key and descending sort order</returns>
255 /// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
256 /// <exception cref="ArgumentException"><paramref name="key"/> does not have an order-comparable result type</exception>
257 public static DbSortClause ToSortClauseDescending(this DbExpression key)
259 ArgumentValidation.ValidateSortClause(key);
260 return new DbSortClause(key, false, String.Empty);
263 /// <summary>
264 /// Creates a new <see cref="DbSortClause"/> with an ascending sort order and the specified collation
265 /// </summary>
266 /// <param name="key">The expression that defines the sort key</param>
267 /// <param name="collation">The collation to sort under</param>
268 /// <returns>A new sort clause with the given sort key and collation, and ascending sort order</returns>
269 /// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
270 /// <exception cref="ArgumentOutOfRangeException"><paramref name="collation"/> is empty or contains only space characters</exception>
271 /// <exception cref="ArgumentException"><paramref name="key"/> does not have an order-comparable result type</exception>
272 public static DbSortClause ToSortClause(this DbExpression key, string collation)
274 ArgumentValidation.ValidateSortClause(key, collation);
275 return new DbSortClause(key, true, collation);
278 /// <summary>
279 /// Creates a new <see cref="DbSortClause"/> with a descending sort order and the specified collation
280 /// </summary>
281 /// <param name="key">The expression that defines the sort key</param>
282 /// <param name="collation">The collation to sort under</param>
283 /// <returns>A new sort clause with the given sort key and collation, and descending sort order</returns>
284 /// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
285 /// <exception cref="ArgumentOutOfRangeException"><paramref name="collation"/> is empty or contains only space characters</exception>
286 /// <exception cref="ArgumentException"><paramref name="key"/> does not have an order-comparable result type</exception>
287 public static DbSortClause ToSortClauseDescending(this DbExpression key, string collation)
289 ArgumentValidation.ValidateSortClause(key, collation);
290 return new DbSortClause(key, false, collation);
293 #endregion
295 #region Binding-based methods: All, Any, Cross|OuterApply, Cross|FullOuter|Inner|LeftOuterJoin, Filter, GroupBy, Project, Skip, Sort
297 /// <summary>
298 /// Creates a new <see cref="DbQuantifierExpression"/> that determines whether the given predicate holds for all elements of the input set.
299 /// </summary>
300 /// <param name="input">An expression binding that specifies the input set.</param>
301 /// <param name="predicate">An expression representing a predicate to evaluate for each member of the input set.</param>
302 /// <returns>A new DbQuantifierExpression that represents the All operation.</returns>
303 /// <exception cref="ArgumentNullException"><paramref name="input"/> or <paramref name="predicate"/> is null</exception>
304 /// <exception cref="ArgumentException">
305 /// <paramref name="predicate"/> does not have a Boolean result type.
306 /// </exception>
307 public static DbQuantifierExpression All(this DbExpressionBinding input, DbExpression predicate)
309 TypeUsage booleanResultType = ArgumentValidation.ValidateQuantifier(input, predicate);
310 return new DbQuantifierExpression(DbExpressionKind.All, booleanResultType, input, predicate);
313 /// <summary>
314 /// Creates a new <see cref="DbQuantifierExpression"/> that determines whether the given predicate holds for any element of the input set.
315 /// </summary>
316 /// <param name="input">An expression binding that specifies the input set.</param>
317 /// <param name="predicate">An expression representing a predicate to evaluate for each member of the input set.</param>
318 /// <returns>A new DbQuantifierExpression that represents the Any operation.</returns>
319 /// <exception cref="ArgumentNullException"><paramref name="input"/> or <paramref name="predicate"/> is null</exception>
320 /// <exception cref="ArgumentException">
321 /// <paramref name="predicate"/> does not have a Boolean result type.
322 /// </exception>
323 public static DbQuantifierExpression Any(this DbExpressionBinding input, DbExpression predicate)
325 TypeUsage booleanResultType = ArgumentValidation.ValidateQuantifier(input, predicate);
326 return new DbQuantifierExpression(DbExpressionKind.Any, booleanResultType, input, predicate);
329 /// <summary>
330 /// Creates a new <see cref="DbApplyExpression"/> that evaluates the given <paramref name="apply"/> expression once for each element of a given input set,
331 /// producing a collection of rows with corresponding input and apply columns. Rows for which <paramref name="apply"/> evaluates to an empty set are not included.
332 /// </summary>
333 /// <param name="input">An <see cref="DbExpressionBinding"/> that specifies the input set.</param>
334 /// <param name="apply">An <see cref="DbExpressionBinding"/> that specifies logic to evaluate once for each member of the input set.</param>
335 /// <returns>An new DbApplyExpression with the specified input and apply bindings and an <see cref="DbExpressionKind"/> of CrossApply.</returns>
336 /// <exception cref="ArgumentNullException"><paramref name="input"/> or <paramref name="apply"/> is null</exception>
337 public static DbApplyExpression CrossApply(this DbExpressionBinding input, DbExpressionBinding apply)
339 TypeUsage resultType = ArgumentValidation.ValidateApply(input, apply);
340 return new DbApplyExpression(DbExpressionKind.CrossApply, resultType, input, apply);
343 /// <summary>
344 /// Creates a new <see cref="DbApplyExpression"/> that evaluates the given <paramref name="apply"/> expression once for each element of a given input set,
345 /// producing a collection of rows with corresponding input and apply columns. Rows for which <paramref name="apply"/> evaluates to an empty set have an apply column value of <code>null</code>.
346 /// </summary>
347 /// <param name="input">An <see cref="DbExpressionBinding"/> that specifies the input set.</param>
348 /// <param name="apply">An <see cref="DbExpressionBinding"/> that specifies logic to evaluate once for each member of the input set.</param>
349 /// <returns>An new DbApplyExpression with the specified input and apply bindings and an <see cref="DbExpressionKind"/> of OuterApply.</returns>
350 /// <exception cref="ArgumentNullException"><paramref name="input"/> or <paramref name="apply"/> is null</exception>
351 public static DbApplyExpression OuterApply(this DbExpressionBinding input, DbExpressionBinding apply)
353 TypeUsage resultType = ArgumentValidation.ValidateApply(input, apply);
354 return new DbApplyExpression(DbExpressionKind.OuterApply, resultType, input, apply);
357 /// <summary>
358 /// Creates a new <see cref="DbCrossJoinExpression"/> that unconditionally joins the sets specified by the list of input expression bindings.
359 /// </summary>
360 /// <param name="inputs">A list of expression bindings that specifies the input sets.</param>
361 /// <returns>A new DbCrossJoinExpression, with an <see cref="DbExpressionKind"/> of CrossJoin, that represents the unconditional join of the input sets.</returns>
362 /// <exception cref="ArgumentNullException"><paramref name="inputs"/> is null or contains null</exception>
363 /// <exception cref="ArgumentException">
364 /// <paramref name="inputs"/> contains fewer than 2 expression bindings.
365 /// </exception>
366 public static DbCrossJoinExpression CrossJoin(IEnumerable<DbExpressionBinding> inputs)
368 TypeUsage resultType;
369 System.Collections.ObjectModel.ReadOnlyCollection<DbExpressionBinding> validInputs = ArgumentValidation.ValidateCrossJoin(inputs, out resultType);
370 return new DbCrossJoinExpression(resultType, validInputs);
373 /// <summary>
374 /// Creates a new <see cref="DbJoinExpression"/> that joins the sets specified by the left and right
375 /// expression bindings, on the specified join condition, using InnerJoin as the <see cref="DbExpressionKind"/>.
376 /// </summary>
377 /// <param name="left">An <see cref="DbExpressionBinding"/> that specifies the left set argument.</param>
378 /// <param name="right">An <see cref="DbExpressionBinding"/> that specifies the right set argument.</param>
379 /// <param name="joinCondition">An expression that specifies the condition on which to join.</param>
380 /// <returns>
381 /// A new DbJoinExpression, with an <see cref="DbExpressionKind"/> of InnerJoin, that represents the inner join operation applied to the left and right
382 /// input sets under the given join condition.
383 /// </returns>
384 /// <exception cref="ArgumentNullException">
385 /// <paramref name="left"/>, <paramref name="right"/> or <paramref name="joinCondition"/> is null.
386 /// </exception>
387 /// <exception cref="ArgumentException">
388 /// <paramref name="joinCondition"/> does not have a Boolean result type.
389 /// </exception>
390 public static DbJoinExpression InnerJoin(this DbExpressionBinding left, DbExpressionBinding right, DbExpression joinCondition)
392 TypeUsage resultType = ArgumentValidation.ValidateJoin(left, right, joinCondition);
393 return new DbJoinExpression(DbExpressionKind.InnerJoin, resultType, left, right, joinCondition);
396 /// <summary>
397 /// Creates a new <see cref="DbJoinExpression"/> that joins the sets specified by the left and right
398 /// expression bindings, on the specified join condition, using LeftOuterJoin as the <see cref="DbExpressionKind"/>.
399 /// </summary>
400 /// <param name="left">An <see cref="DbExpressionBinding"/> that specifies the left set argument.</param>
401 /// <param name="right">An <see cref="DbExpressionBinding"/> that specifies the right set argument.</param>
402 /// <param name="joinCondition">An expression that specifies the condition on which to join.</param>
403 /// <returns>
404 /// A new DbJoinExpression, with an <see cref="DbExpressionKind"/> of LeftOuterJoin, that represents the left outer join operation applied to the left and right
405 /// input sets under the given join condition.
406 /// </returns>
407 /// <exception cref="ArgumentNullException">
408 /// <paramref name="left"/>, <paramref name="right"/> or <paramref name="joinCondition"/> is null.
409 /// </exception>
410 /// <exception cref="ArgumentException">
411 /// <paramref name="joinCondition"/> does not have a Boolean result type.
412 /// </exception>
413 public static DbJoinExpression LeftOuterJoin(this DbExpressionBinding left, DbExpressionBinding right, DbExpression joinCondition)
415 TypeUsage resultType = ArgumentValidation.ValidateJoin(left, right, joinCondition);
416 return new DbJoinExpression(DbExpressionKind.LeftOuterJoin, resultType, left, right, joinCondition);
419 /// <summary>
420 /// Creates a new <see cref="DbJoinExpression"/> that joins the sets specified by the left and right
421 /// expression bindings, on the specified join condition, using FullOuterJoin as the <see cref="DbExpressionKind"/>.
422 /// </summary>
423 /// <param name="left">An <see cref="DbExpressionBinding"/> that specifies the left set argument.</param>
424 /// <param name="right">An <see cref="DbExpressionBinding"/> that specifies the right set argument.</param>
425 /// <param name="joinCondition">An expression that specifies the condition on which to join.</param>
426 /// <returns>
427 /// A new DbJoinExpression, with an <see cref="DbExpressionKind"/> of FullOuterJoin, that represents the full outer join operation applied to the left and right
428 /// input sets under the given join condition.
429 /// </returns>
430 /// <exception cref="ArgumentNullException">
431 /// <paramref name="left"/>, <paramref name="right"/> or <paramref name="joinCondition"/> is null.
432 /// </exception>
433 /// <exception cref="ArgumentException">
434 /// <paramref name="joinCondition"/> does not have a Boolean result type.
435 /// </exception>
436 public static DbJoinExpression FullOuterJoin(this DbExpressionBinding left, DbExpressionBinding right, DbExpression joinCondition)
438 TypeUsage resultType = ArgumentValidation.ValidateJoin(left, right, joinCondition);
439 return new DbJoinExpression(DbExpressionKind.FullOuterJoin, resultType, left, right, joinCondition);
442 /// <summary>
443 /// Creates a new <see cref="DbFilterExpression"/> that filters the elements in the given input set using the specified predicate.
444 /// </summary>
445 /// <param name="input">An expression binding that specifies the input set.</param>
446 /// <param name="predicate">An expression representing a predicate to evaluate for each member of the input set.</param>
447 /// <returns>A new DbFilterExpression that produces the filtered set.</returns>
448 /// <exception cref="ArgumentNullException"><paramref name="input"/> or <paramref name="predicate"/> is null</exception>
449 /// <exception cref="ArgumentException">
450 /// <paramref name="predicate"/> does not have a Boolean result type.
451 /// </exception>
452 public static DbFilterExpression Filter(this DbExpressionBinding input, DbExpression predicate)
454 TypeUsage resultType = ArgumentValidation.ValidateFilter(input, predicate);
455 return new DbFilterExpression(resultType, input, predicate);
458 /// <summary>
459 /// Creates a new <see cref="DbGroupByExpression"/> that groups the elements of the input set according to the specified group keys and applies the given aggregates.
460 /// </summary>
461 /// <param name="input">A <see cref="DbGroupExpressionBinding"/> that specifies the input set.</param>
462 /// <param name="keys">A list of string-expression pairs that define the grouping columns.</param>
463 /// <param name="aggregates">A list of expressions that specify aggregates to apply.</param>
464 /// <returns>A new DbGroupByExpression with the specified input set, grouping keys and aggregates.</returns>
465 /// <exception cref="ArgumentNullException">
466 /// <paramref name="input"/>, <paramref name="keys"/> or <paramref name="aggregates"/> is null,
467 /// <paramref name="keys"/> contains a null key column name or expression, or
468 /// <paramref name="aggregates"/> contains a null aggregate column name or aggregate.
469 /// </exception>
470 /// <exception cref="ArgumentException">
471 /// Both <paramref name="keys"/> and <paramref name="aggregates"/> are empty,
472 /// or an invalid or duplicate column name was specified.
473 /// </exception>
474 /// <remarks>
475 /// DbGroupByExpression allows either the list of keys or the list of aggregates to be empty, but not both.
476 /// </remarks>
477 public static DbGroupByExpression GroupBy(this DbGroupExpressionBinding input, IEnumerable<KeyValuePair<string, DbExpression>> keys, IEnumerable<KeyValuePair<string, DbAggregate>> aggregates)
479 DbExpressionList validKeys;
480 System.Collections.ObjectModel.ReadOnlyCollection<DbAggregate> validAggregates;
481 TypeUsage resultType = ArgumentValidation.ValidateGroupBy(input, keys, aggregates, out validKeys, out validAggregates);
482 return new DbGroupByExpression(resultType, input, validKeys, validAggregates);
485 /// <summary>
486 /// Creates a new <see cref="DbProjectExpression"/> that projects the specified expression over the given input set.
487 /// </summary>
488 /// <param name="input">An expression binding that specifies the input set.</param>
489 /// <param name="projection">An expression to project over the set.</param>
490 /// <returns>A new DbProjectExpression that represents the projection operation.</returns>
491 /// <exception cref="ArgumentNullException"><paramref name="input"/> or <paramref name="projection"/> is null</exception>
492 public static DbProjectExpression Project(this DbExpressionBinding input, DbExpression projection)
494 TypeUsage resultType = ArgumentValidation.ValidateProject(input, projection);
495 return new DbProjectExpression(resultType, input, projection);
498 /// <summary>
499 /// Creates a new <see cref="DbSkipExpression"/> that sorts the given input set by the given sort specifications before skipping the specified number of elements.
500 /// </summary>
501 /// <param name="input">An expression binding that specifies the input set.</param>
502 /// <param name="sortOrder">A list of sort specifications that determine how the elements of the input set should be sorted.</param>
503 /// <param name="count">An expression the specifies how many elements of the ordered set to skip.</param>
504 /// <returns>A new DbSkipExpression that represents the skip operation.</returns>
505 /// <exception cref="ArgumentNullException">
506 /// <paramref name="input"/>, <paramref name="sortOrder"/> or <paramref name="count"/> is null,
507 /// or <paramref name="sortOrder"/> contains null.
508 /// </exception>
509 /// <exception cref="ArgumentException">
510 /// <paramref name="sortOrder"/> is empty,
511 /// or <paramref name="count"/> is not <see cref="DbConstantExpression"/> or <see cref="DbParameterReferenceExpression"/> or has a
512 /// result type that is not equal or promotable to a 64-bit integer type.
513 /// </exception>
514 public static DbSkipExpression Skip(this DbExpressionBinding input, IEnumerable<DbSortClause> sortOrder, DbExpression count)
516 System.Collections.ObjectModel.ReadOnlyCollection<DbSortClause> validSortOrder = ArgumentValidation.ValidateSkip(input, sortOrder, count);
517 return new DbSkipExpression(input.Expression.ResultType, input, validSortOrder, count);
520 /// <summary>
521 /// Creates a new <see cref="DbSortExpression"/> that sorts the given input set by the specified sort specifications.
522 /// </summary>
523 /// <param name="input">An expression binding that specifies the input set.</param>
524 /// <param name="sortOrder">A list of sort specifications that determine how the elements of the input set should be sorted.</param>
525 /// <returns>A new DbSortExpression that represents the sort operation.</returns>
526 /// <exception cref="ArgumentNullException">
527 /// <paramref name="input"/> or <paramref name="sortOrder"/> is null,
528 /// or <paramref name="sortOrder"/> contains null.
529 /// </exception>
530 /// <exception cref="ArgumentException">
531 /// <paramref name="sortOrder"/> is empty.
532 /// </exception>
533 public static DbSortExpression Sort(this DbExpressionBinding input, IEnumerable<DbSortClause> sortOrder)
535 System.Collections.ObjectModel.ReadOnlyCollection<DbSortClause> validSortOrder = ArgumentValidation.ValidateSort(input, sortOrder);
536 return new DbSortExpression(input.Expression.ResultType, input, validSortOrder);
539 #endregion
541 #region Leaf Expressions - Null, Constant, Parameter, Scan
543 #if DBEXPRESSIONBUILDER_NULLCONSTANTS
544 // Binary
545 public static DbNullExpression NullBinary { get { return _binaryNull; } }
546 // Boolean
547 public static DbNullExpression NullBoolean { get { return _boolNull; } }
548 // Byte
549 public static DbNullExpression NullByte { get { return _byteNull; } }
550 // DateTime
551 public static DbNullExpression NullDateTime { get { return _dateTimeNull; } }
552 // DateTimeOffset
553 public static DbNullExpression NullDateTimeOffset { get { return _dateTimeOffsetNull; } }
554 // Decimal
555 public static DbNullExpression NullDecimal { get { return _decimalNull; } }
556 // Double
557 public static DbNullExpression NullDouble { get { return _doubleNull; } }
558 // Guid
559 public static DbNullExpression NullGuid { get { return _guidNull; } }
560 // Int16
561 public static DbNullExpression NullInt16 { get { return _int16Null; } }
562 // Int32
563 public static DbNullExpression NullInt32 { get { return _int32Null; } }
564 // Int64
565 public static DbNullExpression NullInt64 { get { return _int64Null; } }
566 // SByte
567 public static DbNullExpression NullSByte { get { return _sbyteNull; } }
568 // Single
569 public static DbNullExpression NullSingle { get { return _singleNull; } }
570 // String
571 public static DbNullExpression NullString { get { return _stringNull; } }
572 // Time
573 public static DbNullExpression NullTime { get { return _timeNull; } }
574 #endif
576 /// <summary>
577 /// Creates a new <see cref="DbNullExpression"/>, which represents a typed null value.
578 /// </summary>
579 /// <param name="nullType">The type of the null value.</param>
580 /// <returns>An instance of DbNullExpression</returns>
581 /// <exception cref="ArgumentNullException"><paramref name="nullType"/> is null</exception>
582 public static DbNullExpression Null(this TypeUsage nullType)
584 ArgumentValidation.ValidateNull(nullType);
585 return new DbNullExpression(nullType);
588 /// <summary>
589 /// Creates a <see cref="DbConstantExpression"/> with the Boolean value <code>true</code>.
590 /// </summary>
591 /// <returns>A DbConstantExpression with the Boolean value true.</returns>
592 public static DbConstantExpression True { get { return _boolTrue; } }
594 /// <summary>
595 /// Creates a <see cref="DbConstantExpression"/> with the Boolean value <code>false</code>.
596 /// </summary>
597 /// <returns>A DbConstantExpression with the Boolean value false.</returns>
598 public static DbConstantExpression False { get { return _boolFalse; } }
600 /// <summary>
601 /// Creates a new <see cref="DbConstantExpression"/> with the given constant value.
602 /// </summary>
603 /// <param name="value">The constant value to represent.</param>
604 /// <returns>A new DbConstantExpression with the given value.</returns>
605 /// <exception cref="ArgumentNullException"><paramref name="value"/> is null</exception>
606 /// <exception cref="ArgumentException"><paramref name="value"/> is not an instance of a valid constant type</exception>
607 public static DbConstantExpression Constant(object value)
609 TypeUsage constantType = ArgumentValidation.ValidateConstant(value);
610 return new DbConstantExpression(constantType, value);
613 /// <summary>
614 /// Creates a new <see cref="DbConstantExpression"/> of the specified primitive type with the given constant value.
615 /// </summary>
616 /// <param name="constantType">The type of the constant value.</param>
617 /// <param name="value">The constant value to represent.</param>
618 /// <returns>A new DbConstantExpression with the given value and a result type of <paramref name="constantType"/>.</returns>
619 /// <exception cref="ArgumentNullException"><paramref name="value"/> or <paramref name="constantType"/> is null</exception>
620 /// <exception cref="ArgumentException">
621 /// <paramref name="value"/> is not an instance of a valid constant type,
622 /// <paramref name="constantType"/> does not represent a primitive type, or
623 /// <paramref name="value"/> is of a different primitive type than that represented by <paramref name="constantType"/>
624 /// </exception>
625 public static DbConstantExpression Constant(this TypeUsage constantType, object value)
627 ArgumentValidation.ValidateConstant(constantType, value);
628 return new DbConstantExpression(constantType, value);
631 /// <summary>
632 /// Creates a new <see cref="DbParameterReferenceExpression"/> that references a parameter with the specified name and type.
633 /// </summary>
634 /// <param name="type">The type of the referenced parameter</param>
635 /// <param name="name">The name of the referenced parameter</param>
636 /// <returns>
637 /// A DbParameterReferenceExpression that represents a reference to a parameter with the specified name and type;
638 /// the result type of the expression will be the same as <paramref name="type"/>.
639 /// </returns>
640 public static DbParameterReferenceExpression Parameter(this TypeUsage type, string name)
642 ArgumentValidation.ValidateParameter(type, name);
643 return new DbParameterReferenceExpression(type, name);
646 /// <summary>
647 /// Creates a new <see cref="DbVariableReferenceExpression"/> that references a variable with the specified name and type.
648 /// </summary>
649 /// <param name="type">The type of the referenced variable</param>
650 /// <param name="name">The name of the referenced variable</param>
651 /// <returns>
652 /// A DbVariableReferenceExpression that represents a reference to a variable with the specified name and type;
653 /// the result type of the expression will be the same as <paramref name="type"/>.
654 /// </returns>
655 public static DbVariableReferenceExpression Variable(this TypeUsage type, string name)
657 ArgumentValidation.ValidateVariable(type, name);
658 return new DbVariableReferenceExpression(type, name);
661 /// <summary>
662 /// Creates a new <see cref="DbScanExpression"/> that references the specified entity or relationship set.
663 /// </summary>
664 /// <param name="targetSet">Metadata for the entity or relationship set to reference.</param>
665 /// <returns>A new DbScanExpression based on the specified entity or relationship set.</returns>
666 /// <exception cref="ArgumentNullException"><paramref name="targetSet"/> is null</exception>
667 public static DbScanExpression Scan(this EntitySetBase targetSet)
669 TypeUsage resultType = ArgumentValidation.ValidateScan(targetSet);
670 return new DbScanExpression(resultType, targetSet);
673 #endregion
675 #region Boolean Operators - And, Or, Not
677 /// <summary>
678 /// Creates an <see cref="DbAndExpression"/> that performs the logical And of the left and right arguments.
679 /// </summary>
680 /// <param name="left">A Boolean expression that specifies the left argument.</param>
681 /// <param name="right">A Boolean expression that specifies the right argument.</param>
682 /// <returns>A new DbAndExpression with the specified arguments.</returns>
683 /// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
684 /// <exception cref="ArgumentException">
685 /// <paramref name="left"/> or <paramref name="right"/> does not have a Boolean result type.
686 /// </exception>
687 public static DbAndExpression And(this DbExpression left, DbExpression right)
689 TypeUsage resultType = ArgumentValidation.ValidateAnd(left, right);
690 return new DbAndExpression(resultType, left, right);
693 /// <summary>
694 /// Creates an <see cref="DbOrExpression"/> that performs the logical Or of the left and right arguments.
695 /// </summary>
696 /// <param name="left">A Boolean expression that specifies the left argument.</param>
697 /// <param name="right">A Boolean expression that specifies the right argument.</param>
698 /// <returns>A new DbOrExpression with the specified arguments.</returns>
699 /// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
700 /// <exception cref="ArgumentException">
701 /// <paramref name="left"/> or <paramref name="right"/> does not have a Boolean result type.
702 /// </exception>
703 public static DbOrExpression Or(this DbExpression left, DbExpression right)
705 TypeUsage resultType = ArgumentValidation.ValidateOr(left, right);
706 return new DbOrExpression(resultType, left, right);
709 /// <summary>
710 /// Creates a <see cref="DbNotExpression"/> that performs the logical negation of the given argument.
711 /// </summary>
712 /// <param name="argument">A Boolean expression that specifies the argument.</param>
713 /// <returns>A new DbNotExpression with the specified argument.</returns>
714 /// <exception cref="ArgumentNullException"><paramref name="argument"/> is null</exception>
715 /// <exception cref="ArgumentException">
716 /// <paramref name="argument"/> does not have a Boolean result type.
717 /// </exception>
718 public static DbNotExpression Not(this DbExpression argument)
720 TypeUsage resultType = ArgumentValidation.ValidateNot(argument);
721 return new DbNotExpression(resultType, argument);
724 #endregion
726 #region Arithmetic Operators - Divide, Minus, Modulo, Multiply, Plus, UnaryMinus
728 private static DbArithmeticExpression CreateArithmetic(DbExpressionKind kind, DbExpression left, DbExpression right)
730 TypeUsage numericResultType;
731 DbExpressionList arguments = ArgumentValidation.ValidateArithmetic(left, right, out numericResultType);
732 return new DbArithmeticExpression(kind, numericResultType, arguments);
735 /// <summary>
736 /// Creates a new <see cref="DbArithmeticExpression"/> that divides the left argument by the right argument.
737 /// </summary>
738 /// <param name="left">An expression that specifies the left argument.</param>
739 /// <param name="right">An expression that specifies the right argument.</param>
740 /// <returns>A new DbArithmeticExpression representing the division operation.</returns>
741 /// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
742 /// <exception cref="ArgumentException">
743 /// No common numeric result type exists between <paramref name="left"/> and <paramref name="right"/>.
744 /// </exception>
745 public static DbArithmeticExpression Divide(this DbExpression left, DbExpression right)
747 return CreateArithmetic(DbExpressionKind.Divide, left, right);
750 /// <summary>
751 /// Creates a new <see cref="DbArithmeticExpression"/> that subtracts the right argument from the left argument.
752 /// </summary>
753 /// <param name="left">An expression that specifies the left argument.</param>
754 /// <param name="right">An expression that specifies the right argument.</param>
755 /// <returns>A new DbArithmeticExpression representing the subtraction operation.</returns>
756 /// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
757 /// <exception cref="ArgumentException">
758 /// No common numeric result type exists between <paramref name="left"/> and <paramref name="right"/>.
759 /// </exception>
760 public static DbArithmeticExpression Minus(this DbExpression left, DbExpression right)
762 return CreateArithmetic(DbExpressionKind.Minus, left, right);
765 /// <summary>
766 /// Creates a new <see cref="DbArithmeticExpression"/> that computes the remainder of the left argument divided by the right argument.
767 /// </summary>
768 /// <param name="left">An expression that specifies the left argument.</param>
769 /// <param name="right">An expression that specifies the right argument.</param>
770 /// <returns>A new DbArithmeticExpression representing the modulo operation.</returns>
771 /// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
772 /// <exception cref="ArgumentException">
773 /// No common numeric result type exists between <paramref name="left"/> and <paramref name="right"/>.
774 /// </exception>
775 public static DbArithmeticExpression Modulo(this DbExpression left, DbExpression right)
777 return CreateArithmetic(DbExpressionKind.Modulo, left, right);
780 /// <summary>
781 /// Creates a new <see cref="DbArithmeticExpression"/> that multiplies the left argument by the right argument.
782 /// </summary>
783 /// <param name="left">An expression that specifies the left argument.</param>
784 /// <param name="right">An expression that specifies the right argument.</param>
785 /// <returns>A new DbArithmeticExpression representing the multiplication operation.</returns>
786 /// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
787 /// <exception cref="ArgumentException">
788 /// No common numeric result type exists between <paramref name="left"/> and <paramref name="right"/>.
789 /// </exception>
790 public static DbArithmeticExpression Multiply(this DbExpression left, DbExpression right)
792 return CreateArithmetic(DbExpressionKind.Multiply, left, right);
795 /// <summary>
796 /// Creates a new <see cref="DbArithmeticExpression"/> that adds the left argument to the right argument.
797 /// </summary>
798 /// <param name="left">An expression that specifies the left argument.</param>
799 /// <param name="right">An expression that specifies the right argument.</param>
800 /// <returns>A new DbArithmeticExpression representing the addition operation.</returns>
801 /// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
802 /// <exception cref="ArgumentException">
803 /// No common numeric result type exists between <paramref name="left"/> and <paramref name="right"/>.
804 /// </exception>
805 public static DbArithmeticExpression Plus(this DbExpression left, DbExpression right)
807 return CreateArithmetic(DbExpressionKind.Plus, left, right);
810 /// <summary>
811 /// Creates a new <see cref="DbArithmeticExpression"/> that negates the value of the argument.
812 /// </summary>
813 /// <param name="argument">An expression that specifies the argument.</param>
814 /// <returns>A new DbArithmeticExpression representing the negation operation.</returns>
815 /// <exception cref="ArgumentNullException"><paramref name="argument"/> is null</exception>
816 /// <exception cref="ArgumentException">
817 /// No numeric result type exists for <paramref name="argument"/>.
818 /// </exception>
819 public static DbArithmeticExpression UnaryMinus(this DbExpression argument)
821 TypeUsage resultType;
822 DbExpressionList args = ArgumentValidation.ValidateArithmetic(argument, out resultType);
823 return new DbArithmeticExpression(DbExpressionKind.UnaryMinus, resultType, args);
826 /// <summary>
827 /// Creates a new <see cref="DbArithmeticExpression"/> that negates the value of the argument.
828 /// </summary>
829 /// <param name="argument">An expression that specifies the argument.</param>
830 /// <returns>A new DbArithmeticExpression representing the negation operation.</returns>
831 /// <exception cref="ArgumentNullException"><paramref name="argument"/> is null</exception>
832 /// <exception cref="ArgumentException">
833 /// No numeric result type exists for <paramref name="argument"/>.
834 /// </exception>
835 public static DbArithmeticExpression Negate(this DbExpression argument)
837 return DbExpressionBuilder.UnaryMinus(argument);
840 #endregion
842 #region Comparison Operators - Equal, NotEqual, GreaterThan, LessThan, GreaterThanEqual, LessThanEqual, IsNull, Like
844 private static DbComparisonExpression CreateComparison(DbExpressionKind kind, DbExpression left, DbExpression right)
846 TypeUsage resultType = ArgumentValidation.ValidateComparison(kind, left, right);
847 return new DbComparisonExpression(kind, resultType, left, right);
850 /// <summary>
851 /// Creates a new <see cref="DbComparisonExpression"/> that compares the left and right arguments for equality.
852 /// </summary>
853 /// <param name="left">An expression that specifies the left argument.</param>
854 /// <param name="right">An expression that specifies the right argument.</param>
855 /// <returns>A new DbComparisonExpression representing the equality comparison.</returns>
856 /// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
857 /// <exception cref="ArgumentException">
858 /// No common equality-comparable result type exists between <paramref name="left"/> and <paramref name="right"/>.
859 /// </exception>
860 public static DbComparisonExpression Equal(this DbExpression left, DbExpression right)
862 return DbExpressionBuilder.CreateComparison(DbExpressionKind.Equals, left, right);
865 /// <summary>
866 /// Creates a new <see cref="DbComparisonExpression"/> that compares the left and right arguments for inequality.
867 /// </summary>
868 /// <param name="left">An expression that specifies the left argument.</param>
869 /// <param name="right">An expression that specifies the right argument.</param>
870 /// <returns>A new DbComparisonExpression representing the inequality comparison.</returns>
871 /// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
872 /// <exception cref="ArgumentException">
873 /// No common equality-comparable result type exists between <paramref name="left"/> and <paramref name="right"/>.
874 /// </exception>
875 public static DbComparisonExpression NotEqual(this DbExpression left, DbExpression right)
877 return DbExpressionBuilder.CreateComparison(DbExpressionKind.NotEquals, left, right);
880 /// <summary>
881 /// Creates a new <see cref="DbComparisonExpression"/> that determines whether the left argument is greater than the right argument.
882 /// </summary>
883 /// <param name="left">An expression that specifies the left argument.</param>
884 /// <param name="right">An expression that specifies the right argument.</param>
885 /// <returns>A new DbComparisonExpression representing the greater-than comparison.</returns>
886 /// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
887 /// <exception cref="ArgumentException">
888 /// No common order-comparable result type exists between <paramref name="left"/> and <paramref name="right"/>.
889 /// </exception>
890 public static DbComparisonExpression GreaterThan(this DbExpression left, DbExpression right)
892 return DbExpressionBuilder.CreateComparison(DbExpressionKind.GreaterThan, left, right);
895 /// <summary>
896 /// Creates a new <see cref="DbComparisonExpression"/> that determines whether the left argument is less than the right argument.
897 /// </summary>
898 /// <param name="left">An expression that specifies the left argument.</param>
899 /// <param name="right">An expression that specifies the right argument.</param>
900 /// <returns>A new DbComparisonExpression representing the less-than comparison.</returns>
901 /// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
902 /// <exception cref="ArgumentException">
903 /// No common order-comparable result type exists between <paramref name="left"/> and <paramref name="right"/>.
904 /// </exception>
905 public static DbComparisonExpression LessThan(this DbExpression left, DbExpression right)
907 return DbExpressionBuilder.CreateComparison(DbExpressionKind.LessThan, left, right);
910 /// <summary>
911 /// Creates a new <see cref="DbComparisonExpression"/> that determines whether the left argument is greater than or equal to the right argument.
912 /// </summary>
913 /// <param name="left">An expression that specifies the left argument.</param>
914 /// <param name="right">An expression that specifies the right argument.</param>
915 /// <returns>A new DbComparisonExpression representing the greater-than-or-equal-to comparison.</returns>
916 /// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
917 /// <exception cref="ArgumentException">
918 /// No common result type that is both equality- and order-comparable exists between <paramref name="left"/> and <paramref name="right"/>.
919 /// </exception>
920 public static DbComparisonExpression GreaterThanOrEqual(this DbExpression left, DbExpression right)
922 return DbExpressionBuilder.CreateComparison(DbExpressionKind.GreaterThanOrEquals, left, right);
925 /// <summary>
926 /// Creates a new <see cref="DbComparisonExpression"/> that determines whether the left argument is less than or equal to the right argument.
927 /// </summary>
928 /// <param name="left">An expression that specifies the left argument.</param>
929 /// <param name="right">An expression that specifies the right argument.</param>
930 /// <returns>A new DbComparisonExpression representing the less-than-or-equal-to comparison.</returns>
931 /// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
932 /// <exception cref="ArgumentException">
933 /// No common result type that is both equality- and order-comparable exists between <paramref name="left"/> and <paramref name="right"/>.
934 /// </exception>
935 public static DbComparisonExpression LessThanOrEqual(this DbExpression left, DbExpression right)
937 return DbExpressionBuilder.CreateComparison(DbExpressionKind.LessThanOrEquals, left, right);
940 /// <summary>
941 /// Creates a new <see cref="DbIsNullExpression"/> that determines whether the specified argument is null.
942 /// </summary>
943 /// <param name="argument">An expression that specifies the argument.</param>
944 /// <returns>A new DbIsNullExpression with the specified argument.</returns>
945 /// <exception cref="ArgumentNullException"><paramref name="argument"/> is null</exception>
946 /// <exception cref="ArgumentException"><paramref name="argument"/> has a collection result type.</exception>
947 public static DbIsNullExpression IsNull(this DbExpression argument)
949 TypeUsage resultType = ArgumentValidation.ValidateIsNull(argument);
950 return new DbIsNullExpression(resultType, argument, false);
953 /// <summary>
954 /// Creates a new <see cref="DbLikeExpression"/> that compares the specified input string to the given pattern.
955 /// </summary>
956 /// <param name="argument">An expression that specifies the input string.</param>
957 /// <param name="pattern">An expression that specifies the pattern string.</param>
958 /// <returns>A new DbLikeExpression with the specified input, pattern and a null escape.</returns>
959 /// <exception cref="ArgumentNullException"><paramref name="argument"/> or <paramref name="pattern"/> is null</exception>
960 /// <exception cref="ArgumentException"><paramref name="argument"/> or <paramref name="pattern"/> does not have a string result type.</exception>
961 public static DbLikeExpression Like(this DbExpression argument, DbExpression pattern)
963 TypeUsage resultType = ArgumentValidation.ValidateLike(argument, pattern);
964 DbExpression escape = DbExpressionBuilder.Null(pattern.ResultType);
965 return new DbLikeExpression(resultType, argument, pattern, escape);
968 /// <summary>
969 /// Creates a new <see cref="DbLikeExpression"/> that compares the specified input string to the given pattern using the optional escape.
970 /// </summary>
971 /// <param name="argument">An expression that specifies the input string.</param>
972 /// <param name="pattern">An expression that specifies the pattern string.</param>
973 /// <param name="escape">An optional expression that specifies the escape string.</param>
974 /// <returns>A new DbLikeExpression with the specified input, pattern and escape.</returns>
975 /// <exception cref="ArgumentNullException"><paramref name="argument"/>, <paramref name="pattern"/> or <paramref name="escape"/> is null</exception>
976 /// <exception cref="ArgumentException"><paramref name="argument"/>, <paramref name="pattern"/> or <paramref name="escape"/> does not have a string result type.</exception>
977 public static DbLikeExpression Like(this DbExpression argument, DbExpression pattern, DbExpression escape)
979 TypeUsage resultType = ArgumentValidation.ValidateLike(argument, pattern, escape);
980 return new DbLikeExpression(resultType, argument, pattern, escape);
983 #endregion
985 #region Type Operators - Cast, Treat, OfType, OfTypeOnly, IsOf, IsOfOnly
987 /// <summary>
988 /// Creates a new <see cref="DbCastExpression"/> that applies a cast operation to a polymorphic argument.
989 /// </summary>
990 /// <param name="argument">The argument to which the cast should be applied.</param>
991 /// <param name="toType">Type metadata that specifies the type to cast to.</param>
992 /// <returns>A new DbCastExpression with the specified argument and target type.</returns>
993 /// <exception cref="ArgumentNullException"><paramref name="argument"/> or <paramref name="toType"/> is null</exception>
994 /// <exception cref="ArgumentException">The specified cast is not valid.</exception>
995 public static DbCastExpression CastTo(this DbExpression argument, TypeUsage toType)
997 ArgumentValidation.ValidateCastTo(argument, toType);
998 return new DbCastExpression(toType, argument);
1001 /// <summary>
1002 /// Creates a new <see cref="DbTreatExpression"/>.
1003 /// </summary>
1004 /// <param name="argument">An expression that specifies the instance.</param>
1005 /// <param name="treatType">Type metadata for the treat-as type.</param>
1006 /// <returns>A new DbTreatExpression with the specified argument and type.</returns>
1007 /// <exception cref="ArgumentNullException"><paramref name="argument"/> or <paramref name="treatType"/> is null</exception>
1008 /// <exception cref="ArgumentException"><paramref name="treatType"/> is not in the same type hierarchy as the result type of <paramref name="argument"/>.
1009 /// </exception>
1010 /// <remarks>
1011 /// DbTreatExpression requires that <paramref name="argument"/> has a polymorphic result type,
1012 /// and that <paramref name="treatType"/> is a type from the same type hierarchy as that result type.
1013 /// </remarks>
1014 public static DbTreatExpression TreatAs(this DbExpression argument, TypeUsage treatType)
1016 ArgumentValidation.ValidateTreatAs(argument, treatType);
1017 return new DbTreatExpression(treatType, argument);
1020 /// <summary>
1021 /// Creates a new <see cref="DbOfTypeExpression"/> that produces a set consisting of the elements of the given input set that are of the specified type.
1022 /// </summary>
1023 /// <param name="argument">A <see cref="DbExpression"/> that specifies the input set.</param>
1024 /// <param name="type">Type metadata for the type that elements of the input set must have to be included in the resulting set.</param>
1025 /// <returns>A new DbOfTypeExpression with the specified set argument and type, and an ExpressionKind of <see cref="DbExpressionKind.OfType"/>.</returns>
1026 /// <exception cref="ArgumentNullException"><paramref name="argument"/> or <paramref name="type"/> is null</exception>
1027 /// <exception cref="ArgumentException">
1028 /// <paramref name="argument"/> does not have a collection result type, or
1029 /// <paramref name="type"/> is not a type in the same type hierarchy as the element type of the
1030 /// collection result type of <paramref name="argument"/>.
1031 /// </exception>
1032 /// <remarks>
1033 /// DbOfTypeExpression requires that <paramref name="argument"/> has a collection result type with
1034 /// a polymorphic element type, and that <paramref name="type"/> is a type from the same type hierarchy as that element type.
1035 /// </remarks>
1036 public static DbOfTypeExpression OfType(this DbExpression argument, TypeUsage type)
1038 TypeUsage collectionOfTypeResultType = ArgumentValidation.ValidateOfType(argument, type);
1039 return new DbOfTypeExpression(DbExpressionKind.OfType, collectionOfTypeResultType, argument, type);
1042 /// <summary>
1043 /// Creates a new <see cref="DbOfTypeExpression"/> that produces a set consisting of the elements of the given input set that are of exactly the specified type.
1044 /// </summary>
1045 /// <param name="argument">An <see cref="DbExpression"/> that specifies the input set.</param>
1046 /// <param name="type">Type metadata for the type that elements of the input set must match exactly to be included in the resulting set.</param>
1047 /// <returns>A new DbOfTypeExpression with the specified set argument and type, and an ExpressionKind of <see cref="DbExpressionKind.OfTypeOnly"/>.</returns>
1048 /// <exception cref="ArgumentNullException"><paramref name="argument"/> or <paramref name="type"/> is null</exception>
1049 /// <exception cref="ArgumentException">
1050 /// <paramref name="argument"/> does not have a collection result type, or
1051 /// <paramref name="type"/> is not a type in the same type hierarchy as the element type of the
1052 /// collection result type of <paramref name="argument"/>.
1053 /// </exception>
1054 /// <remarks>
1055 /// DbOfTypeExpression requires that <paramref name="argument"/> has a collection result type with
1056 /// a polymorphic element type, and that <paramref name="type"/> is a type from the same type hierarchy as that element type.
1057 /// </remarks>
1058 public static DbOfTypeExpression OfTypeOnly(this DbExpression argument, TypeUsage type)
1060 TypeUsage collectionOfTypeResultType = ArgumentValidation.ValidateOfType(argument, type);
1061 return new DbOfTypeExpression(DbExpressionKind.OfTypeOnly, collectionOfTypeResultType, argument, type);
1064 /// <summary>
1065 /// Creates a new <see cref="DbIsOfExpression"/> that determines whether the given argument is of the specified type or a subtype.
1066 /// </summary>
1067 /// <param name="argument">An expression that specifies the instance.</param>
1068 /// <param name="type">Type metadata that specifies the type that the instance's result type should be compared to.</param>
1069 /// <returns>A new DbIsOfExpression with the specified instance and type and DbExpressionKind IsOf.</returns>
1070 /// <exception cref="ArgumentNullException"><paramref name="argument"/> or <paramref name="type"/> is null</exception>
1071 /// <exception cref="ArgumentException">
1072 /// <paramref name="type"/> is not in the same type hierarchy as the result type of <paramref name="argument"/>.
1073 /// </exception>
1074 /// <remarks>
1075 /// DbIsOfExpression requires that <paramref name="argument"/> has a polymorphic result type,
1076 /// and that <paramref name="type"/> is a type from the same type hierarchy as that result type.
1077 /// </remarks>
1078 public static DbIsOfExpression IsOf(this DbExpression argument, TypeUsage type)
1080 TypeUsage booleanResultType = ArgumentValidation.ValidateIsOf(argument, type);
1081 return new DbIsOfExpression(DbExpressionKind.IsOf, booleanResultType, argument, type);
1084 /// <summary>
1085 /// Creates a new <see cref="DbIsOfExpression"/> expression that determines whether the given argument is of the specified type, and only that type (not a subtype).
1086 /// </summary>
1087 /// <param name="argument">An expression that specifies the instance.</param>
1088 /// <param name="type">Type metadata that specifies the type that the instance's result type should be compared to.</param>
1089 /// <returns>A new DbIsOfExpression with the specified instance and type and DbExpressionKind IsOfOnly.</returns>
1090 /// <exception cref="ArgumentNullException"><paramref name="argument"/> or <paramref name="type"/> is null</exception>
1091 /// <exception cref="ArgumentException">
1092 /// <paramref name="type"/> is not in the same type hierarchy as the result type of <paramref name="argument"/>.
1093 /// </exception>
1094 /// <remarks>
1095 /// DbIsOfExpression requires that <paramref name="argument"/> has a polymorphic result type,
1096 /// and that <paramref name="type"/> is a type from the same type hierarchy as that result type.
1097 /// </remarks>
1098 public static DbIsOfExpression IsOfOnly(this DbExpression argument, TypeUsage type)
1100 TypeUsage booleanResultType = ArgumentValidation.ValidateIsOf(argument, type);
1101 return new DbIsOfExpression(DbExpressionKind.IsOfOnly, booleanResultType, argument, type);
1104 #endregion
1106 #region Ref Operators - Deref, EntityRef, Ref, RefKey, RelationshipNavigation
1108 /// <summary>
1109 /// Creates a new <see cref="DbDerefExpression"/> that retrieves a specific Entity given a reference expression
1110 /// </summary>
1111 /// <param name="argument">An <see cref="DbExpression"/> that provides the reference. This expression must have a reference Type</param>
1112 /// <returns>A new DbDerefExpression that retrieves the specified Entity</returns>
1113 /// <exception cref="ArgumentNullException"><paramref name="argument"/> is null</exception>
1114 /// <exception cref="ArgumentException"><paramref name="argument"/> does not have a reference result type.</exception>
1115 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Deref")]
1116 public static DbDerefExpression Deref(this DbExpression argument)
1118 TypeUsage entityResultType = ArgumentValidation.ValidateDeref(argument);
1119 return new DbDerefExpression(entityResultType, argument);
1122 /// <summary>
1123 /// Creates a new <see cref="DbEntityRefExpression"/> that retrieves the ref of the specifed entity in structural form.
1124 /// </summary>
1125 /// <param name="argument">The expression that provides the entity. This expression must have an entity result type.</param>
1126 /// <returns>A new DbEntityRefExpression that retrieves a reference to the specified entity.</returns>
1127 /// <exception cref="ArgumentNullException"><paramref name="argument"/> is null</exception>
1128 /// <exception cref="ArgumentException"><paramref name="argument"/> does not have an entity result type.</exception>
1129 public static DbEntityRefExpression GetEntityRef(this DbExpression argument)
1131 TypeUsage refResultType = ArgumentValidation.ValidateGetEntityRef(argument);
1132 return new DbEntityRefExpression(refResultType, argument);
1135 /// <summary>
1136 /// Creates a new <see cref="DbRefExpression"/> that encodes a reference to a specific entity based on key values.
1137 /// </summary>
1138 /// <param name="entitySet">The entity set in which the referenced element resides.</param>
1139 /// <param name="keyValues">A collection of <see cref="DbExpression"/>s that provide the key values. These expressions must match (in number, type, and order) the key properties of the referenced entity type.</param>
1140 /// <returns>A new DbRefExpression that references the element with the specified key values in the given entity set.</returns>
1141 /// <exception cref="ArgumentNullException"><paramref name="entitySet"/> is null, or <paramref name="keyValues"/> is null or contains null.</exception>
1142 /// <exception cref="ArgumentException">
1143 /// The count of <paramref name="keyValues"/> does not match the count of key members declared by the <paramref name="entitySet"/>'s element type,
1144 /// or <paramref name="keyValues"/> contains an expression with a result type that is not compatible with the type of the corresponding key member.
1145 /// </exception>
1146 public static DbRefExpression CreateRef(this EntitySet entitySet, IEnumerable<DbExpression> keyValues)
1148 return CreateRefExpression(entitySet, keyValues);
1151 /// <summary>
1152 /// Creates a new <see cref="DbRefExpression"/> that encodes a reference to a specific entity based on key values.
1153 /// </summary>
1154 /// <param name="entitySet">The entity set in which the referenced element resides.</param>
1155 /// <param name="keyValues">A collection of <see cref="DbExpression"/>s that provide the key values. These expressions must match (in number, type, and order) the key properties of the referenced entity type.</param>
1156 /// <returns>A new DbRefExpression that references the element with the specified key values in the given entity set.</returns>
1157 /// <exception cref="ArgumentNullException"><paramref name="entitySet"/> is null, or <paramref name="keyValues"/> is null or contains null.</exception>
1158 /// <exception cref="ArgumentException">
1159 /// The count of <paramref name="keyValues"/> does not match the count of key members declared by the <paramref name="entitySet"/>'s element type,
1160 /// or <paramref name="keyValues"/> contains an expression with a result type that is not compatible with the type of the corresponding key member.
1161 /// </exception>
1162 public static DbRefExpression CreateRef(this EntitySet entitySet, params DbExpression[] keyValues)
1164 return CreateRefExpression(entitySet, keyValues);
1167 /// <summary>
1168 /// Creates a new <see cref="DbRefExpression"/> that encodes a reference to a specific entity of a given type based on key values.
1169 /// </summary>
1170 /// <param name="entitySet">The entity set in which the referenced element resides.</param>
1171 /// <param name="entityType">The specific type of the referenced entity. This must be an entity type from the same hierarchy as the entity set's element type.</param>
1172 /// <param name="keyValues">A collection of <see cref="DbExpression"/>s that provide the key values. These expressions must match (in number, type, and order) the key properties of the referenced entity type.</param>
1173 /// <returns>A new DbRefExpression that references the element with the specified key values in the given entity set.</returns>
1174 /// <exception cref="ArgumentNullException"><paramref name="entitySet"/> or <paramref name="entityType"/> is null, or <paramref name="keyValues"/> is null or contains null.</exception>
1175 /// <exception cref="ArgumentException"><paramref name="entityType"/> is not from the same type hierarchy (a subtype, supertype, or the same type) as <paramref name="entitySet"/>'s element type.</exception>
1176 /// <exception cref="ArgumentException">
1177 /// The count of <paramref name="keyValues"/> does not match the count of key members declared by the <paramref name="entitySet"/>'s element type,
1178 /// or <paramref name="keyValues"/> contains an expression with a result type that is not compatible with the type of the corresponding key member.
1179 /// </exception>
1180 public static DbRefExpression CreateRef(this EntitySet entitySet, EntityType entityType, IEnumerable<DbExpression> keyValues)
1182 return CreateRefExpression(entitySet, entityType, keyValues);
1185 /// <summary>
1186 /// Creates a new <see cref="DbRefExpression"/> that encodes a reference to a specific entity of a given type based on key values.
1187 /// </summary>
1188 /// <param name="entitySet">The entity set in which the referenced element resides.</param>
1189 /// <param name="entityType">The specific type of the referenced entity. This must be an entity type from the same hierarchy as the entity set's element type.</param>
1190 /// <param name="keyValues">A collection of <see cref="DbExpression"/>s that provide the key values. These expressions must match (in number, type, and order) the key properties of the referenced entity type.</param>
1191 /// <returns>A new DbRefExpression that references the element with the specified key values in the given entity set.</returns>
1192 /// <exception cref="ArgumentNullException"><paramref name="entitySet"/> or <paramref name="entityType"/> is null, or <paramref name="keyValues"/> is null or contains null.</exception>
1193 /// <exception cref="ArgumentException"><paramref name="entityType"/> is not from the same type hierarchy (a subtype, supertype, or the same type) as <paramref name="entitySet"/>'s element type.</exception>
1194 /// <exception cref="ArgumentException">
1195 /// The count of <paramref name="keyValues"/> does not match the count of key members declared by the <paramref name="entitySet"/>'s element type,
1196 /// or <paramref name="keyValues"/> contains an expression with a result type that is not compatible with the type of the corresponding key member.
1197 /// </exception>
1198 public static DbRefExpression CreateRef(this EntitySet entitySet, EntityType entityType, params DbExpression[] keyValues)
1200 return CreateRefExpression(entitySet, entityType, keyValues);
1203 private static DbRefExpression CreateRefExpression(EntitySet entitySet, IEnumerable<DbExpression> keyValues)
1205 DbExpression keyConstructor;
1206 TypeUsage refResultType = ArgumentValidation.ValidateCreateRef(entitySet, keyValues, out keyConstructor);
1207 return new DbRefExpression(refResultType, entitySet, keyConstructor);
1210 private static DbRefExpression CreateRefExpression(EntitySet entitySet, EntityType entityType, IEnumerable<DbExpression> keyValues)
1212 DbExpression keyConstructor;
1213 TypeUsage refResultType = ArgumentValidation.ValidateCreateRef(entitySet, entityType, keyValues, out keyConstructor);
1214 return new DbRefExpression(refResultType, entitySet, keyConstructor);
1217 /// <summary>
1218 /// Creates a new <see cref="DbRefExpression"/> that encodes a reference to a specific Entity based on key values.
1219 /// </summary>
1220 /// <param name="entitySet">The Entity set in which the referenced element resides.</param>
1221 /// <param name="keyRow">A <see cref="DbExpression"/> that constructs a record with columns that match (in number, type, and order) the Key properties of the referenced Entity type.</param>
1222 /// <returns>A new DbRefExpression that references the element with the specified key values in the given Entity set.</returns>
1223 /// <exception cref="ArgumentNullException"><paramref name="entitySet"/> or <paramref name="keyRow"/> is null</exception>
1224 /// <exception cref="ArgumentException">
1225 /// <paramref name="keyRow"/> does not have a record result type that matches the key properties of the referenced entity set's entity type.
1226 /// </exception>
1227 /// <remarks>
1228 /// <paramref name="keyRow"/> should be an expression that specifies the key values that identify the referenced entity within the given entity set.
1229 /// The result type of <paramref name="keyRow"/> should contain a corresponding column for each key property defined by <paramref name="entitySet"/>'s entity type.
1230 /// </remarks>
1231 public static DbRefExpression RefFromKey(this EntitySet entitySet, DbExpression keyRow)
1233 TypeUsage refResultType = ArgumentValidation.ValidateRefFromKey(entitySet, keyRow);
1234 return new DbRefExpression(refResultType, entitySet, keyRow);
1237 /// <summary>
1238 /// Creates a new <see cref="DbRefExpression"/> that encodes a reference to a specific Entity based on key values.
1239 /// </summary>
1240 /// <param name="entitySet">The Entity set in which the referenced element resides.</param>
1241 /// <param name="keyRow">A <see cref="DbExpression"/> that constructs a record with columns that match (in number, type, and order) the Key properties of the referenced Entity type.</param>
1242 /// <param name="entityType">The type of the Entity that the reference should refer to.</param>
1243 /// <returns>A new DbRefExpression that references the element with the specified key values in the given Entity set.</returns>
1244 /// <exception cref="ArgumentNullException"><paramref name="entitySet"/>, <paramref name="keyRow"/> or <paramref name="entityType"/> is null</exception>
1245 /// <exception cref="ArgumentException">
1246 /// <paramref name="entityType"/> is not in the same type hierarchy as the entity set's entity type, or <paramref name="keyRow"/> does not have a
1247 /// record result type that matches the key properties of the referenced entity set's entity type.
1248 /// </exception>
1249 /// <remarks>
1250 /// <paramref name="keyRow"/> should be an expression that specifies the key values that identify the referenced entity within the given entity set.
1251 /// The result type of <paramref name="keyRow"/> should contain a corresponding column for each key property defined by <paramref name="entitySet"/>'s entity type.
1252 /// </remarks>
1253 public static DbRefExpression RefFromKey(this EntitySet entitySet, DbExpression keyRow, EntityType entityType)
1255 TypeUsage refResultType = ArgumentValidation.ValidateRefFromKey(entitySet, keyRow, entityType);
1256 return new DbRefExpression(refResultType, entitySet, keyRow);
1259 /// <summary>
1260 /// Creates a new <see cref="DbRefKeyExpression"/> that retrieves the key values of the specifed reference in structural form.
1261 /// </summary>
1262 /// <param name="argument">The expression that provides the reference. This expression must have a reference Type with an Entity element type.</param>
1263 /// <returns>A new DbRefKeyExpression that retrieves the key values of the specified reference.</returns>
1264 /// <exception cref="ArgumentNullException"><paramref name="argument"/> is null</exception>
1265 /// <exception cref="ArgumentException"><paramref name="argument"/> does not have a reference result type.</exception>
1266 public static DbRefKeyExpression GetRefKey(this DbExpression argument)
1268 TypeUsage rowResultType = ArgumentValidation.ValidateGetRefKey(argument);
1269 return new DbRefKeyExpression(rowResultType, argument);
1272 /// <summary>
1273 /// Creates a new <see cref="DbRelationshipNavigationExpression"/> representing the navigation of a composition or association relationship.
1274 /// </summary>
1275 /// <param name="navigateFrom">An expression the specifies the instance from which navigation should occur</param>
1276 /// <param name="fromEnd">Metadata for the property that represents the end of the relationship from which navigation should occur</param>
1277 /// <param name="toEnd">Metadata for the property that represents the end of the relationship to which navigation should occur</param>
1278 /// <returns>A new DbRelationshipNavigationExpression representing the navigation of the specified from and to relation ends of the specified relation type from the specified navigation source instance</returns>
1279 /// <exception cref="ArgumentNullException"><paramref name="fromEnd"/>, <paramref name="toEnd"/> or <paramref name="navigateFrom"/> is null</exception>
1280 /// <exception cref="ArgumentException">
1281 /// <paramref name="fromEnd"/> and <paramref name="toEnd"/> are not declared by the same relationship type, or
1282 /// <paramref name="navigateFrom"/> has a result type that is not compatible with the property type of <paramref name="fromEnd"/>.
1283 /// </exception>
1284 /// <remarks>
1285 /// <see cref="DbRelationshipNavigationExpression"/> requires that navigation always occur from a reference, and so <paramref name="navigateFrom"/> must always have a reference result type.
1286 /// </remarks>
1287 public static DbRelationshipNavigationExpression Navigate(this DbExpression navigateFrom, RelationshipEndMember fromEnd, RelationshipEndMember toEnd)
1289 RelationshipType relType;
1290 TypeUsage resultType = ArgumentValidation.ValidateNavigate(navigateFrom, fromEnd, toEnd, out relType, allowAllRelationshipsInSameTypeHierarchy: false);
1291 return new DbRelationshipNavigationExpression(resultType, relType, fromEnd, toEnd, navigateFrom);
1294 /// <summary>
1295 /// Creates a new <see cref="DbRelationshipNavigationExpression"/> representing the navigation of a composition or association relationship.
1296 /// </summary>
1297 /// <param name="type">Metadata for the relation type that represents the relationship</param>
1298 /// <param name="fromEndName">The name of the property of the relation type that represents the end of the relationship from which navigation should occur</param>
1299 /// <param name="toEndName">The name of the property of the relation type that represents the end of the relationship to which navigation should occur</param>
1300 /// <param name="navigateFrom">An expression the specifies the instance from which naviagtion should occur</param>
1301 /// <returns>A new DbRelationshipNavigationExpression representing the navigation of the specified from and to relation ends of the specified relation type from the specified navigation source instance</returns>
1302 /// <exception cref="ArgumentNullException">
1303 /// <paramref name="type"/>, <paramref name="fromEndName"/>, <paramref name="toEndName"/> or <paramref name="navigateFrom"/> is null.
1304 /// </exception>
1305 /// <exception cref="ArgumentException">
1306 /// <paramref name="type"/> is not associated with this command tree's metadata workspace or <paramref name="navigateFrom"/> is associated with a different command tree,
1307 /// or <paramref name="type"/> does not declare a relation end property with name <paramref name="toEndName"/> or <paramref name="fromEndName"/>,
1308 /// or <paramref name="navigateFrom"/> has a result type that is not compatible with the property type of the relation end property with name <paramref name="fromEndName"/>.
1309 /// </exception>
1310 /// <remarks>
1311 /// <see cref="DbRelationshipNavigationExpression"/> requires that navigation always occur from a reference, and so <paramref name="navigateFrom"/> must always have a reference result type.
1312 /// </remarks>
1313 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
1314 public static DbRelationshipNavigationExpression Navigate(this RelationshipType type, string fromEndName, string toEndName, DbExpression navigateFrom)
1316 RelationshipEndMember fromEnd;
1317 RelationshipEndMember toEnd;
1318 TypeUsage resultType = ArgumentValidation.ValidateNavigate(navigateFrom, type, fromEndName, toEndName, out fromEnd, out toEnd);
1319 return new DbRelationshipNavigationExpression(resultType, type, fromEnd, toEnd, navigateFrom);
1322 #endregion
1324 #region Unary and Binary Set Operators - Distinct, Element, IsEmpty, Except, Intersect, UnionAll, Limit
1326 /// <summary>
1327 /// Creates a new <see cref="DbDistinctExpression"/> that removes duplicates from the given set argument.
1328 /// </summary>
1329 /// <param name="argument">An expression that defines the set over which to perfom the distinct operation.</param>
1330 /// <returns>A new DbDistinctExpression that represents the distinct operation applied to the specified set argument.</returns>
1331 /// <exception cref="ArgumentNullException"><paramref name="argument"/> is null</exception>
1332 /// <exception cref="ArgumentException"><paramref name="argument"/> does not have a collection result type.</exception>
1333 public static DbDistinctExpression Distinct(this DbExpression argument)
1335 TypeUsage resultType = ArgumentValidation.ValidateDistinct(argument);
1336 return new DbDistinctExpression(resultType, argument);
1339 /// <summary>
1340 /// Creates a new <see cref="DbElementExpression"/> that converts a set into a singleton.
1341 /// </summary>
1342 /// <param name="argument">An expression that specifies the input set.</param>
1343 /// <returns>A DbElementExpression that represents the conversion of the set argument to a singleton.</returns>
1344 /// <exception cref="ArgumentNullException"><paramref name="argument"/> is null</exception>
1345 /// <exception cref="ArgumentException"><paramref name="argument"/> does not have a collection result type.</exception>
1346 public static DbElementExpression Element(this DbExpression argument)
1348 TypeUsage resultType = ArgumentValidation.ValidateElement(argument);
1349 return new DbElementExpression(resultType, argument);
1352 /// <summary>
1353 /// Creates a new <see cref="DbIsEmptyExpression"/> that determines whether the specified set argument is an empty set.
1354 /// </summary>
1355 /// <param name="argument">An expression that specifies the input set</param>
1356 /// <returns>A new DbIsEmptyExpression with the specified argument.</returns>
1357 /// <exception cref="ArgumentNullException"><paramref name="argument"/> is null</exception>
1358 /// <exception cref="ArgumentException"><paramref name="argument"/> does not have a collection result type.</exception>
1359 public static DbIsEmptyExpression IsEmpty(this DbExpression argument)
1361 TypeUsage booleanResultType = ArgumentValidation.ValidateIsEmpty(argument);
1362 return new DbIsEmptyExpression(booleanResultType, argument);
1365 /// <summary>
1366 /// Creates a new <see cref="DbExceptExpression"/> that computes the subtraction of the right set argument from the left set argument.
1367 /// </summary>
1368 /// <param name="left">An expression that defines the left set argument.</param>
1369 /// <param name="right">An expression that defines the right set argument.</param>
1370 /// <returns>A new DbExceptExpression that represents the difference of the left argument from the right argument.</returns>
1371 /// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
1372 /// <exception cref="ArgumentException">No common collection result type exists between <paramref name="left"/> and <paramref name="right"/>.</exception>
1373 public static DbExceptExpression Except(this DbExpression left, DbExpression right)
1375 TypeUsage resultType = ArgumentValidation.ValidateExcept(left, right);
1376 return new DbExceptExpression(resultType, left, right);
1379 /// <summary>
1380 /// Creates a new <see cref="DbIntersectExpression"/> that computes the intersection of the left and right set arguments.
1381 /// </summary>
1382 /// <param name="left">An expression that defines the left set argument.</param>
1383 /// <param name="right">An expression that defines the right set argument.</param>
1384 /// <returns>A new DbIntersectExpression that represents the intersection of the left and right arguments.</returns>
1385 /// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
1386 /// <exception cref="ArgumentException">No common collection result type exists between <paramref name="left"/> and <paramref name="right"/>.</exception>
1387 public static DbIntersectExpression Intersect(this DbExpression left, DbExpression right)
1389 TypeUsage resultType = ArgumentValidation.ValidateIntersect(left, right);
1390 return new DbIntersectExpression(resultType, left, right);
1393 /// <summary>
1394 /// Creates a new <see cref="DbUnionAllExpression"/> that computes the union of the left and right set arguments and does not remove duplicates.
1395 /// </summary>
1396 /// <param name="left">An expression that defines the left set argument.</param>
1397 /// <param name="right">An expression that defines the right set argument.</param>
1398 /// <returns>A new DbUnionAllExpression that union, including duplicates, of the the left and right arguments.</returns>
1399 /// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
1400 /// <exception cref="ArgumentException">No common collection result type exists between <paramref name="left"/> and <paramref name="right"/>.</exception>
1401 public static DbUnionAllExpression UnionAll(this DbExpression left, DbExpression right)
1403 TypeUsage resultType = ArgumentValidation.ValidateUnionAll(left, right);
1404 return new DbUnionAllExpression(resultType, left, right);
1407 /// <summary>
1408 /// Creates a new <see cref="DbLimitExpression"/> that restricts the number of elements in the Argument collection to the specified count Limit value.
1409 /// Tied results are not included in the output.
1410 /// </summary>
1411 /// <param name="argument">An expression that specifies the input collection.</param>
1412 /// <param name="count">An expression that specifies the limit value.</param>
1413 /// <returns>A new DbLimitExpression with the specified argument and count limit values that does not include tied results.</returns>
1414 /// <exception cref="ArgumentNullException"><paramref name="argument"/> or <paramref name="count"/> is null</exception>
1415 /// <exception cref="ArgumentException">
1416 /// <paramref name="argument"/> does not have a collection result type,
1417 /// or <paramref name="count"/> does not have a result type that is equal or promotable to a 64-bit integer type.
1418 /// </exception>
1419 public static DbLimitExpression Limit(this DbExpression argument, DbExpression count)
1421 TypeUsage resultType = ArgumentValidation.ValidateLimit(argument, count);
1422 return new DbLimitExpression(resultType, argument, count, false);
1425 #endregion
1427 #region General Operators - Case, Function, NewInstance, Property
1429 /// <summary>
1430 /// Creates a new <see cref="DbCaseExpression"/>.
1431 /// </summary>
1432 /// <param name="whenExpressions">A list of expressions that provide the conditional for of each case.</param>
1433 /// <param name="thenExpressions">A list of expressions that provide the result of each case.</param>
1434 /// <param name="elseExpression">An expression that defines the result when no case is matched.</param>
1435 /// <returns>A new DbCaseExpression with the specified cases and default result.</returns>
1436 /// <exception cref="ArgumentNullException">
1437 /// <paramref name="whenExpressions"/> or <paramref name="thenExpressions"/> is null or contains null,
1438 /// or <paramref name="elseExpression"/> is null.
1439 /// </exception>
1440 /// <exception cref="ArgumentException">
1441 /// <paramref name="whenExpressions"/> or <paramref name="thenExpressions"/> is empty or <paramref name="whenExpressions"/> contains an expression with a non-Boolean result type, or
1442 /// No common result type exists for all expressions in <paramref name="thenExpressions"/> and <paramref name="elseExpression"/>.
1443 /// </exception>
1444 public static DbCaseExpression Case(IEnumerable<DbExpression> whenExpressions, IEnumerable<DbExpression> thenExpressions, DbExpression elseExpression)
1446 DbExpressionList validWhens;
1447 DbExpressionList validThens;
1448 TypeUsage resultType = ArgumentValidation.ValidateCase(whenExpressions, thenExpressions, elseExpression, out validWhens, out validThens);
1449 return new DbCaseExpression(resultType, validWhens, validThens, elseExpression);
1452 /// <summary>
1453 /// Creates a new <see cref="DbFunctionExpression"/> representing the invocation of the specified function with the given arguments.
1454 /// </summary>
1455 /// <param name="function">Metadata for the function to invoke.</param>
1456 /// <param name="arguments">A list of expressions that provide the arguments to the function.</param>
1457 /// <returns>A new DbFunctionExpression representing the function invocation.</returns>
1458 /// <exception cref="ArgumentNullException">
1459 /// <paramref name="function"/> is null, or <paramref name="arguments"/> is null or contains null.
1460 /// </exception>
1461 /// <exception cref="ArgumentException">
1462 /// The count of <paramref name="arguments"/> does not equal the number of parameters declared by <paramref name="function"/>,
1463 /// or <paramref name="arguments"/> contains an expression that has a result type that is not equal or promotable
1464 /// to the corresponding function parameter type.
1465 /// </exception>
1466 public static DbFunctionExpression Invoke(this EdmFunction function, IEnumerable<DbExpression> arguments)
1468 return InvokeFunction(function, arguments);
1471 /// <summary>
1472 /// Creates a new <see cref="DbFunctionExpression"/> representing the invocation of the specified function with the given arguments.
1473 /// </summary>
1474 /// <param name="function">Metadata for the function to invoke.</param>
1475 /// <param name="arguments">Expressions that provide the arguments to the function.</param>
1476 /// <returns>A new DbFunctionExpression representing the function invocation.</returns>
1477 /// <exception cref="ArgumentNullException">
1478 /// <paramref name="function"/> is null, or <paramref name="arguments"/> is null or contains null.
1479 /// </exception>
1480 /// <exception cref="ArgumentException">
1481 /// The count of <paramref name="arguments"/> does not equal the number of parameters declared by <paramref name="function"/>,
1482 /// or <paramref name="arguments"/> contains an expression that has a result type that is not equal or promotable
1483 /// to the corresponding function parameter type.
1484 /// </exception>
1485 public static DbFunctionExpression Invoke(this EdmFunction function, params DbExpression[] arguments)
1487 return InvokeFunction(function, arguments);
1490 private static DbFunctionExpression InvokeFunction(EdmFunction function, IEnumerable<DbExpression> arguments)
1492 DbExpressionList validArguments;
1493 TypeUsage resultType = ArgumentValidation.ValidateFunction(function, arguments, out validArguments);
1494 return new DbFunctionExpression(resultType, function, validArguments);
1497 /// <summary>
1498 /// Creates a new <see cref="DbLambdaExpression"/> representing the application of the specified Lambda function to the given arguments.
1499 /// </summary>
1500 /// <param name="lambda">A <see cref="DbLambda"/> instance representing the Lambda function to apply.</param>
1501 /// <param name="arguments">A list of expressions that provide the arguments.</param>
1502 /// <returns>A new DbLambdaExpression representing the Lambda function application.</returns>
1503 /// <exception cref="ArgumentNullException">
1504 /// <paramref name="lambda"/> is null, or <paramref name="arguments"/> is null or contains null.
1505 /// </exception>
1506 /// <exception cref="ArgumentException">
1507 /// The count of <paramref name="arguments"/> does not equal the number of variables declared by <paramref name="lambda"/>,
1508 /// or <paramref name="arguments"/> contains an expression that has a result type that is not equal or promotable
1509 /// to the corresponding variable type.
1510 /// </exception>
1511 public static DbLambdaExpression Invoke(this DbLambda lambda, IEnumerable<DbExpression> arguments)
1513 return InvokeLambda(lambda, arguments);
1516 /// <summary>
1517 /// Creates a new <see cref="DbLambdaExpression"/> representing the application of the specified Lambda function to the given arguments.
1518 /// </summary>
1519 /// <param name="lambda">A <see cref="DbLambda"/> instance representing the Lambda function to apply.</param>
1520 /// <param name="arguments">Expressions that provide the arguments.</param>
1521 /// <returns>A new DbLambdaExpression representing the Lambda function application.</returns>
1522 /// <exception cref="ArgumentNullException">
1523 /// <paramref name="lambda"/> is null, or <paramref name="arguments"/> is null or contains null.
1524 /// </exception>
1525 /// <exception cref="ArgumentException">
1526 /// The count of <paramref name="arguments"/> does not equal the number of variables declared by <paramref name="lambda"/>,
1527 /// or <paramref name="arguments"/> contains an expression that has a result type that is not equal or promotable
1528 /// to the corresponding variable type.
1529 /// </exception>
1530 public static DbLambdaExpression Invoke(this DbLambda lambda, params DbExpression[] arguments)
1532 return InvokeLambda(lambda, arguments);
1535 private static DbLambdaExpression InvokeLambda(DbLambda lambda, IEnumerable<DbExpression> arguments)
1537 DbExpressionList validArguments;
1538 TypeUsage resultType = ArgumentValidation.ValidateInvoke(lambda, arguments, out validArguments);
1539 return new DbLambdaExpression(resultType, lambda, validArguments);
1542 /// <summary>
1543 /// Creates a new <see cref="DbNewInstanceExpression"/>. If the type argument is a collection type, the arguments specify the elements of the collection. Otherwise the arguments are used as property or column values in the new instance.
1544 /// </summary>
1545 /// <param name="instanceType">The type of the new instance.</param>
1546 /// <param name="arguments">Expressions that specify values of the new instances, interpreted according to the instance's type.</param>
1547 /// <returns>A new DbNewInstanceExpression with the specified type and arguments.</returns>
1548 /// <exception cref="ArgumentNullException"><paramref name="instanceType"/> or <paramref name="arguments"/> is null, or <paramref name="arguments"/> contains null</exception>
1549 /// <exception cref="ArgumentException">
1550 /// <paramref name="arguments"/> is empty or the result types of the contained expressions do not match the requirements of <paramref name="instanceType"/> (as explained in the remarks section).
1551 /// </exception>
1552 /// <remarks>
1553 /// <para>
1554 /// if <paramref name="instanceType"/> is a a collection type then every expression in <paramref name="arguments"/> must have a result type that is promotable to the element type of the <paramref name="instanceType"/>.
1555 /// </para>
1556 /// <para>
1557 /// if <paramref name="instanceType"/> is a row type, <paramref name="arguments"/> must contain as many expressions as there are columns in the row
1558 /// type, and the result type of each expression must be equal or promotable to the type of the corresponding column. A row type that does not declare any columns is invalid.
1559 /// </para>
1560 /// <para>
1561 /// if <paramref name="instanceType"/> is an entity type, <paramref name="arguments"/> must contain as many expressions as there are properties defined by the type,
1562 /// and the result type of each expression must be equal or promotable to the type of the corresponding property.
1563 /// </para>
1564 /// </remarks>
1565 public static DbNewInstanceExpression New(this TypeUsage instanceType, IEnumerable<DbExpression> arguments)
1567 return NewInstance(instanceType, arguments);
1570 /// <summary>
1571 /// Creates a new <see cref="DbNewInstanceExpression"/>. If the type argument is a collection type, the arguments specify the elements of the collection. Otherwise the arguments are used as property or column values in the new instance.
1572 /// </summary>
1573 /// <param name="instanceType">The type of the new instance.</param>
1574 /// <param name="arguments">Expressions that specify values of the new instances, interpreted according to the instance's type.</param>
1575 /// <returns>A new DbNewInstanceExpression with the specified type and arguments.</returns>
1576 /// <exception cref="ArgumentNullException"><paramref name="instanceType"/> or <paramref name="arguments"/> is null, or <paramref name="arguments"/> contains null</exception>
1577 /// <exception cref="ArgumentException">
1578 /// <paramref name="arguments"/> is empty or the result types of the contained expressions do not match the requirements of <paramref name="instanceType"/> (as explained in the remarks section).
1579 /// </exception>
1580 /// <remarks>
1581 /// <para>
1582 /// if <paramref name="instanceType"/> is a a collection type then every expression in <paramref name="arguments"/> must have a result type that is promotable to the element type of the <paramref name="instanceType"/>.
1583 /// </para>
1584 /// <para>
1585 /// if <paramref name="instanceType"/> is a row type, <paramref name="arguments"/> must contain as many expressions as there are columns in the row
1586 /// type, and the result type of each expression must be equal or promotable to the type of the corresponding column. A row type that does not declare any columns is invalid.
1587 /// </para>
1588 /// <para>
1589 /// if <paramref name="instanceType"/> is an entity type, <paramref name="arguments"/> must contain as many expressions as there are properties defined by the type,
1590 /// and the result type of each expression must be equal or promotable to the type of the corresponding property.
1591 /// </para>
1592 /// </remarks>
1593 public static DbNewInstanceExpression New(this TypeUsage instanceType, params DbExpression[] arguments)
1595 return NewInstance(instanceType, arguments);
1598 private static DbNewInstanceExpression NewInstance(TypeUsage instanceType, IEnumerable<DbExpression> arguments)
1600 DbExpressionList validArguments;
1601 TypeUsage resultType = ArgumentValidation.ValidateNew(instanceType, arguments, out validArguments);
1602 return new DbNewInstanceExpression(resultType, validArguments);
1605 /// <summary>
1606 /// Creates a new <see cref="DbNewInstanceExpression"/> that constructs a collection containing the specified elements. The type of the collection is based on the common type of the elements. If no common element type exists an exception is thrown.
1607 /// </summary>
1608 /// <param name="elements">A list of expressions that provide the elements of the collection</param>
1609 /// <returns>A new DbNewInstanceExpression with the specified collection type and arguments.</returns>
1610 /// <exception cref="ArgumentNullException"><paramref name="elements"/> is null, or contains null</exception>
1611 /// <exception cref="ArgumentException">
1612 /// <paramref name="elements"/> is empty or contains expressions for which no common result type exists.
1613 /// </exception>
1614 public static DbNewInstanceExpression NewCollection(IEnumerable<DbExpression> elements)
1616 return CreateNewCollection(elements);
1619 /// <summary>
1620 /// Creates a new <see cref="DbNewInstanceExpression"/> that constructs a collection containing the specified elements. The type of the collection is based on the common type of the elements. If no common element type exists an exception is thrown.
1621 /// </summary>
1622 /// <param name="elements">A list of expressions that provide the elements of the collection</param>
1623 /// <returns>A new DbNewInstanceExpression with the specified collection type and arguments.</returns>
1624 /// <exception cref="ArgumentNullException"><paramref name="elements"/> is null, or contains null</exception>
1625 /// <exception cref="ArgumentException">
1626 /// <paramref name="elements"/> is empty or contains expressions for which no common result type exists.
1627 /// </exception>
1628 public static DbNewInstanceExpression NewCollection(params DbExpression[] elements)
1630 return CreateNewCollection(elements);
1633 private static DbNewInstanceExpression CreateNewCollection(IEnumerable<DbExpression> elements)
1635 DbExpressionList validElements;
1636 TypeUsage collectionResultType = ArgumentValidation.ValidateNewCollection(elements, out validElements);
1637 return new DbNewInstanceExpression(collectionResultType, validElements);
1640 /// <summary>
1641 /// Creates a new <see cref="DbNewInstanceExpression"/> that constructs an empty collection of the specified collection type.
1642 /// </summary>
1643 /// <param name="collectionType">The type metadata for the collection to create</param>
1644 /// <returns>A new DbNewInstanceExpression with the specified collection type and an empty <code>Arguments</code> list.</returns>
1645 /// <exception cref="ArgumentNullException"><paramref name="collectionType"/> is null</exception>
1646 /// <exception cref="ArgumentException"><paramref name="collectionType"/> is not a collection type</exception>
1647 public static DbNewInstanceExpression NewEmptyCollection(this TypeUsage collectionType)
1649 DbExpressionList validElements;
1650 TypeUsage validResultType = ArgumentValidation.ValidateNewEmptyCollection(collectionType, out validElements);
1651 return new DbNewInstanceExpression(validResultType, validElements);
1655 /// <summary>
1656 /// Creates a new <see cref="DbNewInstanceExpression"/> that produces a row with the specified named columns and the given values, specified as expressions.
1657 /// </summary>
1658 /// <param name="columnValues">A list of string-DbExpression key-value pairs that defines the structure and values of the row.</param>
1659 /// <returns>A new DbNewInstanceExpression that represents the construction of the row.</returns>
1660 /// <exception cref="ArgumentNullException"><paramref name="columnValues"/> is null or contains an element with a null column name or expression</exception>
1661 /// <exception cref="ArgumentException">
1662 /// <paramref name="columnValues"/> is empty, or contains a duplicate or invalid column name
1663 /// </exception>
1664 public static DbNewInstanceExpression NewRow(IEnumerable<KeyValuePair<string, DbExpression>> columnValues)
1666 DbExpressionList validElements;
1667 TypeUsage resultType = ArgumentValidation.ValidateNewRow(columnValues, out validElements);
1668 return new DbNewInstanceExpression(resultType, validElements);
1671 /// <summary>
1672 /// Creates a new <see cref="DbPropertyExpression"/> representing the retrieval of the specified property.
1673 /// </summary>
1674 /// <param name="instance">The instance from which to retrieve the property. May be null if the property is static.</param>
1675 /// <param name="propertyMetadata">Metadata for the property to retrieve.</param>
1676 /// <returns>A new DbPropertyExpression representing the property retrieval.</returns>
1677 /// <exception cref="ArgumentNullException"><paramref name="propertyMetadata"/> is null or <paramref name="instance"/> is null and the property is not static.</exception>
1678 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "required for this feature")]
1679 public static DbPropertyExpression Property(this DbExpression instance, EdmProperty propertyMetadata)
1681 return PropertyFromMember(instance, propertyMetadata, "propertyMetadata");
1684 /// <summary>
1685 /// Creates a new <see cref="DbPropertyExpression"/> representing the retrieval of the specified navigation property.
1686 /// </summary>
1687 /// <param name="instance">The instance from which to retrieve the navigation property.</param>
1688 /// <param name="navigationProperty">Metadata for the navigation property to retrieve.</param>
1689 /// <returns>A new DbPropertyExpression representing the navigation property retrieval.</returns>
1690 /// <exception cref="ArgumentNullException"><paramref name="navigationProperty"/> is null or <paramref name="instance"/> is null.</exception>
1691 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "required for this feature")]
1692 public static DbPropertyExpression Property(this DbExpression instance, NavigationProperty navigationProperty)
1694 return PropertyFromMember(instance, navigationProperty, "navigationProperty");
1697 /// <summary>
1698 /// Creates a new <see cref="DbPropertyExpression"/> representing the retrieval of the specified relationship end member.
1699 /// </summary>
1700 /// <param name="instance">The instance from which to retrieve the relationship end member.</param>
1701 /// <param name="relationshipEnd">Metadata for the relationship end member to retrieve.</param>
1702 /// <returns>A new DbPropertyExpression representing the relationship end member retrieval.</returns>
1703 /// <exception cref="ArgumentNullException"><paramref name="relationshipEnd"/> is null or <paramref name="instance"/> is null and the property is not static.</exception>
1704 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "required for this feature")]
1705 public static DbPropertyExpression Property(this DbExpression instance, RelationshipEndMember relationshipEnd)
1707 return PropertyFromMember(instance, relationshipEnd, "relationshipEnd");
1710 /// <summary>
1711 /// Creates a new <see cref="DbPropertyExpression"/> representing the retrieval of the instance property with the specified name from the given instance.
1712 /// </summary>
1713 /// <param name="propertyName">The name of the property to retrieve.</param>
1714 /// <param name="instance">The instance from which to retrieve the property.</param>
1715 /// <returns>A new DbPropertyExpression that represents the property retrieval</returns>
1716 /// <exception cref="ArgumentNullException"><paramref name="propertyName"/> is null or <paramref name="instance"/> is null and the property is not static.</exception>
1717 /// <exception cref="ArgumentOutOfRangeException">No property with the specified name is declared by the type of <paramref name="instance"/>.</exception>
1718 public static DbPropertyExpression Property(this DbExpression instance, string propertyName)
1720 return PropertyByName(instance, propertyName, false);
1723 private static DbPropertyExpression PropertyFromMember(DbExpression instance, EdmMember property, string propertyArgumentName)
1725 TypeUsage resultType = ArgumentValidation.ValidateProperty(instance, property, propertyArgumentName);
1726 return new DbPropertyExpression(resultType, property, instance);
1729 private static DbPropertyExpression PropertyByName(DbExpression instance, string propertyName, bool ignoreCase)
1731 EdmMember property;
1732 TypeUsage resultType = ArgumentValidation.ValidateProperty(instance, propertyName, ignoreCase, out property);
1733 return new DbPropertyExpression(resultType, property, instance);
1736 #endregion
1738 #region Lambda-based methods: All, Any, Cross|OuterApply, Cross|FullOuter|Inner|LeftOuterJoin, Filter, GroupBy, Project, Skip, Sort
1740 private static string ExtractAlias(MethodInfo method)
1742 Debug.Assert(method != null, "Ensure method is non-null before calling ExtractAlias");
1743 string[] aliases = ExtractAliases(method);
1744 Debug.Assert(aliases.Length > 0, "Incompatible method: at least one parameter is required");
1745 return aliases[0];
1748 internal static string[] ExtractAliases(MethodInfo method)
1750 Debug.Assert(method != null, "Ensure method is non-null before calling ExtractAlias");
1751 ParameterInfo[] methodParams = method.GetParameters();
1752 int start;
1753 int paramCount;
1754 if (method.IsStatic && typeof(System.Runtime.CompilerServices.Closure) == methodParams[0].ParameterType)
1756 // Static lambda method has additional first closure parameter
1757 start = 1;
1758 paramCount = methodParams.Length - 1;
1760 else
1762 // Otherwise, method parameters align directly with arguments
1763 start = 0;
1764 paramCount = methodParams.Length;
1767 string[] paramNames = new string[paramCount];
1768 bool generateNames = methodParams.Skip(start).Any(p => p.Name == null);
1769 for (int idx = start; idx < methodParams.Length; idx++)
1771 paramNames[idx - start] = (generateNames ? _bindingAliases.Next() : methodParams[idx].Name);
1773 return paramNames;
1776 private static DbExpressionBinding ConvertToBinding<TResult>(DbExpression source, Func<DbExpression, TResult> argument, string argumentName, out TResult argumentResult)
1778 return ConvertToBinding(source, "source", argument, argumentName, out argumentResult);
1781 private static DbExpressionBinding ConvertToBinding<TResult>(DbExpression source, string sourceName, Func<DbExpression, TResult> argument, string argumentName, out TResult argumentResult)
1783 EntityUtil.CheckArgumentNull(source, sourceName);
1784 EntityUtil.CheckArgumentNull(argument, argumentName);
1785 string alias = ExtractAlias(argument.Method);
1786 DbExpressionBinding binding = DbExpressionBuilder.BindAs(source, alias);
1787 argumentResult = argument(binding.Variable);
1788 return binding;
1791 private static DbExpressionBinding[] ConvertToBinding(DbExpression left, string leftArgumentName, DbExpression right, string rightArgumentName, Func<DbExpression, DbExpression, DbExpression> argument, string argumentName, out DbExpression argumentExp)
1793 EntityUtil.CheckArgumentNull(left, leftArgumentName);
1794 EntityUtil.CheckArgumentNull(right, rightArgumentName);
1796 EntityUtil.CheckArgumentNull(argument, argumentName);
1797 string[] aliases = ExtractAliases(argument.Method);
1798 DbExpressionBinding leftBinding = DbExpressionBuilder.BindAs(left, aliases[0]);
1799 DbExpressionBinding rightBinding = DbExpressionBuilder.BindAs(right, aliases[1]);
1800 argumentExp = argument(leftBinding.Variable, rightBinding.Variable);
1801 return new[] { leftBinding, rightBinding };
1804 [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
1805 private static bool TryGetAnonymousTypeValues<TInstance, TRequired>(object instance, out List<KeyValuePair<string, TRequired>> values)
1807 Debug.Assert(instance != null, "Ensure instance is non-null before calling TryGetAnonymousTypeValues");
1809 // The following heuristic is used to approximate whether or not TInstance is an anonymous type:
1810 // - Derived directly from System.Object
1811 // - Declares only public instance properties
1812 // - All public instance properties are readable and of an appropriate type
1814 values = null;
1815 if (typeof(TInstance).BaseType.Equals(typeof(object)) &&
1816 typeof(TInstance).GetProperties(BindingFlags.Static).Length == 0 &&
1817 typeof(TInstance).GetProperties(BindingFlags.Instance | BindingFlags.NonPublic).Length == 0)
1819 List<KeyValuePair<string, TRequired>> foundValues = null;
1820 foreach (PropertyInfo pi in typeof(TInstance).GetProperties(BindingFlags.Public | BindingFlags.Instance))
1822 if (pi.CanRead && typeof(TRequired).IsAssignableFrom(pi.PropertyType))
1824 if (foundValues == null)
1826 foundValues = new List<KeyValuePair<string, TRequired>>();
1828 foundValues.Add(new KeyValuePair<string, TRequired>(pi.Name, (TRequired)pi.GetValue(instance, null)));
1830 else
1832 foundValues = null;
1833 break;
1836 values = foundValues;
1839 return (values != null);
1842 private static bool TryResolveToConstant(Type type, object value, out DbExpression constantOrNullExpression)
1844 constantOrNullExpression = null;
1846 Type valueType = type;
1847 if (type.IsGenericType && typeof(Nullable<>).Equals(type.GetGenericTypeDefinition()))
1849 valueType = type.GetGenericArguments()[0];
1852 PrimitiveTypeKind primitiveTypeKind;
1853 if (ClrProviderManifest.Instance.TryGetPrimitiveTypeKind(valueType, out primitiveTypeKind))
1855 TypeUsage resultType = TypeHelpers.GetLiteralTypeUsage(primitiveTypeKind);
1856 if (null == value)
1858 constantOrNullExpression = DbExpressionBuilder.Null(resultType);
1860 else
1862 constantOrNullExpression = DbExpressionBuilder.Constant(resultType, value);
1866 return (constantOrNullExpression != null);
1869 private static DbExpression ResolveToExpression<TArgument>(TArgument argument)
1871 object untypedArgument = argument;
1873 DbExpression constantResult;
1874 if (TryResolveToConstant(typeof(TArgument), untypedArgument, out constantResult))
1876 return constantResult;
1879 if (null == untypedArgument)
1881 return (DbExpression)null;
1884 // Direct DbExpression result
1885 if (typeof(DbExpression).IsAssignableFrom(typeof(TArgument)))
1887 return (DbExpression)untypedArgument;
1890 // Row
1891 if (typeof(Row).Equals(typeof(TArgument)))
1893 return ((Row)untypedArgument).ToExpression();
1896 // Conversion from anonymous type instance to DbNewInstanceExpression of a corresponding row type
1897 List<KeyValuePair<string, DbExpression>> columnValues;
1898 if (TryGetAnonymousTypeValues<TArgument, DbExpression>(untypedArgument, out columnValues))
1900 return DbExpressionBuilder.NewRow(columnValues);
1903 // The specified instance cannot be resolved to a DbExpression
1904 throw EntityUtil.NotSupported(Strings.Cqt_Factory_MethodResultTypeNotSupported(typeof(TArgument).FullName));
1907 private static DbApplyExpression CreateApply(DbExpression source, Func<DbExpression, KeyValuePair<string, DbExpression>> apply, Func<DbExpressionBinding, DbExpressionBinding, DbApplyExpression> resultBuilder)
1909 KeyValuePair<string, DbExpression> applyTemplate;
1910 DbExpressionBinding sourceBinding = ConvertToBinding(source, apply, "apply", out applyTemplate);
1911 DbExpressionBinding applyBinding = DbExpressionBuilder.BindAs(applyTemplate.Value, applyTemplate.Key);
1912 return resultBuilder(sourceBinding, applyBinding);
1915 /// <summary>
1916 /// Creates a new <see cref="DbQuantifierExpression"/> that determines whether the given predicate holds for all elements of the input set.
1917 /// </summary>
1918 /// <param name="source">
1919 /// An expression that specifies the input set.
1920 /// </param>
1921 /// <param name="predicate">
1922 /// A method representing a predicate to evaluate for each member of the input set.
1923 /// This method must produce an expression with a Boolean result type that provides
1924 /// the predicate logic.
1925 /// </param>
1926 /// <returns>A new DbQuantifierExpression that represents the All operation.</returns>
1927 /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="predicate"/> is null</exception>
1928 /// <exception cref="ArgumentNullException">The expression produced by <paramref name="predicate"/> is null</exception>
1929 /// <exception cref="ArgumentException"><paramref name="source"/> does not have a collection result type.</exception>
1930 /// <exception cref="ArgumentException">
1931 /// The expression produced by <paramref name="predicate"/> does not have a Boolean result type.
1932 /// </exception>
1933 public static DbQuantifierExpression All(this DbExpression source, Func<DbExpression, DbExpression> predicate)
1935 DbExpression predicateExp;
1936 DbExpressionBinding input = ConvertToBinding(source, predicate, "predicate", out predicateExp);
1937 return DbExpressionBuilder.All(input, predicateExp);
1940 /// <summary>
1941 /// Creates a new <see cref="DbExpression"/> that determines whether the specified set argument is non-empty.
1942 /// </summary>
1943 /// <param name="source">An expression that specifies the input set</param>
1944 /// <returns>A new <see cref="DbNotExpression"/> applied to a new <see cref="DbIsEmptyExpression"/> with the specified argument.</returns>
1945 /// <exception cref="ArgumentNullException"><paramref name="source"/> is null</exception>
1946 /// <exception cref="ArgumentException"><paramref name="source"/> does not have a collection result type.</exception>
1947 public static DbExpression Any(this DbExpression source)
1949 return DbExpressionBuilder.Exists(source);
1952 /// <summary>
1953 /// Creates a new <see cref="DbExpression"/> that determines whether the specified set argument is non-empty.
1954 /// </summary>
1955 /// <param name="argument">An expression that specifies the input set</param>
1956 /// <returns>A new <see cref="DbNotExpression"/> applied to a new <see cref="DbIsEmptyExpression"/> with the specified argument.</returns>
1957 /// <exception cref="ArgumentNullException"><paramref name="argument"/> is null</exception>
1958 /// <exception cref="ArgumentException"><paramref name="argument"/> does not have a collection result type.</exception>
1959 public static DbExpression Exists(this DbExpression argument)
1961 return DbExpressionBuilder.Not(DbExpressionBuilder.IsEmpty(argument));
1964 /// <summary>
1965 /// Creates a new <see cref="DbQuantifierExpression"/> that determines whether the given predicate holds for any element of the input set.
1966 /// </summary>
1967 /// <param name="source">
1968 /// An expression that specifies the input set.
1969 /// </param>
1970 /// <param name="predicate">
1971 /// A method representing the predicate to evaluate for each member of the input set.
1972 /// This method must produce an expression with a Boolean result type that provides
1973 /// the predicate logic.
1974 /// </param>
1975 /// <returns>A new DbQuantifierExpression that represents the Any operation.</returns>
1976 /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="predicate"/> is null</exception>
1977 /// <exception cref="ArgumentNullException">The expression produced by <paramref name="predicate"/> is null</exception>
1978 /// <exception cref="ArgumentException"><paramref name="source"/> does not have a collection result type.</exception>
1979 /// <exception cref="ArgumentException">
1980 /// The expression produced by <paramref name="predicate"/> does not have a Boolean result type.
1981 /// </exception>
1982 public static DbQuantifierExpression Any(this DbExpression source, Func<DbExpression, DbExpression> predicate)
1984 DbExpression predicateExp;
1985 DbExpressionBinding input = ConvertToBinding(source, predicate, "predicate", out predicateExp);
1986 return DbExpressionBuilder.Any(input, predicateExp);
1989 /// <summary>
1990 /// Creates a new <see cref="DbApplyExpression"/> that evaluates the given <paramref name="apply"/> expression once for each element of a given input set,
1991 /// producing a collection of rows with corresponding input and apply columns. Rows for which <paramref name="apply"/> evaluates to an empty set are not included.
1992 /// </summary>
1993 /// <param name="source">
1994 /// A <see cref="DbExpression"/> that specifies the input set.
1995 /// </param>
1996 /// <param name="apply">
1997 /// A method that specifies the logic to evaluate once for each member of the input set.
1998 /// </param>
1999 /// <returns>An new DbApplyExpression with the specified input and apply bindings and an <see cref="DbExpressionKind"/> of CrossApply.</returns>
2000 /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="apply"/> is null</exception>
2001 /// <exception cref="ArgumentException"><paramref name="source"/> does not have a collection result type.</exception>
2002 /// <exception cref="ArgumentNullException">The result of <paramref name="apply"/> contains a name or expression that is null.</exception>
2003 /// <exception cref="ArgumentException">The result of <paramref name="apply"/> contains a name or expression that is not valid in an expression binding.</exception>
2004 public static DbApplyExpression CrossApply(this DbExpression source, Func<DbExpression, KeyValuePair<string, DbExpression>> apply)
2006 return CreateApply(source, apply, DbExpressionBuilder.CrossApply);
2012 /// <summary>
2013 /// Creates a new <see cref="DbApplyExpression"/> that evaluates the given <paramref name="apply"/> expression once for each element of a given input set,
2014 /// producing a collection of rows with corresponding input and apply columns. Rows for which <paramref name="apply"/> evaluates to an empty set have an apply column value of <code>null</code>.
2015 /// </summary>
2016 /// <param name="source">
2017 /// A <see cref="DbExpression"/> that specifies the input set.
2018 /// </param>
2019 /// <param name="apply">
2020 /// A method that specifies the logic to evaluate once for each member of the input set.
2021 /// </param>
2022 /// <returns>An new DbApplyExpression with the specified input and apply bindings and an <see cref="DbExpressionKind"/> of OuterApply.</returns>
2023 /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="apply"/> is null</exception>
2024 /// <exception cref="ArgumentException"><paramref name="source"/> does not have a collection result type.</exception>
2025 /// <exception cref="ArgumentNullException">The result of <paramref name="apply"/> contains a name or expression that is null.</exception>
2026 /// <exception cref="ArgumentException">The result of <paramref name="apply"/> contains a name or expression that is not valid in an expression binding.</exception>
2027 public static DbApplyExpression OuterApply(this DbExpression source, Func<DbExpression, KeyValuePair<string, DbExpression>> apply)
2029 return CreateApply(source, apply, DbExpressionBuilder.OuterApply);
2037 /// <summary>
2038 /// Creates a new <see cref="DbJoinExpression"/> that joins the sets specified by the left and right expressions,
2039 /// on the specified join condition, using FullOuterJoin as the <see cref="DbExpressionKind"/>.
2040 /// </summary>
2041 /// <param name="left">A <see cref="DbExpression"/> that specifies the left set argument.</param>
2042 /// <param name="right">A <see cref="DbExpression"/> that specifies the right set argument.</param>
2043 /// <param name="joinCondition">
2044 /// A method representing the condition on which to join.
2045 /// This method must produce an expression with a Boolean result type that provides the
2046 /// logic of the join condition.
2047 /// </param>
2048 /// <returns>
2049 /// A new DbJoinExpression, with an <see cref="DbExpressionKind"/> of FullOuterJoin, that represents the full outer join operation
2050 /// applied to the left and right input sets under the given join condition.
2051 /// </returns>
2052 /// <exception cref="ArgumentNullException">
2053 /// <paramref name="left"/>, <paramref name="right"/> or <paramref name="joinCondition"/> is null.
2054 /// </exception>
2055 /// <exception cref="ArgumentException">
2056 /// <paramref name="left"/> or <paramref name="right"/> does not have a collection result type.
2057 /// </exception>
2058 /// <exception cref="ArgumentNullException">
2059 /// The expression produced by <paramref name="joinCondition"/> is null.
2060 /// </exception>
2061 /// <exception cref="ArgumentException">
2062 /// The expression produced by <paramref name="joinCondition"/> does not have a Boolean result type.
2063 /// </exception>
2064 public static DbJoinExpression FullOuterJoin(this DbExpression left, DbExpression right, Func<DbExpression, DbExpression, DbExpression> joinCondition)
2066 DbExpression condExp;
2067 DbExpressionBinding[] inputs = ConvertToBinding(left, "left", right, "right", joinCondition, "joinCondition", out condExp);
2068 return DbExpressionBuilder.FullOuterJoin(inputs[0], inputs[1], condExp);
2071 /// <summary>
2072 /// Creates a new <see cref="DbJoinExpression"/> that joins the sets specified by the left and right expressions,
2073 /// on the specified join condition, using InnerJoin as the <see cref="DbExpressionKind"/>.
2074 /// </summary>
2075 /// <param name="left">A <see cref="DbExpression"/> that specifies the left set argument.</param>
2076 /// <param name="right">A <see cref="DbExpression"/> that specifies the right set argument.</param>
2077 /// <param name="joinCondition">
2078 /// A method representing the condition on which to join.
2079 /// This method must produce an expression with a Boolean result type that provides the
2080 /// logic of the join condition.
2081 /// </param>
2082 /// <returns>
2083 /// A new DbJoinExpression, with an <see cref="DbExpressionKind"/> of InnerJoin, that represents the inner join operation
2084 /// applied to the left and right input sets under the given join condition.
2085 /// </returns>
2086 /// <exception cref="ArgumentNullException">
2087 /// <paramref name="left"/>, <paramref name="right"/> or <paramref name="joinCondition"/> is null.
2088 /// </exception>
2089 /// <exception cref="ArgumentException">
2090 /// <paramref name="left"/> or <paramref name="right"/> does not have a collection result type.
2091 /// </exception>
2092 /// <exception cref="ArgumentNullException">
2093 /// The expression produced by <paramref name="joinCondition"/> is null.
2094 /// </exception>
2095 /// <exception cref="ArgumentException">
2096 /// The expression produced by <paramref name="joinCondition"/> does not have a Boolean result type.
2097 /// </exception>
2098 public static DbJoinExpression InnerJoin(this DbExpression left, DbExpression right, Func<DbExpression, DbExpression, DbExpression> joinCondition)
2100 DbExpression condExp;
2101 DbExpressionBinding[] inputs = ConvertToBinding(left, "left", right, "right", joinCondition, "joinCondition", out condExp);
2102 return DbExpressionBuilder.InnerJoin(inputs[0], inputs[1], condExp);
2105 /// <summary>
2106 /// Creates a new <see cref="DbJoinExpression"/> that joins the sets specified by the left and right expressions,
2107 /// on the specified join condition, using LeftOuterJoin as the <see cref="DbExpressionKind"/>.
2108 /// </summary>
2109 /// <param name="left">A <see cref="DbExpression"/> that specifies the left set argument.</param>
2110 /// <param name="right">A <see cref="DbExpression"/> that specifies the right set argument.</param>
2111 /// <param name="joinCondition">
2112 /// A method representing the condition on which to join.
2113 /// This method must produce an expression with a Boolean result type that provides the
2114 /// logic of the join condition.
2115 /// </param>
2116 /// <returns>
2117 /// A new DbJoinExpression, with an <see cref="DbExpressionKind"/> of LeftOuterJoin, that represents the left outer join operation
2118 /// applied to the left and right input sets under the given join condition.
2119 /// </returns>
2120 /// <exception cref="ArgumentNullException">
2121 /// <paramref name="left"/>, <paramref name="right"/> or <paramref name="joinCondition"/> is null.
2122 /// </exception>
2123 /// <exception cref="ArgumentException">
2124 /// <paramref name="left"/> or <paramref name="right"/> does not have a collection result type.
2125 /// </exception>
2126 /// <exception cref="ArgumentNullException">
2127 /// The expression produced by <paramref name="joinCondition"/> is null.
2128 /// </exception>
2129 /// <exception cref="ArgumentException">
2130 /// The expression produced by <paramref name="joinCondition"/> does not have a Boolean result type.
2131 /// </exception>
2132 public static DbJoinExpression LeftOuterJoin(this DbExpression left, DbExpression right, Func<DbExpression, DbExpression, DbExpression> joinCondition)
2134 DbExpression condExp;
2135 DbExpressionBinding[] inputs = ConvertToBinding(left, "left", right, "right", joinCondition, "joinCondition", out condExp);
2136 return DbExpressionBuilder.LeftOuterJoin(inputs[0], inputs[1], condExp);
2139 /// <summary>
2140 /// Creates a new <see cref="DbJoinExpression"/> that joins the sets specified by the outer and inner expressions,
2141 /// on an equality condition between the specified outer and inner keys, using InnerJoin as the <see cref="DbExpressionKind"/>.
2142 /// </summary>
2143 /// <param name="outer">A <see cref="DbExpression"/> that specifies the outer set argument.</param>
2144 /// <param name="inner">A <see cref="DbExpression"/> that specifies the inner set argument.</param>
2145 /// <param name="outerKey">A method that specifies how the outer key value should be derived from an element of the outer set.</param>
2146 /// <param name="innerKey">A method that specifies how the inner key value should be derived from an element of the inner set.</param>
2147 /// <returns>
2148 /// A new DbJoinExpression, with an <see cref="DbExpressionKind"/> of InnerJoin, that represents the inner join operation
2149 /// applied to the left and right input sets under a join condition that compares the outer and inner key values for equality.
2150 /// </returns>
2151 /// <exception cref="ArgumentNullException">
2152 /// <paramref name="outer"/>, <paramref name="inner"/>, <paramref name="outerKey"/> or <paramref name="innerKey"/> is null.
2153 /// </exception>
2154 /// <exception cref="ArgumentException">
2155 /// <paramref name="outer"/> or <paramref name="inner"/> does not have a collection result type.
2156 /// </exception>
2157 /// <exception cref="ArgumentNullException">
2158 /// The expression produced by <paramref name="outerKey"/> or <paramref name="innerKey"/> is null.
2159 /// </exception>
2160 /// <exception cref="ArgumentException">
2161 /// The expressions produced by <paramref name="outerKey"/> and <paramref name="innerKey"/> are not comparable for equality.
2162 /// </exception>
2163 public static DbJoinExpression Join(this DbExpression outer, DbExpression inner, Func<DbExpression, DbExpression> outerKey, Func<DbExpression, DbExpression> innerKey)
2165 DbExpression leftOperand;
2166 DbExpressionBinding leftBinding = ConvertToBinding(outer, "outer", outerKey, "outerKey", out leftOperand);
2168 DbExpression rightOperand;
2169 DbExpressionBinding rightBinding = ConvertToBinding(inner, "inner", innerKey, "innerKey", out rightOperand);
2171 DbExpression joinCondition = DbExpressionBuilder.Equal(leftOperand, rightOperand);
2173 return DbExpressionBuilder.InnerJoin(leftBinding, rightBinding, joinCondition);
2176 /// <summary>
2177 /// Creates a new <see cref="DbProjectExpression"/> that projects the specified selector over the sets specified by the outer and inner
2178 /// expressions, joined on an equality condition between the specified outer and inner keys, using InnerJoin as the <see cref="DbExpressionKind"/>.
2179 /// </summary>
2180 /// <param name="outer">A <see cref="DbExpression"/> that specifies the outer set argument.</param>
2181 /// <param name="inner">A <see cref="DbExpression"/> that specifies the inner set argument.</param>
2182 /// <param name="outerKey">A method that specifies how the outer key value should be derived from an element of the outer set.</param>
2183 /// <param name="innerKey">A method that specifies how the inner key value should be derived from an element of the inner set.</param>
2184 /// <param name="selector">
2185 /// A method that specifies how an element of the result set should be derived from elements of the inner and outer sets.
2186 /// This method must produce an instance of a type that is compatible with Join and can be resolved
2187 /// into a <see cref="DbExpression"/>.
2188 /// Compatibility requirements for <typeparamref name="TSelector"/> are described in remarks.
2189 /// </param>
2190 /// <returns>
2191 /// A new DbProjectExpression with the specified selector as its projection, and a new DbJoinExpression as its input.
2192 /// The input DbJoinExpression is created with an <see cref="DbExpressionKind"/> of InnerJoin, that represents the inner join operation
2193 /// applied to the left and right input sets under a join condition that compares the outer and inner key values for equality.
2194 /// </returns>
2195 /// <exception cref="ArgumentNullException">
2196 /// <paramref name="outer"/>, <paramref name="inner"/>, <paramref name="outerKey"/>, <paramref name="innerKey"/> or <paramref name="selector"/> is null.
2197 /// </exception>
2198 /// <exception cref="ArgumentException">
2199 /// <paramref name="outer"/> or <paramref name="inner"/> does not have a collection result type.
2200 /// </exception>
2201 /// <exception cref="ArgumentNullException">
2202 /// The expression produced by <paramref name="outerKey"/> or <paramref name="innerKey"/> is null.
2203 /// </exception>
2204 /// <exception cref="ArgumentNullException">
2205 /// The result of <paramref name="selector"/> is null after conversion to DbExpression.
2206 /// </exception>
2207 /// <exception cref="ArgumentException">
2208 /// The expressions produced by <paramref name="outerKey"/> and <paramref name="innerKey"/> are not comparable for equality.
2209 /// </exception>
2210 /// <exception cref="ArgumentException">
2211 /// The result of <paramref name="selector"/> is not compatible with SelectMany.
2212 /// </exception>
2213 /// <remarks>
2214 /// To be compatible with Join, <typeparamref name="TSelector"/> must be derived from <see cref="DbExpression"/>,
2215 /// or must be an anonymous type with DbExpression-derived properties.
2216 /// <para>
2217 /// The following are examples of supported types for <typeparamref name="TSelector"/>:
2218 /// <code>outer.Join(inner, o => o.Property("ID"), i => i.Property("ID"), (o, i) => o.Property("Name"))</code> (<typeparamref name="TSelector"/> is <see cref="DbPropertyExpression"/>).
2219 /// <code>outer.Join(inner, o => o.Property("ID"), i => i.Property("ID"), (o, i) => new { OName = o.Property("Name"), IName = i.Property("Name") })</code> (<typeparamref name="TSelector"/> is an anonymous type with DbExpression-derived properties).
2220 /// </para>
2221 /// </remarks>
2222 public static DbProjectExpression Join<TSelector>(this DbExpression outer, DbExpression inner, Func<DbExpression, DbExpression> outerKey, Func<DbExpression, DbExpression> innerKey, Func<DbExpression, DbExpression, TSelector> selector)
2224 // Defer argument validation for all but the selector to the selector-less overload of Join
2225 DbJoinExpression joinExpression = DbExpressionBuilder.Join(outer, inner, outerKey, innerKey);
2227 // Ensure that the selector is non-null;
2228 EntityUtil.CheckArgumentNull(selector, "selector");
2230 // Bind the join expression and produce the selector based on the left and right inputs
2231 DbExpressionBinding joinBinding = DbExpressionBuilder.Bind(joinExpression);
2232 DbExpression left = DbExpressionBuilder.Property(joinBinding.Variable, joinExpression.Left.VariableName);
2233 DbExpression right = DbExpressionBuilder.Property(joinBinding.Variable, joinExpression.Right.VariableName);
2234 TSelector intermediateSelector = selector(left, right);
2235 DbExpression projection = DbExpressionBuilder.ResolveToExpression(intermediateSelector);
2237 // Project the selector over the join expression and return the resulting DbProjectExpression
2238 return DbExpressionBuilder.Project(joinBinding, projection);
2241 /// <summary>
2242 /// Creates a new <see cref="DbSortExpression"/> that sorts the given input set by the specified sort key,
2243 /// with ascending sort order and default collation.
2244 /// </summary>
2245 /// <param name="source">An expression that specifies the input set.</param>
2246 /// <param name="sortKey">
2247 /// A method that specifies how to derive the sort key expression given a member of the input set.
2248 /// This method must produce an expression with an order-comparable result type that provides the
2249 /// sort key definition.
2250 /// </param>
2251 /// <returns>A new DbSortExpression that represents the order-by operation.</returns>
2252 /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="sortKey"/> is null.</exception>
2253 /// <exception cref="ArgumentNullException">The expression produced by <paramref name="sortKey"/> is null.</exception>
2254 /// <exception cref="ArgumentException"><paramref name="source"/> does not have a collection result type.</exception>
2255 /// <exception cref="ArgumentException">
2256 /// The expression produced by <paramref name="sortKey"/> does not have an order-comparable result type.
2257 /// </exception>
2258 public static DbSortExpression OrderBy(this DbExpression source, Func<DbExpression, DbExpression> sortKey)
2260 DbExpression keyExpression;
2261 DbExpressionBinding input = ConvertToBinding(source, sortKey, "sortKey", out keyExpression);
2262 DbSortClause sortClause = DbExpressionBuilder.ToSortClause(keyExpression);
2263 return DbExpressionBuilder.Sort(input, new DbSortClause[] { sortClause });
2266 /// <summary>
2267 /// Creates a new <see cref="DbSortExpression"/> that sorts the given input set by the specified sort key,
2268 /// with ascending sort order and the specified collation.
2269 /// </summary>
2270 /// <param name="source">An expression that specifies the input set.</param>
2271 /// <param name="sortKey">
2272 /// A method that specifies how to derive the sort key expression given a member of the input set.
2273 /// This method must produce an expression with an order-comparable result type that provides the
2274 /// sort key definition.
2275 /// </param>
2276 /// <param name="collation">The collation to sort under</param>
2277 /// <returns>A new DbSortExpression that represents the order-by operation.</returns>
2278 /// <exception cref="ArgumentNullException"><paramref name="source"/>, <paramref name="sortKey"/> or <paramref name="collation"/> is null.</exception>
2279 /// <exception cref="ArgumentNullException">The expression produced by <paramref name="sortKey"/> is null.</exception>
2280 /// <exception cref="ArgumentException"><paramref name="source"/> does not have a collection result type.</exception>
2281 /// <exception cref="ArgumentException">
2282 /// The expression produced by <paramref name="sortKey"/> does not have an order-comparable string result type.
2283 /// </exception>
2284 /// <exception cref="ArgumentOutOfRangeException"><paramref name="collation"/> is empty or contains only space characters</exception>
2285 public static DbSortExpression OrderBy(this DbExpression source, Func<DbExpression, DbExpression> sortKey, string collation)
2287 DbExpression keyExpression;
2288 DbExpressionBinding input = ConvertToBinding(source, sortKey, "sortKey", out keyExpression);
2289 DbSortClause sortClause = DbExpressionBuilder.ToSortClause(keyExpression, collation);
2290 return DbExpressionBuilder.Sort(input, new DbSortClause[] { sortClause });
2293 /// <summary>
2294 /// Creates a new <see cref="DbSortExpression"/> that sorts the given input set by the specified sort key,
2295 /// with descending sort order and default collation.
2296 /// </summary>
2297 /// <param name="source">An expression that specifies the input set.</param>
2298 /// <param name="sortKey">
2299 /// A method that specifies how to derive the sort key expression given a member of the input set.
2300 /// This method must produce an expression with an order-comparable result type that provides the
2301 /// sort key definition.
2302 /// </param>
2303 /// <returns>A new DbSortExpression that represents the order-by operation.</returns>
2304 /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="sortKey"/> is null.</exception>
2305 /// <exception cref="ArgumentNullException">The expression produced by <paramref name="sortKey"/> is null.</exception>
2306 /// <exception cref="ArgumentException"><paramref name="source"/> does not have a collection result type.</exception>
2307 /// <exception cref="ArgumentException">
2308 /// The expression produced by <paramref name="sortKey"/> does not have an order-comparable result type.
2309 /// </exception>
2310 public static DbSortExpression OrderByDescending(this DbExpression source, Func<DbExpression, DbExpression> sortKey)
2312 DbExpression keyExpression;
2313 DbExpressionBinding input = ConvertToBinding(source, sortKey, "sortKey", out keyExpression);
2314 DbSortClause sortClause = DbExpressionBuilder.ToSortClauseDescending(keyExpression);
2315 return DbExpressionBuilder.Sort(input, new DbSortClause[] { sortClause });
2318 /// <summary>
2319 /// Creates a new <see cref="DbSortExpression"/> that sorts the given input set by the specified sort key,
2320 /// with descending sort order and the specified collation.
2321 /// </summary>
2322 /// <param name="source">An expression that specifies the input set.</param>
2323 /// <param name="sortKey">
2324 /// A method that specifies how to derive the sort key expression given a member of the input set.
2325 /// This method must produce an expression with an order-comparable result type that provides the
2326 /// sort key definition.
2327 /// </param>
2328 /// <param name="collation">The collation to sort under</param>
2329 /// <returns>A new DbSortExpression that represents the order-by operation.</returns>
2330 /// <exception cref="ArgumentNullException"><paramref name="source"/>, <paramref name="sortKey"/> or <paramref name="collation"/> is null.</exception>
2331 /// <exception cref="ArgumentNullException">The expression produced by <paramref name="sortKey"/> is null.</exception>
2332 /// <exception cref="ArgumentException"><paramref name="source"/> does not have a collection result type.</exception>
2333 /// <exception cref="ArgumentException">
2334 /// The expression produced by <paramref name="sortKey"/> does not have an order-comparable string result type.
2335 /// </exception>
2336 /// <exception cref="ArgumentOutOfRangeException"><paramref name="collation"/> is empty or contains only space characters</exception>
2337 public static DbSortExpression OrderByDescending(this DbExpression source, Func<DbExpression, DbExpression> sortKey, string collation)
2339 DbExpression keyExpression;
2340 DbExpressionBinding input = ConvertToBinding(source, sortKey, "sortKey", out keyExpression);
2341 DbSortClause sortClause = DbExpressionBuilder.ToSortClauseDescending(keyExpression, collation);
2342 return DbExpressionBuilder.Sort(input, new DbSortClause[] { sortClause });
2345 /// <summary>
2346 /// Creates a new <see cref="DbProjectExpression"/> that selects the specified expression over the given input set.
2347 /// </summary>
2348 /// <param name="source">An expression that specifies the input set.</param>
2349 /// <param name="projection">
2350 /// A method that specifies how to derive the projected expression given a member of the input set.
2351 /// This method must produce an instance of a type that is compatible with Select and can be resolved
2352 /// into a <see cref="DbExpression"/>.
2353 /// Compatibility requirements for <typeparamref name="TProjection"/> are described in remarks.
2354 /// </param>
2355 /// <typeparam name="TProjection">The method result type of <paramref name="projection"/>.</typeparam>
2356 /// <returns>A new DbProjectExpression that represents the select operation.</returns>
2357 /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="projection"/> is null</exception>
2358 /// <exception cref="ArgumentNullException">The result of <paramref name="projection"/> is null.</exception>
2359 /// <remarks>
2360 /// To be compatible with Select, <typeparamref name="TProjection"/> must be derived from <see cref="DbExpression"/>,
2361 /// or must be an anonymous type with DbExpression-derived properties.
2362 /// <para>
2363 /// The following are examples of supported types for <typeparamref name="TProjection"/>:
2364 /// <code>source.Select(x => x.Property("Name"))</code> (<typeparamref name="TProjection"/> is <see cref="DbPropertyExpression"/>).
2365 /// <code>source.Select(x => new { Name = x.Property("Name") })</code> (<typeparamref name="TProjection"/> is an anonymous type with a DbExpression-derived property).
2366 /// </para>
2367 /// </remarks>
2368 public static DbProjectExpression Select<TProjection>(this DbExpression source, Func<DbExpression, TProjection> projection)
2370 EntityUtil.CheckArgumentNull(projection, "projection");
2371 TProjection intermediateProjection;
2372 DbExpressionBinding input = ConvertToBinding(source, projection, "projection", out intermediateProjection);
2373 DbExpression projectionExp = ResolveToExpression(intermediateProjection);
2374 return DbExpressionBuilder.Project(input, projectionExp);
2377 /// <summary>
2378 /// Creates a new <see cref="DbApplyExpression"/> that evaluates the given <paramref name="apply"/> expression once for each element of a given input set,
2379 /// producing a collection of rows with corresponding input and apply columns. Rows for which <paramref name="apply"/> evaluates to an empty set are not included.
2380 /// A <see cref="DbProjectExpression"/> is then created that selects the <paramref name="apply"/> column from each row, producing the overall collection of <paramref name="apply"/> results.
2381 /// </summary>
2382 /// <param name="source">
2383 /// A <see cref="DbExpression"/> that specifies the input set.
2384 /// </param>
2385 /// <param name="apply">
2386 /// A method that represents the logic to evaluate once for each member of the input set.
2387 /// </param>
2388 /// <returns>An new DbProjectExpression that selects the apply column from a new DbApplyExpression with the specified input and apply bindings and an <see cref="DbExpressionKind"/> of CrossApply.</returns>
2389 /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="apply"/> is null.</exception>
2390 /// <exception cref="ArgumentNullException">The expression produced by <paramref name="apply"/> is null.</exception>
2391 /// <exception cref="ArgumentException"><paramref name="source"/> does not have a collection result type.</exception>
2392 /// <exception cref="ArgumentException">The expression produced by <paramref name="apply"/> does not have a collection type.</exception>
2393 public static DbProjectExpression SelectMany(this DbExpression source, Func<DbExpression, DbExpression> apply)
2395 DbExpression functorResult;
2396 DbExpressionBinding inputBinding = ConvertToBinding(source, apply, "apply", out functorResult);
2398 DbExpressionBinding functorBinding = DbExpressionBuilder.Bind(functorResult);
2399 DbApplyExpression intermediateApply = DbExpressionBuilder.CrossApply(inputBinding, functorBinding);
2401 DbExpressionBinding projectionBinding = DbExpressionBuilder.Bind(intermediateApply);
2402 return DbExpressionBuilder.Project(projectionBinding, DbExpressionBuilder.Property(projectionBinding.Variable, functorBinding.VariableName));
2405 /// <summary>
2406 /// Creates a new <see cref="DbApplyExpression"/> that evaluates the given <paramref name="apply"/> expression once for each element of a given input set,
2407 /// producing a collection of rows with corresponding input and apply columns. Rows for which <paramref name="apply"/> evaluates to an empty set are not included.
2408 /// A <see cref="DbProjectExpression"/> is then created that selects the specified <paramref name="selector"/> over each row, producing the overall collection of results.
2409 /// </summary>
2410 /// <typeparam name="TSelector">The method result type of <paramref name="selector"/>.</typeparam>
2411 /// <param name="source">
2412 /// A <see cref="DbExpression"/> that specifies the input set.
2413 /// </param>
2414 /// <param name="apply">
2415 /// A method that represents the logic to evaluate once for each member of the input set.
2416 /// </param>
2417 /// <param name="selector">
2418 /// A method that specifies how an element of the result set should be derived given an element of the input and apply sets.
2419 /// This method must produce an instance of a type that is compatible with SelectMany and can be resolved into a <see cref="DbExpression"/>.
2420 /// Compatibility requirements for <typeparamref name="TSelector"/> are described in remarks.
2421 /// </param>
2422 /// <returns>An new DbProjectExpression that selects the result of the given selector from a new DbApplyExpression with the specified input and apply bindings and an <see cref="DbExpressionKind"/> of CrossApply.</returns>
2423 /// <exception cref="ArgumentNullException"><paramref name="source"/>, <paramref name="apply"/> or <paramref name="selector"/> is null.</exception>
2424 /// <exception cref="ArgumentNullException">The expression produced by <paramref name="apply"/> is null.</exception>
2425 /// <exception cref="ArgumentNullException">The result of <paramref name="selector"/> is null on conversion to DbExpression</exception>
2426 /// <exception cref="ArgumentException"><paramref name="source"/> does not have a collection result type.</exception>
2427 /// <exception cref="ArgumentException">The expression produced by <paramref name="apply"/> does not have a collection type.</exception>
2428 /// <remarks>
2429 /// To be compatible with SelectMany, <typeparamref name="TSelector"/> must be derived from <see cref="DbExpression"/>,
2430 /// or must be an anonymous type with DbExpression-derived properties.
2431 /// <para>
2432 /// The following are examples of supported types for <typeparamref name="TSelector"/>:
2433 /// <code>source.SelectMany(x => x.Property("RelatedCollection"), (source, apply) => apply.Property("Name"))</code> (<typeparamref name="TSelector"/> is <see cref="DbPropertyExpression"/>).
2434 /// <code>source.SelectMany(x => x.Property("RelatedCollection"), (source, apply) => new { SourceName = source.Property("Name"), RelatedName = apply.Property("Name") })</code> (<typeparamref name="TSelector"/> is an anonymous type with DbExpression-derived properties).
2435 /// </para>
2436 /// </remarks>
2437 public static DbProjectExpression SelectMany<TSelector>(this DbExpression source, Func<DbExpression, DbExpression> apply, Func<DbExpression, DbExpression, TSelector> selector)
2439 DbExpression functorResult;
2440 DbExpressionBinding inputBinding = ConvertToBinding(source, apply, "apply", out functorResult);
2441 EntityUtil.CheckArgumentNull(selector, "selector");
2443 DbExpressionBinding functorBinding = DbExpressionBuilder.Bind(functorResult);
2444 DbApplyExpression intermediateApply = DbExpressionBuilder.CrossApply(inputBinding, functorBinding);
2446 DbExpressionBinding projectionBinding = DbExpressionBuilder.Bind(intermediateApply);
2447 DbExpression left = DbExpressionBuilder.Property(projectionBinding.Variable, inputBinding.VariableName);
2448 DbExpression right = DbExpressionBuilder.Property(projectionBinding.Variable, functorBinding.VariableName);
2449 TSelector selectorResult = selector(left, right);
2450 DbExpression projection = ResolveToExpression(selectorResult);
2451 return DbExpressionBuilder.Project(projectionBinding, projection);
2454 /// <summary>
2455 /// Creates a new <see cref="DbSkipExpression"/> that skips the specified number of elements from the given sorted input set.
2456 /// </summary>
2457 /// <param name="argument">A <see cref="DbSortExpression"/> that specifies the sorted input set.</param>
2458 /// <param name="count">An expression the specifies how many elements of the ordered set to skip.</param>
2459 /// <returns>A new DbSkipExpression that represents the skip operation.</returns>
2460 /// <exception cref="ArgumentNullException">
2461 /// <paramref name="argument"/> or <paramref name="count"/> is null.
2462 /// </exception>
2463 /// <exception cref="ArgumentException">
2464 /// <paramref name="count"/> is not <see cref="DbConstantExpression"/> or <see cref="DbParameterReferenceExpression"/> or has a
2465 /// result type that is not equal or promotable to a 64-bit integer type.
2466 /// </exception>
2467 public static DbSkipExpression Skip(this DbSortExpression argument, DbExpression count)
2469 EntityUtil.CheckArgumentNull(argument, "argument");
2470 return DbExpressionBuilder.Skip(argument.Input, argument.SortOrder, count);
2473 /// <summary>
2474 /// Creates a new <see cref="DbLimitExpression"/> that restricts the number of elements in the Argument collection to the specified count Limit value.
2475 /// Tied results are not included in the output.
2476 /// </summary>
2477 /// <param name="argument">An expression that specifies the input collection.</param>
2478 /// <param name="count">An expression that specifies the limit value.</param>
2479 /// <returns>A new DbLimitExpression with the specified argument and count limit values that does not include tied results.</returns>
2480 /// <exception cref="ArgumentNullException"><paramref name="argument"/> or <paramref name="count"/> is null</exception>
2481 /// <exception cref="ArgumentException">
2482 /// <paramref name="argument"/> does not have a collection result type,
2483 /// or <paramref name="count"/> does not have a result type that is equal or promotable to a 64-bit integer type.
2484 /// </exception>
2485 public static DbLimitExpression Take(this DbExpression argument, DbExpression count)
2487 return DbExpressionBuilder.Limit(argument, count);
2490 private static DbSortExpression CreateThenBy(DbSortExpression source, Func<DbExpression, DbExpression> sortKey, bool ascending, string collation, bool useCollation)
2492 EntityUtil.CheckArgumentNull(source, "source");
2493 EntityUtil.CheckArgumentNull(sortKey, "sortKey");
2494 DbExpression sortKeyResult = sortKey(source.Input.Variable);
2495 DbSortClause sortClause;
2496 if (useCollation)
2498 sortClause = (ascending ? DbExpressionBuilder.ToSortClause(sortKeyResult, collation) : DbExpressionBuilder.ToSortClauseDescending(sortKeyResult, collation));
2500 else
2502 sortClause = (ascending ? DbExpressionBuilder.ToSortClause(sortKeyResult) : DbExpressionBuilder.ToSortClauseDescending(sortKeyResult));
2505 List<DbSortClause> newSortOrder = new List<DbSortClause>(source.SortOrder.Count + 1);
2506 newSortOrder.AddRange(source.SortOrder);
2507 newSortOrder.Add(sortClause);
2509 return DbExpressionBuilder.Sort(source.Input, newSortOrder);
2512 /// <summary>
2513 /// Creates a new <see cref="DbSortExpression"/> that with a sort order that includes the sort order
2514 /// of the given order input set together with the specified sort key in ascending sort order and
2515 /// with default collation.
2516 /// </summary>
2517 /// <param name="source">A DbSortExpression that specifies the ordered input set.</param>
2518 /// <param name="sortKey">
2519 /// A method that specifies how to derive the additional sort key expression given a member of the
2520 /// input set.
2521 /// This method must produce an expression with an order-comparable result type that provides the
2522 /// sort key definition.
2523 /// </param>
2524 /// <returns>A new DbSortExpression that represents the new overall order-by operation.</returns>
2525 /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="sortKey"/> is null.</exception>
2526 /// <exception cref="ArgumentNullException">The expression produced by <paramref name="sortKey"/> is null.</exception>
2527 /// <exception cref="ArgumentException"><paramref name="source"/> does not have a collection result type.</exception>
2528 /// <exception cref="ArgumentException">
2529 /// The expression produced by <paramref name="sortKey"/> does not have an order-comparable result type.
2530 /// </exception>
2531 public static DbSortExpression ThenBy(this DbSortExpression source, Func<DbExpression, DbExpression> sortKey)
2533 return CreateThenBy(source, sortKey, true, null, false);
2536 /// <summary>
2537 /// Creates a new <see cref="DbSortExpression"/> that with a sort order that includes the sort order
2538 /// of the given order input set together with the specified sort key in ascending sort order and
2539 /// with the specified collation.
2540 /// </summary>
2541 /// <param name="source">A DbSortExpression that specifies the ordered input set.</param>
2542 /// <param name="sortKey">
2543 /// A method that specifies how to derive the additional sort key expression given a member of the
2544 /// input set.
2545 /// This method must produce an expression with an order-comparable result type that provides the
2546 /// sort key definition.
2547 /// </param>
2548 /// <param name="collation">The collation to sort under</param>
2549 /// <returns>A new DbSortExpression that represents the new overall order-by operation.</returns>
2550 /// <exception cref="ArgumentNullException"><paramref name="source"/>, <paramref name="sortKey"/> or <paramref name="collation"/> is null.</exception>
2551 /// <exception cref="ArgumentNullException">The expression produced by <paramref name="sortKey"/> is null.</exception>
2552 /// <exception cref="ArgumentException"><paramref name="source"/> does not have a collection result type.</exception>
2553 /// <exception cref="ArgumentException">
2554 /// The expression produced by <paramref name="sortKey"/> does not have an order-comparable string result type.
2555 /// </exception>
2556 /// <exception cref="ArgumentOutOfRangeException"><paramref name="collation"/> is empty or contains only space characters</exception>
2557 public static DbSortExpression ThenBy(this DbSortExpression source, Func<DbExpression, DbExpression> sortKey, string collation)
2559 return CreateThenBy(source, sortKey, true, collation, true);
2562 /// <summary>
2563 /// Creates a new <see cref="DbSortExpression"/> that with a sort order that includes the sort order
2564 /// of the given order input set together with the specified sort key in descending sort order and
2565 /// with default collation.
2566 /// </summary>
2567 /// <param name="source">A DbSortExpression that specifies the ordered input set.</param>
2568 /// <param name="sortKey">
2569 /// A method that specifies how to derive the additional sort key expression given a member of the
2570 /// input set.
2571 /// This method must produce an expression with an order-comparable result type that provides the
2572 /// sort key definition.
2573 /// </param>
2574 /// <returns>A new DbSortExpression that represents the new overall order-by operation.</returns>
2575 /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="sortKey"/> is null.</exception>
2576 /// <exception cref="ArgumentNullException">The expression produced by <paramref name="sortKey"/> is null.</exception>
2577 /// <exception cref="ArgumentException"><paramref name="source"/> does not have a collection result type.</exception>
2578 /// <exception cref="ArgumentException">
2579 /// The expression produced by <paramref name="sortKey"/> does not have an order-comparable result type.
2580 /// </exception>
2581 public static DbSortExpression ThenByDescending(this DbSortExpression source, Func<DbExpression, DbExpression> sortKey)
2583 return CreateThenBy(source, sortKey, false, null, false);
2586 /// <summary>
2587 /// Creates a new <see cref="DbSortExpression"/> that with a sort order that includes the sort order
2588 /// of the given order input set together with the specified sort key in descending sort order and
2589 /// with the specified collation.
2590 /// </summary>
2591 /// <param name="source">A DbSortExpression that specifies the ordered input set.</param>
2592 /// <param name="sortKey">
2593 /// A method that specifies how to derive the additional sort key expression given a member of the
2594 /// input set.
2595 /// This method must produce an expression with an order-comparable result type that provides the
2596 /// sort key definition.
2597 /// </param>
2598 /// <param name="collation">The collation to sort under</param>
2599 /// <returns>A new DbSortExpression that represents the new overall order-by operation.</returns>
2600 /// <exception cref="ArgumentNullException"><paramref name="source"/>, <paramref name="sortKey"/> or <paramref name="collation"/> is null.</exception>
2601 /// <exception cref="ArgumentNullException">The expression produced by <paramref name="sortKey"/> is null.</exception>
2602 /// <exception cref="ArgumentException"><paramref name="source"/> does not have a collection result type.</exception>
2603 /// <exception cref="ArgumentException">
2604 /// The expression produced by <paramref name="sortKey"/> does not have an order-comparable string result type.
2605 /// </exception>
2606 /// <exception cref="ArgumentOutOfRangeException"><paramref name="collation"/> is empty or contains only space characters</exception>
2607 public static DbSortExpression ThenByDescending(this DbSortExpression source, Func<DbExpression, DbExpression> sortKey, string collation)
2609 return CreateThenBy(source, sortKey, false, collation, true);
2612 /// <summary>
2613 /// Creates a new <see cref="DbFilterExpression"/> that filters the elements in the given input set using the specified predicate.
2614 /// </summary>
2615 /// <param name="source">
2616 /// An expression that specifies the input set.
2617 /// </param>
2618 /// <param name="predicate">
2619 /// A method representing the predicate to evaluate for each member of the input set.
2620 /// This method must produce an expression with a Boolean result type that provides
2621 /// the predicate logic.
2622 /// </param>
2623 /// <returns>A new DbQuantifierExpression that represents the Any operation.</returns>
2624 /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="predicate"/> is null</exception>
2625 /// <exception cref="ArgumentNullException">The expression produced by <paramref name="predicate"/> is null</exception>
2626 /// <exception cref="ArgumentException">
2627 /// The expression produced by <paramref name="predicate"/> does not have a Boolean result type.
2628 /// </exception>
2629 public static DbFilterExpression Where(this DbExpression source, Func<DbExpression, DbExpression> predicate)
2631 DbExpression predicateExp;
2632 DbExpressionBinding input = ConvertToBinding(source, predicate, "predicate", out predicateExp);
2633 return DbExpressionBuilder.Filter(input, predicateExp);
2636 /// <summary>
2637 /// Creates a new <see cref="DbExpression"/> that computes the union of the left and right set arguments with duplicates removed.
2638 /// </summary>
2639 /// <param name="left">An expression that defines the left set argument.</param>
2640 /// <param name="right">An expression that defines the right set argument.</param>
2641 /// <returns>A new DbExpression that computes the union, without duplicates, of the the left and right arguments.</returns>
2642 /// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
2643 /// <exception cref="ArgumentException">No common collection result type with an equality-comparable element type exists between <paramref name="left"/> and <paramref name="right"/>.</exception>
2644 public static DbExpression Union(this DbExpression left, DbExpression right)
2646 return DbExpressionBuilder.Distinct(DbExpressionBuilder.UnionAll(left, right));
2649 #endregion
2651 #region Internal Helper API - ideally these methods should be removed
2653 internal static AliasGenerator AliasGenerator
2655 get { return _bindingAliases; }
2658 internal static DbNullExpression CreatePrimitiveNullExpression(PrimitiveTypeKind primitiveType)
2660 switch(primitiveType)
2662 case PrimitiveTypeKind.Binary:
2663 return _binaryNull;
2664 case PrimitiveTypeKind.Boolean:
2665 return _boolNull;
2666 case PrimitiveTypeKind.Byte:
2667 return _byteNull;
2668 case PrimitiveTypeKind.DateTime:
2669 return _dateTimeNull;
2670 case PrimitiveTypeKind.DateTimeOffset:
2671 return _dateTimeOffsetNull;
2672 case PrimitiveTypeKind.Decimal:
2673 return _decimalNull;
2674 case PrimitiveTypeKind.Double:
2675 return _doubleNull;
2676 case PrimitiveTypeKind.Geography:
2677 return _geographyNull;
2678 case PrimitiveTypeKind.Geometry:
2679 return _geometryNull;
2680 case PrimitiveTypeKind.Guid:
2681 return _guidNull;
2682 case PrimitiveTypeKind.Int16:
2683 return _int16Null;
2684 case PrimitiveTypeKind.Int32:
2685 return _int32Null;
2686 case PrimitiveTypeKind.Int64:
2687 return _int64Null;
2688 case PrimitiveTypeKind.SByte:
2689 return _sbyteNull;
2690 case PrimitiveTypeKind.Single:
2691 return _singleNull;
2692 case PrimitiveTypeKind.String:
2693 return _stringNull;
2694 case PrimitiveTypeKind.Time:
2695 return _timeNull;
2697 default:
2698 throw EntityUtil.InvalidEnumerationValue(typeof(PrimitiveTypeKind), (int)primitiveType);
2702 internal static DbApplyExpression CreateApplyExpressionByKind(DbExpressionKind applyKind, DbExpressionBinding input, DbExpressionBinding apply)
2704 Debug.Assert(DbExpressionKind.CrossApply == applyKind || DbExpressionKind.OuterApply == applyKind, "Invalid ApplyType");
2706 switch (applyKind)
2708 case DbExpressionKind.CrossApply:
2709 return CrossApply(input, apply);
2711 case DbExpressionKind.OuterApply:
2712 return OuterApply(input, apply);
2714 default:
2715 throw EntityUtil.InvalidEnumerationValue(typeof(DbExpressionKind), (int)applyKind);
2719 internal static DbExpression CreateJoinExpressionByKind(DbExpressionKind joinKind, DbExpression joinCondition, DbExpressionBinding input1, DbExpressionBinding input2)
2721 Debug.Assert(DbExpressionKind.CrossJoin == joinKind ||
2722 DbExpressionKind.FullOuterJoin == joinKind ||
2723 DbExpressionKind.InnerJoin == joinKind ||
2724 DbExpressionKind.LeftOuterJoin == joinKind,
2725 "Invalid DbExpressionKind for CreateJoinExpressionByKind");
2727 if (DbExpressionKind.CrossJoin == joinKind)
2729 Debug.Assert(null == joinCondition, "Condition should not be specified for CrossJoin");
2730 return CrossJoin(new DbExpressionBinding[2] { input1, input2 });
2732 else
2734 Debug.Assert(joinCondition != null, "Condition must be specified for non-CrossJoin");
2736 switch (joinKind)
2738 case DbExpressionKind.InnerJoin:
2739 return InnerJoin(input1, input2, joinCondition);
2741 case DbExpressionKind.LeftOuterJoin:
2742 return LeftOuterJoin(input1, input2, joinCondition);
2744 case DbExpressionKind.FullOuterJoin:
2745 return FullOuterJoin(input1, input2, joinCondition);
2747 default:
2748 throw EntityUtil.InvalidEnumerationValue(typeof(DbExpressionKind), (int)joinKind);
2753 /// <summary>
2754 /// Used only by span rewriter, when a row could be specified as an argument
2755 /// </summary>
2756 internal static DbIsNullExpression CreateIsNullExpressionAllowingRowTypeArgument(DbExpression argument)
2758 TypeUsage resultType = ArgumentValidation.ValidateIsNull(argument, true);
2759 return new DbIsNullExpression(resultType, argument, true);
2762 /// <summary>
2763 /// Creates a new <see cref="DbElementExpression"/> that converts a single-member set with a single property
2764 /// into a singleton. The result type of the created <see cref="DbElementExpression"/> equals the result type
2765 /// of the single property of the element of the argument.
2766 ///
2767 /// This method should only be used when the argument is of a collection type with
2768 /// element of structured type with only one property.
2769 /// </summary>
2770 /// <param name="argument">An expression that specifies the input set.</param>
2771 /// <returns>A DbElementExpression that represents the conversion of the single-member set argument to a singleton.</returns>
2772 /// <exception cref="ArgumentNullException"><paramref name="argument"/> is null</exception>
2773 /// <exception cref="ArgumentException">
2774 /// <paramref name="argument"/> is associated with a different command tree,
2775 /// or does not have a collection result type, or its element type is not a structured type
2776 /// with only one property
2777 /// </exception>
2778 internal static DbElementExpression CreateElementExpressionUnwrapSingleProperty(DbExpression argument)
2780 TypeUsage resultType = ArgumentValidation.ValidateElement(argument);
2782 // Change the result type of the element expression to the type of the
2783 // single property of the element of its operand.
2784 IList<EdmProperty> properties = TypeHelpers.GetProperties(resultType);
2785 if (properties == null || properties.Count != 1)
2787 throw EntityUtil.Argument(System.Data.Entity.Strings.Cqt_Element_InvalidArgumentForUnwrapSingleProperty, "arg");
2789 resultType = properties[0].TypeUsage;
2790 return new DbElementExpression(resultType, argument, true);
2793 /// <summary>
2794 /// Creates a new <see cref="DbRelatedEntityRef"/> that describes how to satisfy the relationship
2795 /// navigation operation from <paramref name="sourceEnd"/> to <paramref name="targetEnd"/>, which
2796 /// must be declared by the same relationship type.
2797 /// DbRelatedEntityRefs are used in conjuction with <see cref="DbNewInstanceExpression"/>
2798 /// to construct Entity instances that are capable of resolving relationship navigation operations based on
2799 /// the provided DbRelatedEntityRefs without the need for additional navigation operations.
2800 /// Note also that this factory method is not intended to be part of the public Command Tree API
2801 /// since its intent is to support Entity constructors in view definitions that express information about
2802 /// related Entities using the 'WITH RELATIONSHIP' clause in eSQL.
2803 /// </summary>
2804 /// <param name="sourceEnd">The relationship end from which navigation takes place</param>
2805 ///<param name="targetEnd">The relationship end to which navigation may be satisifed using the target entity ref</param>
2806 ///<param name="targetEntity">An expression that produces a reference to the target entity (and must therefore have a Ref result type)</param>
2807 internal static DbRelatedEntityRef CreateRelatedEntityRef(RelationshipEndMember sourceEnd, RelationshipEndMember targetEnd, DbExpression targetEntity)
2809 return new DbRelatedEntityRef(sourceEnd, targetEnd, targetEntity);
2812 /// <summary>
2813 /// Creates a new <see cref="DbNewInstanceExpression"/> that constructs an instance of an Entity type
2814 /// together with the specified information about Entities related to the newly constructed Entity by
2815 /// relationship navigations where the target end has multiplicity of at most one.
2816 /// Note that this factory method is not intended to be part of the public Command Tree API since its
2817 /// intent is to support Entity constructors in view definitions that express information about
2818 /// related Entities using the 'WITH RELATIONSHIP' clause in eSQL.
2819 /// </summary>
2820 /// <param name="instanceType">The type of the Entity instance that is being constructed</param>
2821 /// <param name="attributeValues">Values for each (non-relationship) property of the Entity</param>
2822 /// <param name="relationships">A (possibly empty) list of <see cref="DbRelatedEntityRef"/>s that describe Entities that are related to the constructed Entity by various relationship types.</param>
2823 /// <returns>A new DbNewInstanceExpression that represents the construction of the Entity, and includes the specified related Entity information in the see <see cref="DbNewInstanceExpression.RelatedEntityReferences"/> collection.</returns>
2824 internal static DbNewInstanceExpression CreateNewEntityWithRelationshipsExpression(EntityType entityType, IList<DbExpression> attributeValues, IList<DbRelatedEntityRef> relationships)
2826 DbExpressionList validAttributes;
2827 System.Collections.ObjectModel.ReadOnlyCollection<DbRelatedEntityRef> validRelatedRefs;
2828 TypeUsage resultType = ArgumentValidation.ValidateNewEntityWithRelationships(entityType, attributeValues, relationships, out validAttributes, out validRelatedRefs);
2829 return new DbNewInstanceExpression(resultType, validAttributes, validRelatedRefs);
2832 /// <summary>
2833 /// Same as <see cref="Navigate(DbExpression, RelationshipEndMember, RelationshipEndMember)"/> only allows the property type of <paramref name="fromEnd"/>
2834 /// to be any type in the same type hierarchy as the result type of <paramref name="navigateFrom"/>.
2835 /// Only used by relationship span.
2836 /// </summary>
2837 /// <param name="navigateFrom"></param>
2838 /// <param name="fromEnd"></param>
2839 /// <param name="toEnd"></param>
2840 /// <returns></returns>
2841 internal static DbRelationshipNavigationExpression NavigateAllowingAllRelationshipsInSameTypeHierarchy(this DbExpression navigateFrom, RelationshipEndMember fromEnd, RelationshipEndMember toEnd)
2843 RelationshipType relType;
2844 TypeUsage resultType = ArgumentValidation.ValidateNavigate(navigateFrom, fromEnd, toEnd, out relType, allowAllRelationshipsInSameTypeHierarchy: true);
2845 return new DbRelationshipNavigationExpression(resultType, relType, fromEnd, toEnd, navigateFrom);
2848 internal static DbPropertyExpression CreatePropertyExpressionFromMember(DbExpression instance, EdmMember member)
2850 return PropertyFromMember(instance, member, "member");
2853 #if ENABLE_NESTAGGREGATE
2854 /// <summary>
2855 /// Creates a new <see cref="NestAggregate"/> over the specified argument
2856 /// </summary>
2857 /// <param name="argument">The argument over which to perform the nest operation</param>
2858 /// <returns>A new nest aggregate with a reference to the given argument.</returns>
2859 /// <exception cref="ArgumentNullException"><paramref name="argument"/> is null</exception>
2860 /// <exception cref="ArgumentException"><paramref name="argument"/> is associated with a different command tree</exception>
2861 /*CQT_PUBLIC_API(*/internal/*)*/ NestAggregate CreateNestAggregate(Expression argument)
2863 return new NestAggregate(this, argument);
2865 #endif
2867 #if METHOD_EXPRESSION
2868 /// <summary>
2869 /// Creates a new <see cref="MethodExpression"/> representing the invocation of the specified method on the given instance with the given arguments.
2870 /// </summary>
2871 /// <param name="methodInfo">The metadata for the method to invoke.</param>
2872 /// <param name="instance">The invocation target.</param>
2873 /// <param name="args">The arguments to the method.</param>
2874 /// <returns>A new MethodExpression that represents the method invocation.</returns>
2875 /// <exception cref="ArgumentNullException">
2876 /// <paramref name="methodInfo"/> or <paramref name="instance"/> is null,
2877 /// or <paramref name="args"/> is null or contains null
2878 /// </exception>
2879 /// <exception cref="ArgumentException">
2880 /// <paramref name="methodInfo"/> is not associated with this command tree's metadata workspace,
2881 /// <paramref name="instance"/> is associated with a different command tree
2882 /// or has a result type that is not equal or promotable to the declaring type of the method,
2883 /// or <paramref name="args"/> contains an incorrect number of expressions,
2884 /// an expression with a result type that is not equal or promotable to the type of the corresponding
2885 /// method parameter, or an expression that is associated with a different command tree.
2886 /// </exception>
2887 /*CQT_PUBLIC_API(*/internal/*)*/ MethodExpression CreateInstanceMethodExpression(MethodMetadata methodInfo, Expression instance, IList<Expression> args)
2889 if (methodInfo != null && methodInfo.IsStatic)
2891 throw EntityUtil.Argument(System.Data.Entity.Strings.Cqt_Factory_InstanceMethodRequired, "methodInfo");
2894 return new MethodExpression(this, methodInfo, args, instance);
2897 /// <summary>
2898 /// Creates a new <see cref="MethodExpression"/> representing the invocation of the specified method with the given arguments.
2899 /// </summary>
2900 /// <param name="methodInfo">The metadata for the method to invoke.</param>
2901 /// <param name="args">The arguments to the method.</param>
2902 /// <returns>A new MethodExpression that represents the method invocation.</returns>
2903 /// <exception cref="ArgumentNullException"><paramref name="methodInfo"/> is null, or <paramref name="args"/> is null or contains null</exception>
2904 /// <exception cref="ArgumentException">
2905 /// <paramref name="methodInfo"/> is not associated with this command tree's metadata workspace,
2906 /// or <paramref name="args"/> contains an incorrect number of expressions,
2907 /// an expression with a result type that is not equal or promotable to the type of the corresponding
2908 /// method parameter, or an expression that is associated with a different command tree.
2909 /// </exception>
2910 /*CQT_PUBLIC_API(*/internal/*)*/ MethodExpression CreateStaticMethodExpression(MethodMetadata methodInfo, IList<Expression> args)
2912 if (methodInfo != null && !methodInfo.IsStatic)
2914 throw EntityUtil.Argument(System.Data.Entity.Strings.Cqt_Factory_StaticMethodRequired, "methodInfo");
2917 return new MethodExpression(this, methodInfo, args, null);
2919 #endif
2921 #endregion