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