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 //---------------------------------------------------------------------
9 
10 namespace System.Data.Common.CommandTrees.ExpressionBuilder
11 {
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;
25 
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
31     {
32         #region Private Implementation
33 
34         private static readonly AliasGenerator _bindingAliases = new AliasGenerator("Var_", 0);
35 
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));
53 
54         private static readonly DbConstantExpression _boolTrue = Constant(true);
55         private static readonly DbConstantExpression _boolFalse = Constant(false);
56 
57         #endregion
58 
59         #region Helpers (not strictly Command Tree API)
60 
As(this DbExpression value, string alias)61         public static KeyValuePair<string, DbExpression> As(this DbExpression value, string alias)
62         {
63             return new KeyValuePair<string, DbExpression>(alias, value);
64         }
65 
As(this DbAggregate value, string alias)66         public static KeyValuePair<string, DbAggregate> As(this DbAggregate value, string alias)
67         {
68             return new KeyValuePair<string, DbAggregate>(alias, value);
69         }
70 
71         #endregion
72 
73         #region Bindings - Expression and Group
74 
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>
Bind(this DbExpression input)82         public static DbExpressionBinding Bind(this DbExpression input)
83         {
84             return DbExpressionBuilder.BindAs(input, _bindingAliases.Next());
85         }
86 
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>
BindAs(this DbExpression input, string varName)95         public static DbExpressionBinding BindAs(this DbExpression input, string varName)
96         {
97             TypeUsage elementType = ArgumentValidation.ValidateBindAs(input, varName);
98             DbVariableReferenceExpression inputRef = new DbVariableReferenceExpression(elementType, varName);
99             return new DbExpressionBinding(input, inputRef);
100         }
101 
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>
GroupBind(this DbExpression input)109         public static DbGroupExpressionBinding GroupBind(this DbExpression input)
110         {
111             string alias = _bindingAliases.Next();
112             return DbExpressionBuilder.GroupBindAs(input, alias, string.Format(CultureInfo.InvariantCulture, "Group{0}", alias));
113         }
114 
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>
GroupBindAs(this DbExpression input, string varName, string groupVarName)124         public static DbGroupExpressionBinding GroupBindAs(this DbExpression input, string varName, string groupVarName)
125         {
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);
130         }
131 
132         #endregion
133 
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
135 
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>
Aggregate(this EdmFunction function, DbExpression argument)148         public static DbFunctionAggregate Aggregate(this EdmFunction function, DbExpression argument)
149         {
150             return CreateFunctionAggregate(function, argument, false);
151         }
152 
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>
AggregateDistinct(this EdmFunction function, DbExpression argument)165         public static DbFunctionAggregate AggregateDistinct(this EdmFunction function, DbExpression argument)
166         {
167             return CreateFunctionAggregate(function, argument, true);
168         }
169 
CreateFunctionAggregate(EdmFunction function, DbExpression argument, bool isDistinct)170         private static DbFunctionAggregate CreateFunctionAggregate(EdmFunction function, DbExpression argument, bool isDistinct)
171         {
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);
176         }
177 
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>
GroupAggregate(DbExpression argument)184         /*ENABLE_ELEMENT_SELECTOR(*/internal/*)*/ static DbGroupAggregate GroupAggregate(DbExpression argument)
185         {
186             DbExpressionList arguments = ArgumentValidation.ValidateGroupAggregate(argument);
187             TypeUsage resultType = TypeHelpers.CreateCollectionTypeUsage(argument.ResultType);
188             return new DbGroupAggregate(resultType, arguments);
189         }
190 
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>
Lambda(DbExpression body, IEnumerable<DbVariableReferenceExpression> variables)206         public static DbLambda Lambda(DbExpression body, IEnumerable<DbVariableReferenceExpression> variables)
207         {
208             return CreateLambda(body, variables);
209         }
210 
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>
Lambda(DbExpression body, params DbVariableReferenceExpression[] variables)226         public static DbLambda Lambda(DbExpression body, params DbVariableReferenceExpression[] variables)
227         {
228             return CreateLambda(body, variables);
229         }
230 
CreateLambda(DbExpression body, IEnumerable<DbVariableReferenceExpression> variables)231         private static DbLambda CreateLambda(DbExpression body, IEnumerable<DbVariableReferenceExpression> variables)
232         {
233             var validVars = ArgumentValidation.ValidateLambda(variables, body);
234             return new DbLambda(validVars, body);
235         }
236 
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>
ToSortClause(this DbExpression key)244         public static DbSortClause ToSortClause(this DbExpression key)
245         {
246             ArgumentValidation.ValidateSortClause(key);
247             return new DbSortClause(key, true, String.Empty);
248         }
249 
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>
ToSortClauseDescending(this DbExpression key)257         public static DbSortClause ToSortClauseDescending(this DbExpression key)
258         {
259             ArgumentValidation.ValidateSortClause(key);
260             return new DbSortClause(key, false, String.Empty);
261         }
262 
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>
ToSortClause(this DbExpression key, string collation)272         public static DbSortClause ToSortClause(this DbExpression key, string collation)
273         {
274             ArgumentValidation.ValidateSortClause(key, collation);
275             return new DbSortClause(key, true, collation);
276         }
277 
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>
ToSortClauseDescending(this DbExpression key, string collation)287         public static DbSortClause ToSortClauseDescending(this DbExpression key, string collation)
288         {
289             ArgumentValidation.ValidateSortClause(key, collation);
290             return new DbSortClause(key, false, collation);
291         }
292 
293         #endregion
294 
295         #region Binding-based methods: All, Any, Cross|OuterApply, Cross|FullOuter|Inner|LeftOuterJoin, Filter, GroupBy, Project, Skip, Sort
296 
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>
All(this DbExpressionBinding input, DbExpression predicate)307         public static DbQuantifierExpression All(this DbExpressionBinding input, DbExpression predicate)
308         {
309             TypeUsage booleanResultType = ArgumentValidation.ValidateQuantifier(input, predicate);
310             return new DbQuantifierExpression(DbExpressionKind.All, booleanResultType, input, predicate);
311         }
312 
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>
Any(this DbExpressionBinding input, DbExpression predicate)323         public static DbQuantifierExpression Any(this DbExpressionBinding input, DbExpression predicate)
324         {
325             TypeUsage booleanResultType = ArgumentValidation.ValidateQuantifier(input, predicate);
326             return new DbQuantifierExpression(DbExpressionKind.Any, booleanResultType, input, predicate);
327         }
328 
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>
CrossApply(this DbExpressionBinding input, DbExpressionBinding apply)337         public static DbApplyExpression CrossApply(this DbExpressionBinding input, DbExpressionBinding apply)
338         {
339             TypeUsage resultType = ArgumentValidation.ValidateApply(input, apply);
340             return new DbApplyExpression(DbExpressionKind.CrossApply, resultType, input, apply);
341         }
342 
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>
OuterApply(this DbExpressionBinding input, DbExpressionBinding apply)351         public static DbApplyExpression OuterApply(this DbExpressionBinding input, DbExpressionBinding apply)
352         {
353             TypeUsage resultType = ArgumentValidation.ValidateApply(input, apply);
354             return new DbApplyExpression(DbExpressionKind.OuterApply, resultType, input, apply);
355         }
356 
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>
CrossJoin(IEnumerable<DbExpressionBinding> inputs)366         public static DbCrossJoinExpression CrossJoin(IEnumerable<DbExpressionBinding> inputs)
367         {
368             TypeUsage resultType;
369             System.Collections.ObjectModel.ReadOnlyCollection<DbExpressionBinding> validInputs = ArgumentValidation.ValidateCrossJoin(inputs, out resultType);
370             return new DbCrossJoinExpression(resultType, validInputs);
371         }
372 
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>
InnerJoin(this DbExpressionBinding left, DbExpressionBinding right, DbExpression joinCondition)390         public static DbJoinExpression InnerJoin(this DbExpressionBinding left, DbExpressionBinding right, DbExpression joinCondition)
391         {
392             TypeUsage resultType = ArgumentValidation.ValidateJoin(left, right, joinCondition);
393             return new DbJoinExpression(DbExpressionKind.InnerJoin, resultType, left, right, joinCondition);
394         }
395 
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>
LeftOuterJoin(this DbExpressionBinding left, DbExpressionBinding right, DbExpression joinCondition)413         public static DbJoinExpression LeftOuterJoin(this DbExpressionBinding left, DbExpressionBinding right, DbExpression joinCondition)
414         {
415             TypeUsage resultType = ArgumentValidation.ValidateJoin(left, right, joinCondition);
416             return new DbJoinExpression(DbExpressionKind.LeftOuterJoin, resultType, left, right, joinCondition);
417         }
418 
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>
FullOuterJoin(this DbExpressionBinding left, DbExpressionBinding right, DbExpression joinCondition)436         public static DbJoinExpression FullOuterJoin(this DbExpressionBinding left, DbExpressionBinding right, DbExpression joinCondition)
437         {
438             TypeUsage resultType = ArgumentValidation.ValidateJoin(left, right, joinCondition);
439             return new DbJoinExpression(DbExpressionKind.FullOuterJoin, resultType, left, right, joinCondition);
440         }
441 
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>
Filter(this DbExpressionBinding input, DbExpression predicate)452         public static DbFilterExpression Filter(this DbExpressionBinding input, DbExpression predicate)
453         {
454             TypeUsage resultType = ArgumentValidation.ValidateFilter(input, predicate);
455             return new DbFilterExpression(resultType, input, predicate);
456         }
457 
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>
GroupBy(this DbGroupExpressionBinding input, IEnumerable<KeyValuePair<string, DbExpression>> keys, IEnumerable<KeyValuePair<string, DbAggregate>> aggregates)477         public static DbGroupByExpression GroupBy(this DbGroupExpressionBinding input, IEnumerable<KeyValuePair<string, DbExpression>> keys, IEnumerable<KeyValuePair<string, DbAggregate>> aggregates)
478         {
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);
483         }
484 
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>
Project(this DbExpressionBinding input, DbExpression projection)492         public static DbProjectExpression Project(this DbExpressionBinding input, DbExpression projection)
493         {
494             TypeUsage resultType = ArgumentValidation.ValidateProject(input, projection);
495             return new DbProjectExpression(resultType, input, projection);
496         }
497 
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>
Skip(this DbExpressionBinding input, IEnumerable<DbSortClause> sortOrder, DbExpression count)514         public static DbSkipExpression Skip(this DbExpressionBinding input, IEnumerable<DbSortClause> sortOrder, DbExpression count)
515         {
516             System.Collections.ObjectModel.ReadOnlyCollection<DbSortClause> validSortOrder = ArgumentValidation.ValidateSkip(input, sortOrder, count);
517             return new DbSkipExpression(input.Expression.ResultType, input, validSortOrder, count);
518         }
519 
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>
Sort(this DbExpressionBinding input, IEnumerable<DbSortClause> sortOrder)533         public static DbSortExpression Sort(this DbExpressionBinding input, IEnumerable<DbSortClause> sortOrder)
534         {
535             System.Collections.ObjectModel.ReadOnlyCollection<DbSortClause> validSortOrder = ArgumentValidation.ValidateSort(input, sortOrder);
536             return new DbSortExpression(input.Expression.ResultType, input, validSortOrder);
537         }
538 
539         #endregion
540 
541         #region Leaf Expressions - Null, Constant, Parameter, Scan
542 
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
575 
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>
Null(this TypeUsage nullType)582         public static DbNullExpression Null(this TypeUsage nullType)
583         {
584             ArgumentValidation.ValidateNull(nullType);
585             return new DbNullExpression(nullType);
586         }
587 
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; } }
593 
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; } }
599 
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>
Constant(object value)607         public static DbConstantExpression Constant(object value)
608         {
609             TypeUsage constantType = ArgumentValidation.ValidateConstant(value);
610             return new DbConstantExpression(constantType, value);
611         }
612 
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>
Constant(this TypeUsage constantType, object value)625         public static DbConstantExpression Constant(this TypeUsage constantType, object value)
626         {
627             ArgumentValidation.ValidateConstant(constantType, value);
628             return new DbConstantExpression(constantType, value);
629         }
630 
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>
Parameter(this TypeUsage type, string name)640         public static DbParameterReferenceExpression Parameter(this TypeUsage type, string name)
641         {
642             ArgumentValidation.ValidateParameter(type, name);
643             return new DbParameterReferenceExpression(type, name);
644         }
645 
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>
Variable(this TypeUsage type, string name)655         public static DbVariableReferenceExpression Variable(this TypeUsage type, string name)
656         {
657             ArgumentValidation.ValidateVariable(type, name);
658             return new DbVariableReferenceExpression(type, name);
659         }
660 
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>
Scan(this EntitySetBase targetSet)667         public static DbScanExpression Scan(this EntitySetBase targetSet)
668         {
669             TypeUsage resultType = ArgumentValidation.ValidateScan(targetSet);
670             return new DbScanExpression(resultType, targetSet);
671         }
672 
673         #endregion
674 
675         #region Boolean Operators - And, Or, Not
676 
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>
And(this DbExpression left, DbExpression right)687         public static DbAndExpression And(this DbExpression left, DbExpression right)
688         {
689             TypeUsage resultType = ArgumentValidation.ValidateAnd(left, right);
690             return new DbAndExpression(resultType, left, right);
691         }
692 
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>
Or(this DbExpression left, DbExpression right)703         public static DbOrExpression Or(this DbExpression left, DbExpression right)
704         {
705             TypeUsage resultType = ArgumentValidation.ValidateOr(left, right);
706             return new DbOrExpression(resultType, left, right);
707         }
708 
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>
Not(this DbExpression argument)718         public static DbNotExpression Not(this DbExpression argument)
719         {
720             TypeUsage resultType = ArgumentValidation.ValidateNot(argument);
721             return new DbNotExpression(resultType, argument);
722         }
723 
724         #endregion
725 
726         #region Arithmetic Operators - Divide, Minus, Modulo, Multiply, Plus, UnaryMinus
727 
CreateArithmetic(DbExpressionKind kind, DbExpression left, DbExpression right)728         private static DbArithmeticExpression CreateArithmetic(DbExpressionKind kind, DbExpression left, DbExpression right)
729         {
730             TypeUsage numericResultType;
731             DbExpressionList arguments = ArgumentValidation.ValidateArithmetic(left, right, out numericResultType);
732             return new DbArithmeticExpression(kind, numericResultType, arguments);
733         }
734 
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>
Divide(this DbExpression left, DbExpression right)745         public static DbArithmeticExpression Divide(this DbExpression left, DbExpression right)
746         {
747             return CreateArithmetic(DbExpressionKind.Divide, left, right);
748         }
749 
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>
Minus(this DbExpression left, DbExpression right)760         public static DbArithmeticExpression Minus(this DbExpression left, DbExpression right)
761         {
762             return CreateArithmetic(DbExpressionKind.Minus, left, right);
763         }
764 
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>
Modulo(this DbExpression left, DbExpression right)775         public static DbArithmeticExpression Modulo(this DbExpression left, DbExpression right)
776         {
777             return CreateArithmetic(DbExpressionKind.Modulo, left, right);
778         }
779 
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>
Multiply(this DbExpression left, DbExpression right)790         public static DbArithmeticExpression Multiply(this DbExpression left, DbExpression right)
791         {
792             return CreateArithmetic(DbExpressionKind.Multiply, left, right);
793         }
794 
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>
Plus(this DbExpression left, DbExpression right)805         public static DbArithmeticExpression Plus(this DbExpression left, DbExpression right)
806         {
807             return CreateArithmetic(DbExpressionKind.Plus, left, right);
808         }
809 
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>
UnaryMinus(this DbExpression argument)819         public static DbArithmeticExpression UnaryMinus(this DbExpression argument)
820         {
821             TypeUsage resultType;
822             DbExpressionList args = ArgumentValidation.ValidateArithmetic(argument, out resultType);
823             return new DbArithmeticExpression(DbExpressionKind.UnaryMinus, resultType, args);
824         }
825 
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>
Negate(this DbExpression argument)835         public static DbArithmeticExpression Negate(this DbExpression argument)
836         {
837             return DbExpressionBuilder.UnaryMinus(argument);
838         }
839 
840         #endregion
841 
842         #region Comparison Operators - Equal, NotEqual, GreaterThan, LessThan, GreaterThanEqual, LessThanEqual, IsNull, Like
843 
CreateComparison(DbExpressionKind kind, DbExpression left, DbExpression right)844         private static DbComparisonExpression CreateComparison(DbExpressionKind kind, DbExpression left, DbExpression right)
845         {
846             TypeUsage resultType = ArgumentValidation.ValidateComparison(kind, left, right);
847             return new DbComparisonExpression(kind, resultType, left, right);
848         }
849 
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>
Equal(this DbExpression left, DbExpression right)860         public static DbComparisonExpression Equal(this DbExpression left, DbExpression right)
861         {
862             return DbExpressionBuilder.CreateComparison(DbExpressionKind.Equals, left, right);
863         }
864 
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>
NotEqual(this DbExpression left, DbExpression right)875         public static DbComparisonExpression NotEqual(this DbExpression left, DbExpression right)
876         {
877             return DbExpressionBuilder.CreateComparison(DbExpressionKind.NotEquals, left, right);
878         }
879 
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>
GreaterThan(this DbExpression left, DbExpression right)890         public static DbComparisonExpression GreaterThan(this DbExpression left, DbExpression right)
891         {
892             return DbExpressionBuilder.CreateComparison(DbExpressionKind.GreaterThan, left, right);
893         }
894 
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>
LessThan(this DbExpression left, DbExpression right)905         public static DbComparisonExpression LessThan(this DbExpression left, DbExpression right)
906         {
907             return DbExpressionBuilder.CreateComparison(DbExpressionKind.LessThan, left, right);
908         }
909 
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>
GreaterThanOrEqual(this DbExpression left, DbExpression right)920         public static DbComparisonExpression GreaterThanOrEqual(this DbExpression left, DbExpression right)
921         {
922             return DbExpressionBuilder.CreateComparison(DbExpressionKind.GreaterThanOrEquals, left, right);
923         }
924 
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>
LessThanOrEqual(this DbExpression left, DbExpression right)935         public static DbComparisonExpression LessThanOrEqual(this DbExpression left, DbExpression right)
936         {
937             return DbExpressionBuilder.CreateComparison(DbExpressionKind.LessThanOrEquals, left, right);
938         }
939 
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>
IsNull(this DbExpression argument)947         public static DbIsNullExpression IsNull(this DbExpression argument)
948         {
949             TypeUsage resultType = ArgumentValidation.ValidateIsNull(argument);
950             return new DbIsNullExpression(resultType, argument, false);
951         }
952 
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>
Like(this DbExpression argument, DbExpression pattern)961         public static DbLikeExpression Like(this DbExpression argument, DbExpression pattern)
962         {
963             TypeUsage resultType = ArgumentValidation.ValidateLike(argument, pattern);
964             DbExpression escape = DbExpressionBuilder.Null(pattern.ResultType);
965             return new DbLikeExpression(resultType, argument, pattern, escape);
966         }
967 
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>
Like(this DbExpression argument, DbExpression pattern, DbExpression escape)977         public static DbLikeExpression Like(this DbExpression argument, DbExpression pattern, DbExpression escape)
978         {
979             TypeUsage resultType = ArgumentValidation.ValidateLike(argument, pattern, escape);
980             return new DbLikeExpression(resultType, argument, pattern, escape);
981         }
982 
983         #endregion
984 
985         #region Type Operators - Cast, Treat, OfType, OfTypeOnly, IsOf, IsOfOnly
986 
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>
CastTo(this DbExpression argument, TypeUsage toType)995         public static DbCastExpression CastTo(this DbExpression argument, TypeUsage toType)
996         {
997             ArgumentValidation.ValidateCastTo(argument, toType);
998             return new DbCastExpression(toType, argument);
999         }
1000 
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>
TreatAs(this DbExpression argument, TypeUsage treatType)1014         public static DbTreatExpression TreatAs(this DbExpression argument, TypeUsage treatType)
1015         {
1016             ArgumentValidation.ValidateTreatAs(argument, treatType);
1017             return new DbTreatExpression(treatType, argument);
1018         }
1019 
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>
OfType(this DbExpression argument, TypeUsage type)1036         public static DbOfTypeExpression OfType(this DbExpression argument, TypeUsage type)
1037         {
1038             TypeUsage collectionOfTypeResultType = ArgumentValidation.ValidateOfType(argument, type);
1039             return new DbOfTypeExpression(DbExpressionKind.OfType, collectionOfTypeResultType, argument, type);
1040         }
1041 
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>
OfTypeOnly(this DbExpression argument, TypeUsage type)1058         public static DbOfTypeExpression OfTypeOnly(this DbExpression argument, TypeUsage type)
1059         {
1060             TypeUsage collectionOfTypeResultType = ArgumentValidation.ValidateOfType(argument, type);
1061             return new DbOfTypeExpression(DbExpressionKind.OfTypeOnly, collectionOfTypeResultType, argument, type);
1062         }
1063 
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>
IsOf(this DbExpression argument, TypeUsage type)1078         public static DbIsOfExpression IsOf(this DbExpression argument, TypeUsage type)
1079         {
1080             TypeUsage booleanResultType = ArgumentValidation.ValidateIsOf(argument, type);
1081             return new DbIsOfExpression(DbExpressionKind.IsOf, booleanResultType, argument, type);
1082         }
1083 
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>
IsOfOnly(this DbExpression argument, TypeUsage type)1098         public static DbIsOfExpression IsOfOnly(this DbExpression argument, TypeUsage type)
1099         {
1100             TypeUsage booleanResultType = ArgumentValidation.ValidateIsOf(argument, type);
1101             return new DbIsOfExpression(DbExpressionKind.IsOfOnly, booleanResultType, argument, type);
1102         }
1103 
1104         #endregion
1105 
1106         #region Ref Operators - Deref, EntityRef, Ref, RefKey, RelationshipNavigation
1107 
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")]
Deref(this DbExpression argument)1116         public static DbDerefExpression Deref(this DbExpression argument)
1117         {
1118             TypeUsage entityResultType = ArgumentValidation.ValidateDeref(argument);
1119             return new DbDerefExpression(entityResultType, argument);
1120         }
1121 
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>
GetEntityRef(this DbExpression argument)1129         public static DbEntityRefExpression GetEntityRef(this DbExpression argument)
1130         {
1131             TypeUsage refResultType = ArgumentValidation.ValidateGetEntityRef(argument);
1132             return new DbEntityRefExpression(refResultType, argument);
1133         }
1134 
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>
CreateRef(this EntitySet entitySet, IEnumerable<DbExpression> keyValues)1146         public static DbRefExpression CreateRef(this EntitySet entitySet, IEnumerable<DbExpression> keyValues)
1147         {
1148             return CreateRefExpression(entitySet, keyValues);
1149         }
1150 
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>
CreateRef(this EntitySet entitySet, params DbExpression[] keyValues)1162         public static DbRefExpression CreateRef(this EntitySet entitySet, params DbExpression[] keyValues)
1163         {
1164             return CreateRefExpression(entitySet, keyValues);
1165         }
1166 
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>
CreateRef(this EntitySet entitySet, EntityType entityType, IEnumerable<DbExpression> keyValues)1180         public static DbRefExpression CreateRef(this EntitySet entitySet, EntityType entityType, IEnumerable<DbExpression> keyValues)
1181         {
1182             return CreateRefExpression(entitySet, entityType, keyValues);
1183         }
1184 
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>
CreateRef(this EntitySet entitySet, EntityType entityType, params DbExpression[] keyValues)1198         public static DbRefExpression CreateRef(this EntitySet entitySet, EntityType entityType, params DbExpression[] keyValues)
1199         {
1200             return CreateRefExpression(entitySet, entityType, keyValues);
1201         }
1202 
CreateRefExpression(EntitySet entitySet, IEnumerable<DbExpression> keyValues)1203         private static DbRefExpression CreateRefExpression(EntitySet entitySet, IEnumerable<DbExpression> keyValues)
1204         {
1205             DbExpression keyConstructor;
1206             TypeUsage refResultType = ArgumentValidation.ValidateCreateRef(entitySet, keyValues, out keyConstructor);
1207             return new DbRefExpression(refResultType, entitySet, keyConstructor);
1208         }
1209 
CreateRefExpression(EntitySet entitySet, EntityType entityType, IEnumerable<DbExpression> keyValues)1210         private static DbRefExpression CreateRefExpression(EntitySet entitySet, EntityType entityType, IEnumerable<DbExpression> keyValues)
1211         {
1212             DbExpression keyConstructor;
1213             TypeUsage refResultType = ArgumentValidation.ValidateCreateRef(entitySet, entityType, keyValues, out keyConstructor);
1214             return new DbRefExpression(refResultType, entitySet, keyConstructor);
1215         }
1216 
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>
RefFromKey(this EntitySet entitySet, DbExpression keyRow)1231         public static DbRefExpression RefFromKey(this EntitySet entitySet, DbExpression keyRow)
1232         {
1233             TypeUsage refResultType = ArgumentValidation.ValidateRefFromKey(entitySet, keyRow);
1234             return new DbRefExpression(refResultType, entitySet, keyRow);
1235         }
1236 
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>
RefFromKey(this EntitySet entitySet, DbExpression keyRow, EntityType entityType)1253         public static DbRefExpression RefFromKey(this EntitySet entitySet, DbExpression keyRow, EntityType entityType)
1254         {
1255             TypeUsage refResultType = ArgumentValidation.ValidateRefFromKey(entitySet, keyRow, entityType);
1256             return new DbRefExpression(refResultType, entitySet, keyRow);
1257         }
1258 
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>
GetRefKey(this DbExpression argument)1266         public static DbRefKeyExpression GetRefKey(this DbExpression argument)
1267         {
1268             TypeUsage rowResultType = ArgumentValidation.ValidateGetRefKey(argument);
1269             return new DbRefKeyExpression(rowResultType, argument);
1270         }
1271 
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>
Navigate(this DbExpression navigateFrom, RelationshipEndMember fromEnd, RelationshipEndMember toEnd)1287         public static DbRelationshipNavigationExpression Navigate(this DbExpression navigateFrom, RelationshipEndMember fromEnd, RelationshipEndMember toEnd)
1288         {
1289             RelationshipType relType;
1290             TypeUsage resultType = ArgumentValidation.ValidateNavigate(navigateFrom, fromEnd, toEnd, out relType, allowAllRelationshipsInSameTypeHierarchy: false);
1291             return new DbRelationshipNavigationExpression(resultType, relType, fromEnd, toEnd, navigateFrom);
1292         }
1293 
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")]
Navigate(this RelationshipType type, string fromEndName, string toEndName, DbExpression navigateFrom)1314         public static DbRelationshipNavigationExpression Navigate(this RelationshipType type, string fromEndName, string toEndName, DbExpression navigateFrom)
1315         {
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);
1320         }
1321 
1322         #endregion
1323 
1324         #region Unary and Binary Set Operators - Distinct, Element, IsEmpty, Except, Intersect, UnionAll, Limit
1325 
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>
Distinct(this DbExpression argument)1333         public static DbDistinctExpression Distinct(this DbExpression argument)
1334         {
1335             TypeUsage resultType = ArgumentValidation.ValidateDistinct(argument);
1336             return new DbDistinctExpression(resultType, argument);
1337         }
1338 
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>
Element(this DbExpression argument)1346         public static DbElementExpression Element(this DbExpression argument)
1347         {
1348             TypeUsage resultType = ArgumentValidation.ValidateElement(argument);
1349             return new DbElementExpression(resultType, argument);
1350         }
1351 
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>
IsEmpty(this DbExpression argument)1359         public static DbIsEmptyExpression IsEmpty(this DbExpression argument)
1360         {
1361             TypeUsage booleanResultType = ArgumentValidation.ValidateIsEmpty(argument);
1362             return new DbIsEmptyExpression(booleanResultType, argument);
1363         }
1364 
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>
Except(this DbExpression left, DbExpression right)1373         public static DbExceptExpression Except(this DbExpression left, DbExpression right)
1374         {
1375             TypeUsage resultType = ArgumentValidation.ValidateExcept(left, right);
1376             return new DbExceptExpression(resultType, left, right);
1377         }
1378 
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>
Intersect(this DbExpression left, DbExpression right)1387         public static DbIntersectExpression Intersect(this DbExpression left, DbExpression right)
1388         {
1389             TypeUsage resultType = ArgumentValidation.ValidateIntersect(left, right);
1390             return new DbIntersectExpression(resultType, left, right);
1391         }
1392 
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>
UnionAll(this DbExpression left, DbExpression right)1401         public static DbUnionAllExpression UnionAll(this DbExpression left, DbExpression right)
1402         {
1403             TypeUsage resultType = ArgumentValidation.ValidateUnionAll(left, right);
1404             return new DbUnionAllExpression(resultType, left, right);
1405         }
1406 
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>
Limit(this DbExpression argument, DbExpression count)1419         public static DbLimitExpression Limit(this DbExpression argument, DbExpression count)
1420         {
1421             TypeUsage resultType = ArgumentValidation.ValidateLimit(argument, count);
1422             return new DbLimitExpression(resultType, argument, count, false);
1423         }
1424 
1425         #endregion
1426 
1427         #region General Operators - Case, Function, NewInstance, Property
1428 
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>
Case(IEnumerable<DbExpression> whenExpressions, IEnumerable<DbExpression> thenExpressions, DbExpression elseExpression)1444         public static DbCaseExpression Case(IEnumerable<DbExpression> whenExpressions, IEnumerable<DbExpression> thenExpressions, DbExpression elseExpression)
1445         {
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);
1450         }
1451 
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>
Invoke(this EdmFunction function, IEnumerable<DbExpression> arguments)1466         public static DbFunctionExpression Invoke(this EdmFunction function, IEnumerable<DbExpression> arguments)
1467         {
1468             return InvokeFunction(function, arguments);
1469         }
1470 
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>
Invoke(this EdmFunction function, params DbExpression[] arguments)1485         public static DbFunctionExpression Invoke(this EdmFunction function, params DbExpression[] arguments)
1486         {
1487             return InvokeFunction(function, arguments);
1488         }
1489 
InvokeFunction(EdmFunction function, IEnumerable<DbExpression> arguments)1490         private static DbFunctionExpression InvokeFunction(EdmFunction function, IEnumerable<DbExpression> arguments)
1491         {
1492             DbExpressionList validArguments;
1493             TypeUsage resultType = ArgumentValidation.ValidateFunction(function, arguments, out validArguments);
1494             return new DbFunctionExpression(resultType, function, validArguments);
1495         }
1496 
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>
Invoke(this DbLambda lambda, IEnumerable<DbExpression> arguments)1511         public static DbLambdaExpression Invoke(this DbLambda lambda, IEnumerable<DbExpression> arguments)
1512         {
1513             return InvokeLambda(lambda, arguments);
1514         }
1515 
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>
Invoke(this DbLambda lambda, params DbExpression[] arguments)1530         public static DbLambdaExpression Invoke(this DbLambda lambda, params DbExpression[] arguments)
1531         {
1532             return InvokeLambda(lambda, arguments);
1533         }
1534 
InvokeLambda(DbLambda lambda, IEnumerable<DbExpression> arguments)1535         private static DbLambdaExpression InvokeLambda(DbLambda lambda, IEnumerable<DbExpression> arguments)
1536         {
1537             DbExpressionList validArguments;
1538             TypeUsage resultType = ArgumentValidation.ValidateInvoke(lambda, arguments, out validArguments);
1539             return new DbLambdaExpression(resultType, lambda, validArguments);
1540         }
1541 
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>
New(this TypeUsage instanceType, IEnumerable<DbExpression> arguments)1565         public static DbNewInstanceExpression New(this TypeUsage instanceType, IEnumerable<DbExpression> arguments)
1566         {
1567             return NewInstance(instanceType, arguments);
1568         }
1569 
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>
New(this TypeUsage instanceType, params DbExpression[] arguments)1593         public static DbNewInstanceExpression New(this TypeUsage instanceType, params DbExpression[] arguments)
1594         {
1595             return NewInstance(instanceType, arguments);
1596         }
1597 
NewInstance(TypeUsage instanceType, IEnumerable<DbExpression> arguments)1598         private static DbNewInstanceExpression NewInstance(TypeUsage instanceType, IEnumerable<DbExpression> arguments)
1599         {
1600             DbExpressionList validArguments;
1601             TypeUsage resultType = ArgumentValidation.ValidateNew(instanceType, arguments, out validArguments);
1602             return new DbNewInstanceExpression(resultType, validArguments);
1603         }
1604 
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>
NewCollection(IEnumerable<DbExpression> elements)1614         public static DbNewInstanceExpression NewCollection(IEnumerable<DbExpression> elements)
1615         {
1616             return CreateNewCollection(elements);
1617         }
1618 
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>
NewCollection(params DbExpression[] elements)1628         public static DbNewInstanceExpression NewCollection(params DbExpression[] elements)
1629         {
1630             return CreateNewCollection(elements);
1631         }
1632 
CreateNewCollection(IEnumerable<DbExpression> elements)1633         private static DbNewInstanceExpression CreateNewCollection(IEnumerable<DbExpression> elements)
1634         {
1635             DbExpressionList validElements;
1636             TypeUsage collectionResultType = ArgumentValidation.ValidateNewCollection(elements, out validElements);
1637             return new DbNewInstanceExpression(collectionResultType, validElements);
1638         }
1639 
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>
NewEmptyCollection(this TypeUsage collectionType)1647         public static DbNewInstanceExpression NewEmptyCollection(this TypeUsage collectionType)
1648         {
1649             DbExpressionList validElements;
1650             TypeUsage validResultType = ArgumentValidation.ValidateNewEmptyCollection(collectionType, out validElements);
1651             return new DbNewInstanceExpression(validResultType, validElements);
1652         }
1653 
1654 
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>
NewRow(IEnumerable<KeyValuePair<string, DbExpression>> columnValues)1664         public static DbNewInstanceExpression NewRow(IEnumerable<KeyValuePair<string, DbExpression>> columnValues)
1665         {
1666             DbExpressionList validElements;
1667             TypeUsage resultType = ArgumentValidation.ValidateNewRow(columnValues, out validElements);
1668             return new DbNewInstanceExpression(resultType, validElements);
1669         }
1670 
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")]
Property(this DbExpression instance, EdmProperty propertyMetadata)1679         public static DbPropertyExpression Property(this DbExpression instance, EdmProperty propertyMetadata)
1680         {
1681             return PropertyFromMember(instance, propertyMetadata, "propertyMetadata");
1682         }
1683 
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")]
Property(this DbExpression instance, NavigationProperty navigationProperty)1692         public static DbPropertyExpression Property(this DbExpression instance, NavigationProperty navigationProperty)
1693         {
1694             return PropertyFromMember(instance, navigationProperty, "navigationProperty");
1695         }
1696 
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")]
Property(this DbExpression instance, RelationshipEndMember relationshipEnd)1705         public static DbPropertyExpression Property(this DbExpression instance, RelationshipEndMember relationshipEnd)
1706         {
1707             return PropertyFromMember(instance, relationshipEnd, "relationshipEnd");
1708         }
1709 
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>
Property(this DbExpression instance, string propertyName)1718         public static DbPropertyExpression Property(this DbExpression instance, string propertyName)
1719         {
1720             return PropertyByName(instance, propertyName, false);
1721         }
1722 
PropertyFromMember(DbExpression instance, EdmMember property, string propertyArgumentName)1723         private static DbPropertyExpression PropertyFromMember(DbExpression instance, EdmMember property, string propertyArgumentName)
1724         {
1725             TypeUsage resultType = ArgumentValidation.ValidateProperty(instance, property, propertyArgumentName);
1726             return new DbPropertyExpression(resultType, property, instance);
1727         }
1728 
PropertyByName(DbExpression instance, string propertyName, bool ignoreCase)1729         private static DbPropertyExpression PropertyByName(DbExpression instance, string propertyName, bool ignoreCase)
1730         {
1731             EdmMember property;
1732             TypeUsage resultType = ArgumentValidation.ValidateProperty(instance, propertyName, ignoreCase, out property);
1733             return new DbPropertyExpression(resultType, property, instance);
1734         }
1735 
1736         #endregion
1737 
1738         #region Lambda-based methods: All, Any, Cross|OuterApply, Cross|FullOuter|Inner|LeftOuterJoin, Filter, GroupBy, Project, Skip, Sort
1739 
ExtractAlias(MethodInfo method)1740         private static string ExtractAlias(MethodInfo method)
1741         {
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];
1746         }
1747 
ExtractAliases(MethodInfo method)1748         internal static string[] ExtractAliases(MethodInfo method)
1749         {
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)
1755             {
1756                 // Static lambda method has additional first closure parameter
1757                 start = 1;
1758                 paramCount = methodParams.Length - 1;
1759             }
1760             else
1761             {
1762                 // Otherwise, method parameters align directly with arguments
1763                 start = 0;
1764                 paramCount = methodParams.Length;
1765             }
1766 
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++)
1770             {
1771                 paramNames[idx - start] = (generateNames ? _bindingAliases.Next() : methodParams[idx].Name);
1772             }
1773             return paramNames;
1774         }
1775 
ConvertToBinding(DbExpression source, Func<DbExpression, TResult> argument, string argumentName, out TResult argumentResult)1776         private static DbExpressionBinding ConvertToBinding<TResult>(DbExpression source, Func<DbExpression, TResult> argument, string argumentName, out TResult argumentResult)
1777         {
1778             return ConvertToBinding(source, "source", argument, argumentName, out argumentResult);
1779         }
1780 
ConvertToBinding(DbExpression source, string sourceName, Func<DbExpression, TResult> argument, string argumentName, out TResult argumentResult)1781         private static DbExpressionBinding ConvertToBinding<TResult>(DbExpression source, string sourceName, Func<DbExpression, TResult> argument, string argumentName, out TResult argumentResult)
1782         {
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;
1789         }
1790 
ConvertToBinding(DbExpression left, string leftArgumentName, DbExpression right, string rightArgumentName, Func<DbExpression, DbExpression, DbExpression> argument, string argumentName, out DbExpression argumentExp)1791         private static DbExpressionBinding[] ConvertToBinding(DbExpression left, string leftArgumentName, DbExpression right, string rightArgumentName, Func<DbExpression, DbExpression, DbExpression> argument, string argumentName, out DbExpression argumentExp)
1792         {
1793             EntityUtil.CheckArgumentNull(left, leftArgumentName);
1794             EntityUtil.CheckArgumentNull(right, rightArgumentName);
1795 
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 };
1802         }
1803 
1804         [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
TryGetAnonymousTypeValues(object instance, out List<KeyValuePair<string, TRequired>> values)1805         private static bool TryGetAnonymousTypeValues<TInstance, TRequired>(object instance, out List<KeyValuePair<string, TRequired>> values)
1806         {
1807             Debug.Assert(instance != null, "Ensure instance is non-null before calling TryGetAnonymousTypeValues");
1808 
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
1813 
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)
1818             {
1819                 List<KeyValuePair<string, TRequired>> foundValues = null;
1820                 foreach (PropertyInfo pi in typeof(TInstance).GetProperties(BindingFlags.Public | BindingFlags.Instance))
1821                 {
1822                     if (pi.CanRead && typeof(TRequired).IsAssignableFrom(pi.PropertyType))
1823                     {
1824                         if (foundValues == null)
1825                         {
1826                             foundValues = new List<KeyValuePair<string, TRequired>>();
1827                         }
1828                         foundValues.Add(new KeyValuePair<string, TRequired>(pi.Name, (TRequired)pi.GetValue(instance, null)));
1829                     }
1830                     else
1831                     {
1832                         foundValues = null;
1833                         break;
1834                     }
1835                 }
1836                 values = foundValues;
1837             }
1838 
1839             return (values != null);
1840         }
1841 
TryResolveToConstant(Type type, object value, out DbExpression constantOrNullExpression)1842         private static bool TryResolveToConstant(Type type, object value, out DbExpression constantOrNullExpression)
1843         {
1844             constantOrNullExpression = null;
1845 
1846             Type valueType = type;
1847             if (type.IsGenericType && typeof(Nullable<>).Equals(type.GetGenericTypeDefinition()))
1848             {
1849                 valueType = type.GetGenericArguments()[0];
1850             }
1851 
1852             PrimitiveTypeKind primitiveTypeKind;
1853             if (ClrProviderManifest.Instance.TryGetPrimitiveTypeKind(valueType, out primitiveTypeKind))
1854             {
1855                 TypeUsage resultType = TypeHelpers.GetLiteralTypeUsage(primitiveTypeKind);
1856                 if (null == value)
1857                 {
1858                     constantOrNullExpression = DbExpressionBuilder.Null(resultType);
1859                 }
1860                 else
1861                 {
1862                     constantOrNullExpression = DbExpressionBuilder.Constant(resultType, value);
1863                 }
1864             }
1865 
1866             return (constantOrNullExpression != null);
1867         }
1868 
ResolveToExpression(TArgument argument)1869         private static DbExpression ResolveToExpression<TArgument>(TArgument argument)
1870         {
1871             object untypedArgument = argument;
1872 
1873             DbExpression constantResult;
1874             if (TryResolveToConstant(typeof(TArgument), untypedArgument, out constantResult))
1875             {
1876                 return constantResult;
1877             }
1878 
1879             if (null == untypedArgument)
1880             {
1881                 return (DbExpression)null;
1882             }
1883 
1884             // Direct DbExpression result
1885             if (typeof(DbExpression).IsAssignableFrom(typeof(TArgument)))
1886             {
1887                 return (DbExpression)untypedArgument;
1888             }
1889 
1890             // Row
1891             if (typeof(Row).Equals(typeof(TArgument)))
1892             {
1893                 return ((Row)untypedArgument).ToExpression();
1894             }
1895 
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))
1899             {
1900                 return DbExpressionBuilder.NewRow(columnValues);
1901             }
1902 
1903             // The specified instance cannot be resolved to a DbExpression
1904             throw EntityUtil.NotSupported(Strings.Cqt_Factory_MethodResultTypeNotSupported(typeof(TArgument).FullName));
1905         }
1906 
CreateApply(DbExpression source, Func<DbExpression, KeyValuePair<string, DbExpression>> apply, Func<DbExpressionBinding, DbExpressionBinding, DbApplyExpression> resultBuilder)1907         private static DbApplyExpression CreateApply(DbExpression source, Func<DbExpression, KeyValuePair<string, DbExpression>> apply, Func<DbExpressionBinding, DbExpressionBinding, DbApplyExpression> resultBuilder)
1908         {
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);
1913         }
1914 
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>
All(this DbExpression source, Func<DbExpression, DbExpression> predicate)1933         public static DbQuantifierExpression All(this DbExpression source, Func<DbExpression, DbExpression> predicate)
1934         {
1935             DbExpression predicateExp;
1936             DbExpressionBinding input = ConvertToBinding(source, predicate, "predicate", out predicateExp);
1937             return DbExpressionBuilder.All(input, predicateExp);
1938         }
1939 
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>
Any(this DbExpression source)1947         public static DbExpression Any(this DbExpression source)
1948         {
1949             return DbExpressionBuilder.Exists(source);
1950         }
1951 
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>
Exists(this DbExpression argument)1959         public static DbExpression Exists(this DbExpression argument)
1960         {
1961             return DbExpressionBuilder.Not(DbExpressionBuilder.IsEmpty(argument));
1962         }
1963 
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>
Any(this DbExpression source, Func<DbExpression, DbExpression> predicate)1982         public static DbQuantifierExpression Any(this DbExpression source, Func<DbExpression, DbExpression> predicate)
1983         {
1984             DbExpression predicateExp;
1985             DbExpressionBinding input = ConvertToBinding(source, predicate, "predicate", out predicateExp);
1986             return DbExpressionBuilder.Any(input, predicateExp);
1987         }
1988 
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>
CrossApply(this DbExpression source, Func<DbExpression, KeyValuePair<string, DbExpression>> apply)2004         public static DbApplyExpression CrossApply(this DbExpression source, Func<DbExpression, KeyValuePair<string, DbExpression>> apply)
2005         {
2006             return CreateApply(source, apply, DbExpressionBuilder.CrossApply);
2007         }
2008 
2009         //
2010 
2011 
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>
OuterApply(this DbExpression source, Func<DbExpression, KeyValuePair<string, DbExpression>> apply)2027         public static DbApplyExpression OuterApply(this DbExpression source, Func<DbExpression, KeyValuePair<string, DbExpression>> apply)
2028         {
2029             return CreateApply(source, apply, DbExpressionBuilder.OuterApply);
2030         }
2031 
2032         //
2033 
2034 
2035         //
2036 
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>
FullOuterJoin(this DbExpression left, DbExpression right, Func<DbExpression, DbExpression, DbExpression> joinCondition)2064         public static DbJoinExpression FullOuterJoin(this DbExpression left, DbExpression right, Func<DbExpression, DbExpression, DbExpression> joinCondition)
2065         {
2066             DbExpression condExp;
2067             DbExpressionBinding[] inputs = ConvertToBinding(left, "left", right, "right", joinCondition, "joinCondition", out condExp);
2068             return DbExpressionBuilder.FullOuterJoin(inputs[0], inputs[1], condExp);
2069         }
2070 
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>
InnerJoin(this DbExpression left, DbExpression right, Func<DbExpression, DbExpression, DbExpression> joinCondition)2098         public static DbJoinExpression InnerJoin(this DbExpression left, DbExpression right, Func<DbExpression, DbExpression, DbExpression> joinCondition)
2099         {
2100             DbExpression condExp;
2101             DbExpressionBinding[] inputs = ConvertToBinding(left, "left", right, "right", joinCondition, "joinCondition", out condExp);
2102             return DbExpressionBuilder.InnerJoin(inputs[0], inputs[1], condExp);
2103         }
2104 
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>
LeftOuterJoin(this DbExpression left, DbExpression right, Func<DbExpression, DbExpression, DbExpression> joinCondition)2132         public static DbJoinExpression LeftOuterJoin(this DbExpression left, DbExpression right, Func<DbExpression, DbExpression, DbExpression> joinCondition)
2133         {
2134             DbExpression condExp;
2135             DbExpressionBinding[] inputs = ConvertToBinding(left, "left", right, "right", joinCondition, "joinCondition", out condExp);
2136             return DbExpressionBuilder.LeftOuterJoin(inputs[0], inputs[1], condExp);
2137         }
2138 
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>
Join(this DbExpression outer, DbExpression inner, Func<DbExpression, DbExpression> outerKey, Func<DbExpression, DbExpression> innerKey)2163         public static DbJoinExpression Join(this DbExpression outer, DbExpression inner, Func<DbExpression, DbExpression> outerKey, Func<DbExpression, DbExpression> innerKey)
2164         {
2165             DbExpression leftOperand;
2166             DbExpressionBinding leftBinding = ConvertToBinding(outer, "outer", outerKey, "outerKey", out leftOperand);
2167 
2168             DbExpression rightOperand;
2169             DbExpressionBinding rightBinding = ConvertToBinding(inner, "inner", innerKey, "innerKey", out rightOperand);
2170 
2171             DbExpression joinCondition = DbExpressionBuilder.Equal(leftOperand, rightOperand);
2172 
2173             return DbExpressionBuilder.InnerJoin(leftBinding, rightBinding, joinCondition);
2174         }
2175 
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>
Join(this DbExpression outer, DbExpression inner, Func<DbExpression, DbExpression> outerKey, Func<DbExpression, DbExpression> innerKey, Func<DbExpression, DbExpression, TSelector> selector)2222         public static DbProjectExpression Join<TSelector>(this DbExpression outer, DbExpression inner, Func<DbExpression, DbExpression> outerKey, Func<DbExpression, DbExpression> innerKey, Func<DbExpression, DbExpression, TSelector> selector)
2223         {
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);
2226 
2227             // Ensure that the selector is non-null;
2228             EntityUtil.CheckArgumentNull(selector, "selector");
2229 
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);
2236 
2237             // Project the selector over the join expression and return the resulting DbProjectExpression
2238             return DbExpressionBuilder.Project(joinBinding, projection);
2239         }
2240 
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>
OrderBy(this DbExpression source, Func<DbExpression, DbExpression> sortKey)2258         public static DbSortExpression OrderBy(this DbExpression source, Func<DbExpression, DbExpression> sortKey)
2259         {
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 });
2264         }
2265 
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>
OrderBy(this DbExpression source, Func<DbExpression, DbExpression> sortKey, string collation)2285         public static DbSortExpression OrderBy(this DbExpression source, Func<DbExpression, DbExpression> sortKey, string collation)
2286         {
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 });
2291         }
2292 
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>
OrderByDescending(this DbExpression source, Func<DbExpression, DbExpression> sortKey)2310         public static DbSortExpression OrderByDescending(this DbExpression source, Func<DbExpression, DbExpression> sortKey)
2311         {
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 });
2316         }
2317 
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>
OrderByDescending(this DbExpression source, Func<DbExpression, DbExpression> sortKey, string collation)2337         public static DbSortExpression OrderByDescending(this DbExpression source, Func<DbExpression, DbExpression> sortKey, string collation)
2338         {
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 });
2343         }
2344 
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>
Select(this DbExpression source, Func<DbExpression, TProjection> projection)2368         public static DbProjectExpression Select<TProjection>(this DbExpression source, Func<DbExpression, TProjection> projection)
2369         {
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);
2375         }
2376 
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>
SelectMany(this DbExpression source, Func<DbExpression, DbExpression> apply)2393         public static DbProjectExpression SelectMany(this DbExpression source, Func<DbExpression, DbExpression> apply)
2394         {
2395             DbExpression functorResult;
2396             DbExpressionBinding inputBinding = ConvertToBinding(source, apply, "apply", out functorResult);
2397 
2398             DbExpressionBinding functorBinding = DbExpressionBuilder.Bind(functorResult);
2399             DbApplyExpression intermediateApply = DbExpressionBuilder.CrossApply(inputBinding, functorBinding);
2400 
2401             DbExpressionBinding projectionBinding = DbExpressionBuilder.Bind(intermediateApply);
2402             return DbExpressionBuilder.Project(projectionBinding, DbExpressionBuilder.Property(projectionBinding.Variable, functorBinding.VariableName));
2403         }
2404 
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>
SelectMany(this DbExpression source, Func<DbExpression, DbExpression> apply, Func<DbExpression, DbExpression, TSelector> selector)2437         public static DbProjectExpression SelectMany<TSelector>(this DbExpression source, Func<DbExpression, DbExpression> apply, Func<DbExpression, DbExpression, TSelector> selector)
2438         {
2439             DbExpression functorResult;
2440             DbExpressionBinding inputBinding = ConvertToBinding(source, apply, "apply", out functorResult);
2441             EntityUtil.CheckArgumentNull(selector, "selector");
2442 
2443             DbExpressionBinding functorBinding = DbExpressionBuilder.Bind(functorResult);
2444             DbApplyExpression intermediateApply = DbExpressionBuilder.CrossApply(inputBinding, functorBinding);
2445 
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);
2452         }
2453 
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>
Skip(this DbSortExpression argument, DbExpression count)2467         public static DbSkipExpression Skip(this DbSortExpression argument, DbExpression count)
2468         {
2469             EntityUtil.CheckArgumentNull(argument, "argument");
2470             return DbExpressionBuilder.Skip(argument.Input, argument.SortOrder, count);
2471         }
2472 
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>
Take(this DbExpression argument, DbExpression count)2485         public static DbLimitExpression Take(this DbExpression argument, DbExpression count)
2486         {
2487             return DbExpressionBuilder.Limit(argument, count);
2488         }
2489 
CreateThenBy(DbSortExpression source, Func<DbExpression, DbExpression> sortKey, bool ascending, string collation, bool useCollation)2490         private static DbSortExpression CreateThenBy(DbSortExpression source, Func<DbExpression, DbExpression> sortKey, bool ascending, string collation, bool useCollation)
2491         {
2492             EntityUtil.CheckArgumentNull(source, "source");
2493             EntityUtil.CheckArgumentNull(sortKey, "sortKey");
2494             DbExpression sortKeyResult = sortKey(source.Input.Variable);
2495             DbSortClause sortClause;
2496             if (useCollation)
2497             {
2498                 sortClause = (ascending ? DbExpressionBuilder.ToSortClause(sortKeyResult, collation) : DbExpressionBuilder.ToSortClauseDescending(sortKeyResult, collation));
2499             }
2500             else
2501             {
2502                 sortClause = (ascending ? DbExpressionBuilder.ToSortClause(sortKeyResult) : DbExpressionBuilder.ToSortClauseDescending(sortKeyResult));
2503             }
2504 
2505             List<DbSortClause> newSortOrder = new List<DbSortClause>(source.SortOrder.Count + 1);
2506             newSortOrder.AddRange(source.SortOrder);
2507             newSortOrder.Add(sortClause);
2508 
2509             return DbExpressionBuilder.Sort(source.Input, newSortOrder);
2510         }
2511 
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>
ThenBy(this DbSortExpression source, Func<DbExpression, DbExpression> sortKey)2531         public static DbSortExpression ThenBy(this DbSortExpression source, Func<DbExpression, DbExpression> sortKey)
2532         {
2533             return CreateThenBy(source, sortKey, true, null, false);
2534         }
2535 
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>
ThenBy(this DbSortExpression source, Func<DbExpression, DbExpression> sortKey, string collation)2557         public static DbSortExpression ThenBy(this DbSortExpression source, Func<DbExpression, DbExpression> sortKey, string collation)
2558         {
2559             return CreateThenBy(source, sortKey, true, collation, true);
2560         }
2561 
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>
ThenByDescending(this DbSortExpression source, Func<DbExpression, DbExpression> sortKey)2581         public static DbSortExpression ThenByDescending(this DbSortExpression source, Func<DbExpression, DbExpression> sortKey)
2582         {
2583             return CreateThenBy(source, sortKey, false, null, false);
2584         }
2585 
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>
ThenByDescending(this DbSortExpression source, Func<DbExpression, DbExpression> sortKey, string collation)2607         public static DbSortExpression ThenByDescending(this DbSortExpression source, Func<DbExpression, DbExpression> sortKey, string collation)
2608         {
2609             return CreateThenBy(source, sortKey, false, collation, true);
2610         }
2611 
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>
Where(this DbExpression source, Func<DbExpression, DbExpression> predicate)2629         public static DbFilterExpression Where(this DbExpression source, Func<DbExpression, DbExpression> predicate)
2630         {
2631             DbExpression predicateExp;
2632             DbExpressionBinding input = ConvertToBinding(source, predicate, "predicate", out predicateExp);
2633             return DbExpressionBuilder.Filter(input, predicateExp);
2634         }
2635 
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>
Union(this DbExpression left, DbExpression right)2644         public static DbExpression Union(this DbExpression left, DbExpression right)
2645         {
2646             return DbExpressionBuilder.Distinct(DbExpressionBuilder.UnionAll(left, right));
2647         }
2648 
2649         #endregion
2650 
2651         #region Internal Helper API - ideally these methods should be removed
2652 
2653         internal static AliasGenerator AliasGenerator
2654         {
2655             get { return _bindingAliases; }
2656         }
2657 
CreatePrimitiveNullExpression(PrimitiveTypeKind primitiveType)2658         internal static DbNullExpression CreatePrimitiveNullExpression(PrimitiveTypeKind primitiveType)
2659         {
2660             switch(primitiveType)
2661             {
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;
2696 
2697                 default:
2698                     throw EntityUtil.InvalidEnumerationValue(typeof(PrimitiveTypeKind), (int)primitiveType);
2699             }
2700         }
2701 
CreateApplyExpressionByKind(DbExpressionKind applyKind, DbExpressionBinding input, DbExpressionBinding apply)2702         internal static DbApplyExpression CreateApplyExpressionByKind(DbExpressionKind applyKind, DbExpressionBinding input, DbExpressionBinding apply)
2703         {
2704             Debug.Assert(DbExpressionKind.CrossApply == applyKind || DbExpressionKind.OuterApply == applyKind, "Invalid ApplyType");
2705 
2706             switch (applyKind)
2707             {
2708                 case DbExpressionKind.CrossApply:
2709                     return CrossApply(input, apply);
2710 
2711                 case DbExpressionKind.OuterApply:
2712                     return OuterApply(input, apply);
2713 
2714                 default:
2715                     throw EntityUtil.InvalidEnumerationValue(typeof(DbExpressionKind), (int)applyKind);
2716             }
2717         }
2718 
CreateJoinExpressionByKind(DbExpressionKind joinKind, DbExpression joinCondition, DbExpressionBinding input1, DbExpressionBinding input2)2719         internal static DbExpression CreateJoinExpressionByKind(DbExpressionKind joinKind, DbExpression joinCondition, DbExpressionBinding input1, DbExpressionBinding input2)
2720         {
2721             Debug.Assert(DbExpressionKind.CrossJoin == joinKind ||
2722                          DbExpressionKind.FullOuterJoin == joinKind ||
2723                          DbExpressionKind.InnerJoin == joinKind ||
2724                          DbExpressionKind.LeftOuterJoin == joinKind,
2725                          "Invalid DbExpressionKind for CreateJoinExpressionByKind");
2726 
2727             if (DbExpressionKind.CrossJoin == joinKind)
2728             {
2729                 Debug.Assert(null == joinCondition, "Condition should not be specified for CrossJoin");
2730                 return CrossJoin(new DbExpressionBinding[2] { input1, input2 });
2731             }
2732             else
2733             {
2734                 Debug.Assert(joinCondition != null, "Condition must be specified for non-CrossJoin");
2735 
2736                 switch (joinKind)
2737                 {
2738                     case DbExpressionKind.InnerJoin:
2739                         return InnerJoin(input1, input2, joinCondition);
2740 
2741                     case DbExpressionKind.LeftOuterJoin:
2742                         return LeftOuterJoin(input1, input2, joinCondition);
2743 
2744                     case DbExpressionKind.FullOuterJoin:
2745                         return FullOuterJoin(input1, input2, joinCondition);
2746 
2747                     default:
2748                         throw EntityUtil.InvalidEnumerationValue(typeof(DbExpressionKind), (int)joinKind);
2749                 }
2750             }
2751         }
2752 
2753         /// <summary>
2754         /// Used only by span rewriter, when a row could be specified as an argument
2755         /// </summary>
CreateIsNullExpressionAllowingRowTypeArgument(DbExpression argument)2756         internal static DbIsNullExpression CreateIsNullExpressionAllowingRowTypeArgument(DbExpression argument)
2757         {
2758             TypeUsage resultType = ArgumentValidation.ValidateIsNull(argument, true);
2759             return new DbIsNullExpression(resultType, argument, true);
2760         }
2761 
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>
CreateElementExpressionUnwrapSingleProperty(DbExpression argument)2778         internal static DbElementExpression CreateElementExpressionUnwrapSingleProperty(DbExpression argument)
2779         {
2780             TypeUsage resultType = ArgumentValidation.ValidateElement(argument);
2781 
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)
2786             {
2787                 throw EntityUtil.Argument(System.Data.Entity.Strings.Cqt_Element_InvalidArgumentForUnwrapSingleProperty, "arg");
2788             }
2789             resultType = properties[0].TypeUsage;
2790             return new DbElementExpression(resultType, argument, true);
2791         }
2792 
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>
CreateRelatedEntityRef(RelationshipEndMember sourceEnd, RelationshipEndMember targetEnd, DbExpression targetEntity)2807         internal static DbRelatedEntityRef CreateRelatedEntityRef(RelationshipEndMember sourceEnd, RelationshipEndMember targetEnd, DbExpression targetEntity)
2808         {
2809             return new DbRelatedEntityRef(sourceEnd, targetEnd, targetEntity);
2810         }
2811 
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>
CreateNewEntityWithRelationshipsExpression(EntityType entityType, IList<DbExpression> attributeValues, IList<DbRelatedEntityRef> relationships)2824         internal static DbNewInstanceExpression CreateNewEntityWithRelationshipsExpression(EntityType entityType, IList<DbExpression> attributeValues, IList<DbRelatedEntityRef> relationships)
2825         {
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);
2830         }
2831 
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>
NavigateAllowingAllRelationshipsInSameTypeHierarchy(this DbExpression navigateFrom, RelationshipEndMember fromEnd, RelationshipEndMember toEnd)2841         internal static DbRelationshipNavigationExpression NavigateAllowingAllRelationshipsInSameTypeHierarchy(this DbExpression navigateFrom, RelationshipEndMember fromEnd, RelationshipEndMember toEnd)
2842         {
2843             RelationshipType relType;
2844             TypeUsage resultType = ArgumentValidation.ValidateNavigate(navigateFrom, fromEnd, toEnd, out relType, allowAllRelationshipsInSameTypeHierarchy: true);
2845             return new DbRelationshipNavigationExpression(resultType, relType, fromEnd, toEnd, navigateFrom);
2846         }
2847 
CreatePropertyExpressionFromMember(DbExpression instance, EdmMember member)2848         internal static DbPropertyExpression CreatePropertyExpressionFromMember(DbExpression instance, EdmMember member)
2849         {
2850             return PropertyFromMember(instance, member, "member");
2851         }
2852 
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>
CreateNestAggregate(Expression argument)2861         /*CQT_PUBLIC_API(*/internal/*)*/ NestAggregate CreateNestAggregate(Expression argument)
2862         {
2863             return new NestAggregate(this, argument);
2864         }
2865 #endif
2866 
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>
CreateInstanceMethodExpression(MethodMetadata methodInfo, Expression instance, IList<Expression> args)2887         /*CQT_PUBLIC_API(*/internal/*)*/ MethodExpression CreateInstanceMethodExpression(MethodMetadata methodInfo, Expression instance, IList<Expression> args)
2888         {
2889             if (methodInfo != null && methodInfo.IsStatic)
2890             {
2891                 throw EntityUtil.Argument(System.Data.Entity.Strings.Cqt_Factory_InstanceMethodRequired, "methodInfo");
2892             }
2893 
2894             return new MethodExpression(this, methodInfo, args, instance);
2895         }
2896 
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>
CreateStaticMethodExpression(MethodMetadata methodInfo, IList<Expression> args)2910         /*CQT_PUBLIC_API(*/internal/*)*/ MethodExpression CreateStaticMethodExpression(MethodMetadata methodInfo, IList<Expression> args)
2911         {
2912             if (methodInfo != null && !methodInfo.IsStatic)
2913             {
2914                 throw EntityUtil.Argument(System.Data.Entity.Strings.Cqt_Factory_StaticMethodRequired, "methodInfo");
2915             }
2916 
2917             return new MethodExpression(this, methodInfo, args, null);
2918         }
2919 #endif
2920 
2921         #endregion
2922     }
2923 }
2924