|
//---------------------------------------------------------------------
// <copyright file="DbExpressionBuilder.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner Microsoft
// @backupOwner Microsoft
//---------------------------------------------------------------------
namespace System.Data.Common.CommandTrees.ExpressionBuilder
{
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Data.Common.CommandTrees.ExpressionBuilder.Internal;
using System.Data.Common.CommandTrees.Internal;
using System.Data.Common.Utils;
using System.Data.Entity;
using System.Data.Metadata.Edm;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
/// <summary>
/// Provides an API to construct <see cref="DbExpression"/>s and allows that API to be accessed as extension methods on the expression type itself.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Db")]
public static class DbExpressionBuilder
{
#region Private Implementation
private static readonly AliasGenerator _bindingAliases = new AliasGenerator("Var_", 0);
private static readonly DbNullExpression _binaryNull = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.Binary));
private static readonly DbNullExpression _boolNull = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.Boolean));
private static readonly DbNullExpression _byteNull = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.Byte));
private static readonly DbNullExpression _dateTimeNull = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.DateTime));
private static readonly DbNullExpression _dateTimeOffsetNull = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.DateTimeOffset));
private static readonly DbNullExpression _decimalNull = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.Decimal));
private static readonly DbNullExpression _doubleNull = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.Double));
private static readonly DbNullExpression _geographyNull = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.Geography));
private static readonly DbNullExpression _geometryNull = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.Geometry));
private static readonly DbNullExpression _guidNull = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.Guid));
private static readonly DbNullExpression _int16Null = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.Int16));
private static readonly DbNullExpression _int32Null = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.Int32));
private static readonly DbNullExpression _int64Null = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.Int64));
private static readonly DbNullExpression _sbyteNull = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.SByte));
private static readonly DbNullExpression _singleNull = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.Single));
private static readonly DbNullExpression _stringNull = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.String));
private static readonly DbNullExpression _timeNull = Null(EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(PrimitiveTypeKind.Time));
private static readonly DbConstantExpression _boolTrue = Constant(true);
private static readonly DbConstantExpression _boolFalse = Constant(false);
#endregion
#region Helpers (not strictly Command Tree API)
public static KeyValuePair<string, DbExpression> As(this DbExpression value, string alias)
{
return new KeyValuePair<string, DbExpression>(alias, value);
}
public static KeyValuePair<string, DbAggregate> As(this DbAggregate value, string alias)
{
return new KeyValuePair<string, DbAggregate>(alias, value);
}
#endregion
#region Bindings - Expression and Group
/// <summary>
/// Creates a new <see cref="DbExpressionBinding"/> that uses a generated variable name to bind the given expression
/// </summary>
/// <param name="input">The expression to bind</param>
/// <returns>A new expression binding with the specified expression and a generated variable name</returns>
/// <exception cref="ArgumentNullException"><paramref name="input"/> is null</exception>
/// <exception cref="ArgumentException"><paramref name="input"/> does not have a collection result type</exception>
public static DbExpressionBinding Bind(this DbExpression input)
{
return DbExpressionBuilder.BindAs(input, _bindingAliases.Next());
}
/// <summary>
/// Creates a new <see cref="DbExpressionBinding"/> that uses the specified variable name to bind the given expression
/// </summary>
/// <param name="input">The expression to bind</param>
/// <param name="varName">The variable name that should be used for the binding</param>
/// <returns>A new expression binding with the specified expression and variable name</returns>
/// <exception cref="ArgumentNullException"><paramref name="input"/> or <paramref name="varName"/> is null</exception>
/// <exception cref="ArgumentException"><paramref name="input"/> does not have a collection result type</exception>
public static DbExpressionBinding BindAs(this DbExpression input, string varName)
{
TypeUsage elementType = ArgumentValidation.ValidateBindAs(input, varName);
DbVariableReferenceExpression inputRef = new DbVariableReferenceExpression(elementType, varName);
return new DbExpressionBinding(input, inputRef);
}
/// <summary>
/// Creates a new group expression binding that uses generated variable and group variable names to bind the given expression
/// </summary>
/// <param name="input">The expression to bind</param>
/// <returns>A new group expression binding with the specified expression and a generated variable name and group variable name</returns>
/// <exception cref="ArgumentNullException"><paramref name="input"/> is null</exception>
/// <exception cref="ArgumentException"><paramref name="input"/> does not have a collection result type</exception>
public static DbGroupExpressionBinding GroupBind(this DbExpression input)
{
string alias = _bindingAliases.Next();
return DbExpressionBuilder.GroupBindAs(input, alias, string.Format(CultureInfo.InvariantCulture, "Group{0}", alias));
}
/// <summary>
/// Creates a new <see cref="DbGroupExpressionBinding"/> that uses the specified variable name and group variable names to bind the given expression
/// </summary>
/// <param name="input">The expression to bind</param>
/// <param name="varName">The variable name that should be used for the binding</param>
/// <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>
/// <returns>A new group expression binding with the specified expression, variable name and group variable name</returns>
/// <exception cref="ArgumentNullException"><paramref name="input"/>, <paramref name="varName"/> or <paramref name="groupVarName"/> is null</exception>
/// <exception cref="ArgumentException"><paramref name="input"/> does not have a collection result type</exception>
public static DbGroupExpressionBinding GroupBindAs(this DbExpression input, string varName, string groupVarName)
{
TypeUsage elementType = ArgumentValidation.ValidateGroupBindAs(input, varName, groupVarName);
DbVariableReferenceExpression inputRef = new DbVariableReferenceExpression(elementType, varName);
DbVariableReferenceExpression groupRef = new DbVariableReferenceExpression(elementType, groupVarName);
return new DbGroupExpressionBinding(input, inputRef, groupRef);
}
#endregion
#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
/// <summary>
/// Creates a new <see cref="DbFunctionAggregate"/>.
/// </summary>
/// <param name="function">The function that defines the aggregate operation.</param>
/// <param name="argument">The argument over which the aggregate function should be calculated.</param>
/// <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>
/// <exception cref="ArgumentNullException"><paramref name="function"/> or <paramref name="argument"/> is null</exception>
/// <exception cref="ArgumentException">
/// <paramref name="function"/> is not an aggregate function or has more than one argument, or
/// the result type of <paramref name="argument"/> is not equal or promotable to
/// the parameter type of <paramref name="function"/>
/// </exception>
public static DbFunctionAggregate Aggregate(this EdmFunction function, DbExpression argument)
{
return CreateFunctionAggregate(function, argument, false);
}
/// <summary>
/// Creates a new <see cref="DbFunctionAggregate"/> that is applied in a distinct fashion.
/// </summary>
/// <param name="function">The function that defines the aggregate operation.</param>
/// <param name="argument">The argument over which the aggregate function should be calculated.</param>
/// <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>
/// <exception cref="ArgumentNullException"><paramref name="function"/> or <paramref name="argument"/> is null</exception>
/// <exception cref="ArgumentException">
/// <paramref name="function"/> is not an aggregate function or has more than one argument, or
/// the result type of <paramref name="argument"/> is not equal or promotable to
/// the parameter type of <paramref name="function"/>
/// </exception>
public static DbFunctionAggregate AggregateDistinct(this EdmFunction function, DbExpression argument)
{
return CreateFunctionAggregate(function, argument, true);
}
private static DbFunctionAggregate CreateFunctionAggregate(EdmFunction function, DbExpression argument, bool isDistinct)
{
EntityUtil.CheckArgumentNull(argument, "argument");
DbExpressionList funcArgs = ArgumentValidation.ValidateFunctionAggregate(function, new[] { argument });
TypeUsage resultType = function.ReturnParameter.TypeUsage;
return new DbFunctionAggregate(resultType, funcArgs, function, isDistinct);
}
/// <summary>
/// Creates a new <see cref="DbGroupAggregate"/> over the specified argument
/// </summary>
/// <param name="argument">The argument over which to perform the nest operation</param>
/// <returns>A new group aggregate representing the elements of the group referenced by the given argument.</returns>
/// <exception cref="ArgumentNullException"><paramref name="argument"/> is null</exception>
/*ENABLE_ELEMENT_SELECTOR(*/internal/*)*/ static DbGroupAggregate GroupAggregate(DbExpression argument)
{
DbExpressionList arguments = ArgumentValidation.ValidateGroupAggregate(argument);
TypeUsage resultType = TypeHelpers.CreateCollectionTypeUsage(argument.ResultType);
return new DbGroupAggregate(resultType, arguments);
}
/// <summary>
/// Creates a <see cref="DbLambda"/> with the specified inline Lambda function implementation and formal parameters.
/// </summary>
/// <param name="body">An expression that defines the logic of the Lambda function</param>
/// <param name="variables">
/// A <see cref="DbVariableReferenceExpression"/> collection that represents the formal parameters to the Lambda function.
/// These variables are valid for use in the <paramref name="body"/> expression.
/// </param>
/// <returns>A new DbLambda that describes an inline Lambda function with the specified body and formal parameters</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="variables"/> is null or contains null, or <paramref name="body"/> is null
/// </exception>.
/// <exception cref="ArgumentException">
/// <paramref name="variables"/> contains more than one element with the same variable name.
/// </exception>
public static DbLambda Lambda(DbExpression body, IEnumerable<DbVariableReferenceExpression> variables)
{
return CreateLambda(body, variables);
}
/// <summary>
/// Creates a <see cref="DbLambda"/> with the specified inline Lambda function implementation and formal parameters.
/// </summary>
/// <param name="body">An expression that defines the logic of the Lambda function</param>
/// <param name="variables">
/// A <see cref="DbVariableReferenceExpression"/> collection that represents the formal parameters to the Lambda function.
/// These variables are valid for use in the <paramref name="body"/> expression.
/// </param>
/// <returns>A new DbLambda that describes an inline Lambda function with the specified body and formal parameters</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="variables"/> is null or contains null, or <paramref name="body"/> is null
/// </exception>.
/// <exception cref="ArgumentException">
/// <paramref name="variables"/> contains more than one element with the same variable name.
/// </exception>
public static DbLambda Lambda(DbExpression body, params DbVariableReferenceExpression[] variables)
{
return CreateLambda(body, variables);
}
private static DbLambda CreateLambda(DbExpression body, IEnumerable<DbVariableReferenceExpression> variables)
{
var validVars = ArgumentValidation.ValidateLambda(variables, body);
return new DbLambda(validVars, body);
}
/// <summary>
/// Creates a new <see cref="DbSortClause"/> with an ascending sort order and default collation
/// </summary>
/// <param name="key">The expression that defines the sort key</param>
/// <returns>A new sort clause with the given sort key and ascending sort order</returns>
/// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
/// <exception cref="ArgumentException"><paramref name="key"/> does not have an order-comparable result type</exception>
public static DbSortClause ToSortClause(this DbExpression key)
{
ArgumentValidation.ValidateSortClause(key);
return new DbSortClause(key, true, String.Empty);
}
/// <summary>
/// Creates a new <see cref="DbSortClause"/> with a descending sort order and default collation
/// </summary>
/// <param name="key">The expression that defines the sort key</param>
/// <returns>A new sort clause with the given sort key and descending sort order</returns>
/// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
/// <exception cref="ArgumentException"><paramref name="key"/> does not have an order-comparable result type</exception>
public static DbSortClause ToSortClauseDescending(this DbExpression key)
{
ArgumentValidation.ValidateSortClause(key);
return new DbSortClause(key, false, String.Empty);
}
/// <summary>
/// Creates a new <see cref="DbSortClause"/> with an ascending sort order and the specified collation
/// </summary>
/// <param name="key">The expression that defines the sort key</param>
/// <param name="collation">The collation to sort under</param>
/// <returns>A new sort clause with the given sort key and collation, and ascending sort order</returns>
/// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="collation"/> is empty or contains only space characters</exception>
/// <exception cref="ArgumentException"><paramref name="key"/> does not have an order-comparable result type</exception>
public static DbSortClause ToSortClause(this DbExpression key, string collation)
{
ArgumentValidation.ValidateSortClause(key, collation);
return new DbSortClause(key, true, collation);
}
/// <summary>
/// Creates a new <see cref="DbSortClause"/> with a descending sort order and the specified collation
/// </summary>
/// <param name="key">The expression that defines the sort key</param>
/// <param name="collation">The collation to sort under</param>
/// <returns>A new sort clause with the given sort key and collation, and descending sort order</returns>
/// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="collation"/> is empty or contains only space characters</exception>
/// <exception cref="ArgumentException"><paramref name="key"/> does not have an order-comparable result type</exception>
public static DbSortClause ToSortClauseDescending(this DbExpression key, string collation)
{
ArgumentValidation.ValidateSortClause(key, collation);
return new DbSortClause(key, false, collation);
}
#endregion
#region Binding-based methods: All, Any, Cross|OuterApply, Cross|FullOuter|Inner|LeftOuterJoin, Filter, GroupBy, Project, Skip, Sort
/// <summary>
/// Creates a new <see cref="DbQuantifierExpression"/> that determines whether the given predicate holds for all elements of the input set.
/// </summary>
/// <param name="input">An expression binding that specifies the input set.</param>
/// <param name="predicate">An expression representing a predicate to evaluate for each member of the input set.</param>
/// <returns>A new DbQuantifierExpression that represents the All operation.</returns>
/// <exception cref="ArgumentNullException"><paramref name="input"/> or <paramref name="predicate"/> is null</exception>
/// <exception cref="ArgumentException">
/// <paramref name="predicate"/> does not have a Boolean result type.
/// </exception>
public static DbQuantifierExpression All(this DbExpressionBinding input, DbExpression predicate)
{
TypeUsage booleanResultType = ArgumentValidation.ValidateQuantifier(input, predicate);
return new DbQuantifierExpression(DbExpressionKind.All, booleanResultType, input, predicate);
}
/// <summary>
/// Creates a new <see cref="DbQuantifierExpression"/> that determines whether the given predicate holds for any element of the input set.
/// </summary>
/// <param name="input">An expression binding that specifies the input set.</param>
/// <param name="predicate">An expression representing a predicate to evaluate for each member of the input set.</param>
/// <returns>A new DbQuantifierExpression that represents the Any operation.</returns>
/// <exception cref="ArgumentNullException"><paramref name="input"/> or <paramref name="predicate"/> is null</exception>
/// <exception cref="ArgumentException">
/// <paramref name="predicate"/> does not have a Boolean result type.
/// </exception>
public static DbQuantifierExpression Any(this DbExpressionBinding input, DbExpression predicate)
{
TypeUsage booleanResultType = ArgumentValidation.ValidateQuantifier(input, predicate);
return new DbQuantifierExpression(DbExpressionKind.Any, booleanResultType, input, predicate);
}
/// <summary>
/// Creates a new <see cref="DbApplyExpression"/> that evaluates the given <paramref name="apply"/> expression once for each element of a given input set,
/// 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.
/// </summary>
/// <param name="input">An <see cref="DbExpressionBinding"/> that specifies the input set.</param>
/// <param name="apply">An <see cref="DbExpressionBinding"/> that specifies logic to evaluate once for each member of the input set.</param>
/// <returns>An new DbApplyExpression with the specified input and apply bindings and an <see cref="DbExpressionKind"/> of CrossApply.</returns>
/// <exception cref="ArgumentNullException"><paramref name="input"/> or <paramref name="apply"/> is null</exception>
public static DbApplyExpression CrossApply(this DbExpressionBinding input, DbExpressionBinding apply)
{
TypeUsage resultType = ArgumentValidation.ValidateApply(input, apply);
return new DbApplyExpression(DbExpressionKind.CrossApply, resultType, input, apply);
}
/// <summary>
/// Creates a new <see cref="DbApplyExpression"/> that evaluates the given <paramref name="apply"/> expression once for each element of a given input set,
/// 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>.
/// </summary>
/// <param name="input">An <see cref="DbExpressionBinding"/> that specifies the input set.</param>
/// <param name="apply">An <see cref="DbExpressionBinding"/> that specifies logic to evaluate once for each member of the input set.</param>
/// <returns>An new DbApplyExpression with the specified input and apply bindings and an <see cref="DbExpressionKind"/> of OuterApply.</returns>
/// <exception cref="ArgumentNullException"><paramref name="input"/> or <paramref name="apply"/> is null</exception>
public static DbApplyExpression OuterApply(this DbExpressionBinding input, DbExpressionBinding apply)
{
TypeUsage resultType = ArgumentValidation.ValidateApply(input, apply);
return new DbApplyExpression(DbExpressionKind.OuterApply, resultType, input, apply);
}
/// <summary>
/// Creates a new <see cref="DbCrossJoinExpression"/> that unconditionally joins the sets specified by the list of input expression bindings.
/// </summary>
/// <param name="inputs">A list of expression bindings that specifies the input sets.</param>
/// <returns>A new DbCrossJoinExpression, with an <see cref="DbExpressionKind"/> of CrossJoin, that represents the unconditional join of the input sets.</returns>
/// <exception cref="ArgumentNullException"><paramref name="inputs"/> is null or contains null</exception>
/// <exception cref="ArgumentException">
/// <paramref name="inputs"/> contains fewer than 2 expression bindings.
/// </exception>
public static DbCrossJoinExpression CrossJoin(IEnumerable<DbExpressionBinding> inputs)
{
TypeUsage resultType;
System.Collections.ObjectModel.ReadOnlyCollection<DbExpressionBinding> validInputs = ArgumentValidation.ValidateCrossJoin(inputs, out resultType);
return new DbCrossJoinExpression(resultType, validInputs);
}
/// <summary>
/// Creates a new <see cref="DbJoinExpression"/> that joins the sets specified by the left and right
/// expression bindings, on the specified join condition, using InnerJoin as the <see cref="DbExpressionKind"/>.
/// </summary>
/// <param name="left">An <see cref="DbExpressionBinding"/> that specifies the left set argument.</param>
/// <param name="right">An <see cref="DbExpressionBinding"/> that specifies the right set argument.</param>
/// <param name="joinCondition">An expression that specifies the condition on which to join.</param>
/// <returns>
/// A new DbJoinExpression, with an <see cref="DbExpressionKind"/> of InnerJoin, that represents the inner join operation applied to the left and right
/// input sets under the given join condition.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="left"/>, <paramref name="right"/> or <paramref name="joinCondition"/> is null.
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="joinCondition"/> does not have a Boolean result type.
/// </exception>
public static DbJoinExpression InnerJoin(this DbExpressionBinding left, DbExpressionBinding right, DbExpression joinCondition)
{
TypeUsage resultType = ArgumentValidation.ValidateJoin(left, right, joinCondition);
return new DbJoinExpression(DbExpressionKind.InnerJoin, resultType, left, right, joinCondition);
}
/// <summary>
/// Creates a new <see cref="DbJoinExpression"/> that joins the sets specified by the left and right
/// expression bindings, on the specified join condition, using LeftOuterJoin as the <see cref="DbExpressionKind"/>.
/// </summary>
/// <param name="left">An <see cref="DbExpressionBinding"/> that specifies the left set argument.</param>
/// <param name="right">An <see cref="DbExpressionBinding"/> that specifies the right set argument.</param>
/// <param name="joinCondition">An expression that specifies the condition on which to join.</param>
/// <returns>
/// A new DbJoinExpression, with an <see cref="DbExpressionKind"/> of LeftOuterJoin, that represents the left outer join operation applied to the left and right
/// input sets under the given join condition.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="left"/>, <paramref name="right"/> or <paramref name="joinCondition"/> is null.
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="joinCondition"/> does not have a Boolean result type.
/// </exception>
public static DbJoinExpression LeftOuterJoin(this DbExpressionBinding left, DbExpressionBinding right, DbExpression joinCondition)
{
TypeUsage resultType = ArgumentValidation.ValidateJoin(left, right, joinCondition);
return new DbJoinExpression(DbExpressionKind.LeftOuterJoin, resultType, left, right, joinCondition);
}
/// <summary>
/// Creates a new <see cref="DbJoinExpression"/> that joins the sets specified by the left and right
/// expression bindings, on the specified join condition, using FullOuterJoin as the <see cref="DbExpressionKind"/>.
/// </summary>
/// <param name="left">An <see cref="DbExpressionBinding"/> that specifies the left set argument.</param>
/// <param name="right">An <see cref="DbExpressionBinding"/> that specifies the right set argument.</param>
/// <param name="joinCondition">An expression that specifies the condition on which to join.</param>
/// <returns>
/// A new DbJoinExpression, with an <see cref="DbExpressionKind"/> of FullOuterJoin, that represents the full outer join operation applied to the left and right
/// input sets under the given join condition.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="left"/>, <paramref name="right"/> or <paramref name="joinCondition"/> is null.
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="joinCondition"/> does not have a Boolean result type.
/// </exception>
public static DbJoinExpression FullOuterJoin(this DbExpressionBinding left, DbExpressionBinding right, DbExpression joinCondition)
{
TypeUsage resultType = ArgumentValidation.ValidateJoin(left, right, joinCondition);
return new DbJoinExpression(DbExpressionKind.FullOuterJoin, resultType, left, right, joinCondition);
}
/// <summary>
/// Creates a new <see cref="DbFilterExpression"/> that filters the elements in the given input set using the specified predicate.
/// </summary>
/// <param name="input">An expression binding that specifies the input set.</param>
/// <param name="predicate">An expression representing a predicate to evaluate for each member of the input set.</param>
/// <returns>A new DbFilterExpression that produces the filtered set.</returns>
/// <exception cref="ArgumentNullException"><paramref name="input"/> or <paramref name="predicate"/> is null</exception>
/// <exception cref="ArgumentException">
/// <paramref name="predicate"/> does not have a Boolean result type.
/// </exception>
public static DbFilterExpression Filter(this DbExpressionBinding input, DbExpression predicate)
{
TypeUsage resultType = ArgumentValidation.ValidateFilter(input, predicate);
return new DbFilterExpression(resultType, input, predicate);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="input">A <see cref="DbGroupExpressionBinding"/> that specifies the input set.</param>
/// <param name="keys">A list of string-expression pairs that define the grouping columns.</param>
/// <param name="aggregates">A list of expressions that specify aggregates to apply.</param>
/// <returns>A new DbGroupByExpression with the specified input set, grouping keys and aggregates.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="input"/>, <paramref name="keys"/> or <paramref name="aggregates"/> is null,
/// <paramref name="keys"/> contains a null key column name or expression, or
/// <paramref name="aggregates"/> contains a null aggregate column name or aggregate.
/// </exception>
/// <exception cref="ArgumentException">
/// Both <paramref name="keys"/> and <paramref name="aggregates"/> are empty,
/// or an invalid or duplicate column name was specified.
/// </exception>
/// <remarks>
/// DbGroupByExpression allows either the list of keys or the list of aggregates to be empty, but not both.
/// </remarks>
public static DbGroupByExpression GroupBy(this DbGroupExpressionBinding input, IEnumerable<KeyValuePair<string, DbExpression>> keys, IEnumerable<KeyValuePair<string, DbAggregate>> aggregates)
{
DbExpressionList validKeys;
System.Collections.ObjectModel.ReadOnlyCollection<DbAggregate> validAggregates;
TypeUsage resultType = ArgumentValidation.ValidateGroupBy(input, keys, aggregates, out validKeys, out validAggregates);
return new DbGroupByExpression(resultType, input, validKeys, validAggregates);
}
/// <summary>
/// Creates a new <see cref="DbProjectExpression"/> that projects the specified expression over the given input set.
/// </summary>
/// <param name="input">An expression binding that specifies the input set.</param>
/// <param name="projection">An expression to project over the set.</param>
/// <returns>A new DbProjectExpression that represents the projection operation.</returns>
/// <exception cref="ArgumentNullException"><paramref name="input"/> or <paramref name="projection"/> is null</exception>
public static DbProjectExpression Project(this DbExpressionBinding input, DbExpression projection)
{
TypeUsage resultType = ArgumentValidation.ValidateProject(input, projection);
return new DbProjectExpression(resultType, input, projection);
}
/// <summary>
/// Creates a new <see cref="DbSkipExpression"/> that sorts the given input set by the given sort specifications before skipping the specified number of elements.
/// </summary>
/// <param name="input">An expression binding that specifies the input set.</param>
/// <param name="sortOrder">A list of sort specifications that determine how the elements of the input set should be sorted.</param>
/// <param name="count">An expression the specifies how many elements of the ordered set to skip.</param>
/// <returns>A new DbSkipExpression that represents the skip operation.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="input"/>, <paramref name="sortOrder"/> or <paramref name="count"/> is null,
/// or <paramref name="sortOrder"/> contains null.
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="sortOrder"/> is empty,
/// or <paramref name="count"/> is not <see cref="DbConstantExpression"/> or <see cref="DbParameterReferenceExpression"/> or has a
/// result type that is not equal or promotable to a 64-bit integer type.
/// </exception>
public static DbSkipExpression Skip(this DbExpressionBinding input, IEnumerable<DbSortClause> sortOrder, DbExpression count)
{
System.Collections.ObjectModel.ReadOnlyCollection<DbSortClause> validSortOrder = ArgumentValidation.ValidateSkip(input, sortOrder, count);
return new DbSkipExpression(input.Expression.ResultType, input, validSortOrder, count);
}
/// <summary>
/// Creates a new <see cref="DbSortExpression"/> that sorts the given input set by the specified sort specifications.
/// </summary>
/// <param name="input">An expression binding that specifies the input set.</param>
/// <param name="sortOrder">A list of sort specifications that determine how the elements of the input set should be sorted.</param>
/// <returns>A new DbSortExpression that represents the sort operation.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="input"/> or <paramref name="sortOrder"/> is null,
/// or <paramref name="sortOrder"/> contains null.
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="sortOrder"/> is empty.
/// </exception>
public static DbSortExpression Sort(this DbExpressionBinding input, IEnumerable<DbSortClause> sortOrder)
{
System.Collections.ObjectModel.ReadOnlyCollection<DbSortClause> validSortOrder = ArgumentValidation.ValidateSort(input, sortOrder);
return new DbSortExpression(input.Expression.ResultType, input, validSortOrder);
}
#endregion
#region Leaf Expressions - Null, Constant, Parameter, Scan
#if DBEXPRESSIONBUILDER_NULLCONSTANTS
// Binary
public static DbNullExpression NullBinary { get { return _binaryNull; } }
// Boolean
public static DbNullExpression NullBoolean { get { return _boolNull; } }
// Byte
public static DbNullExpression NullByte { get { return _byteNull; } }
// DateTime
public static DbNullExpression NullDateTime { get { return _dateTimeNull; } }
// DateTimeOffset
public static DbNullExpression NullDateTimeOffset { get { return _dateTimeOffsetNull; } }
// Decimal
public static DbNullExpression NullDecimal { get { return _decimalNull; } }
// Double
public static DbNullExpression NullDouble { get { return _doubleNull; } }
// Guid
public static DbNullExpression NullGuid { get { return _guidNull; } }
// Int16
public static DbNullExpression NullInt16 { get { return _int16Null; } }
// Int32
public static DbNullExpression NullInt32 { get { return _int32Null; } }
// Int64
public static DbNullExpression NullInt64 { get { return _int64Null; } }
// SByte
public static DbNullExpression NullSByte { get { return _sbyteNull; } }
// Single
public static DbNullExpression NullSingle { get { return _singleNull; } }
// String
public static DbNullExpression NullString { get { return _stringNull; } }
// Time
public static DbNullExpression NullTime { get { return _timeNull; } }
#endif
/// <summary>
/// Creates a new <see cref="DbNullExpression"/>, which represents a typed null value.
/// </summary>
/// <param name="nullType">The type of the null value.</param>
/// <returns>An instance of DbNullExpression</returns>
/// <exception cref="ArgumentNullException"><paramref name="nullType"/> is null</exception>
public static DbNullExpression Null(this TypeUsage nullType)
{
ArgumentValidation.ValidateNull(nullType);
return new DbNullExpression(nullType);
}
/// <summary>
/// Creates a <see cref="DbConstantExpression"/> with the Boolean value <code>true</code>.
/// </summary>
/// <returns>A DbConstantExpression with the Boolean value true.</returns>
public static DbConstantExpression True { get { return _boolTrue; } }
/// <summary>
/// Creates a <see cref="DbConstantExpression"/> with the Boolean value <code>false</code>.
/// </summary>
/// <returns>A DbConstantExpression with the Boolean value false.</returns>
public static DbConstantExpression False { get { return _boolFalse; } }
/// <summary>
/// Creates a new <see cref="DbConstantExpression"/> with the given constant value.
/// </summary>
/// <param name="value">The constant value to represent.</param>
/// <returns>A new DbConstantExpression with the given value.</returns>
/// <exception cref="ArgumentNullException"><paramref name="value"/> is null</exception>
/// <exception cref="ArgumentException"><paramref name="value"/> is not an instance of a valid constant type</exception>
public static DbConstantExpression Constant(object value)
{
TypeUsage constantType = ArgumentValidation.ValidateConstant(value);
return new DbConstantExpression(constantType, value);
}
/// <summary>
/// Creates a new <see cref="DbConstantExpression"/> of the specified primitive type with the given constant value.
/// </summary>
/// <param name="constantType">The type of the constant value.</param>
/// <param name="value">The constant value to represent.</param>
/// <returns>A new DbConstantExpression with the given value and a result type of <paramref name="constantType"/>.</returns>
/// <exception cref="ArgumentNullException"><paramref name="value"/> or <paramref name="constantType"/> is null</exception>
/// <exception cref="ArgumentException">
/// <paramref name="value"/> is not an instance of a valid constant type,
/// <paramref name="constantType"/> does not represent a primitive type, or
/// <paramref name="value"/> is of a different primitive type than that represented by <paramref name="constantType"/>
/// </exception>
public static DbConstantExpression Constant(this TypeUsage constantType, object value)
{
ArgumentValidation.ValidateConstant(constantType, value);
return new DbConstantExpression(constantType, value);
}
/// <summary>
/// Creates a new <see cref="DbParameterReferenceExpression"/> that references a parameter with the specified name and type.
/// </summary>
/// <param name="type">The type of the referenced parameter</param>
/// <param name="name">The name of the referenced parameter</param>
/// <returns>
/// A DbParameterReferenceExpression that represents a reference to a parameter with the specified name and type;
/// the result type of the expression will be the same as <paramref name="type"/>.
/// </returns>
public static DbParameterReferenceExpression Parameter(this TypeUsage type, string name)
{
ArgumentValidation.ValidateParameter(type, name);
return new DbParameterReferenceExpression(type, name);
}
/// <summary>
/// Creates a new <see cref="DbVariableReferenceExpression"/> that references a variable with the specified name and type.
/// </summary>
/// <param name="type">The type of the referenced variable</param>
/// <param name="name">The name of the referenced variable</param>
/// <returns>
/// A DbVariableReferenceExpression that represents a reference to a variable with the specified name and type;
/// the result type of the expression will be the same as <paramref name="type"/>.
/// </returns>
public static DbVariableReferenceExpression Variable(this TypeUsage type, string name)
{
ArgumentValidation.ValidateVariable(type, name);
return new DbVariableReferenceExpression(type, name);
}
/// <summary>
/// Creates a new <see cref="DbScanExpression"/> that references the specified entity or relationship set.
/// </summary>
/// <param name="targetSet">Metadata for the entity or relationship set to reference.</param>
/// <returns>A new DbScanExpression based on the specified entity or relationship set.</returns>
/// <exception cref="ArgumentNullException"><paramref name="targetSet"/> is null</exception>
public static DbScanExpression Scan(this EntitySetBase targetSet)
{
TypeUsage resultType = ArgumentValidation.ValidateScan(targetSet);
return new DbScanExpression(resultType, targetSet);
}
#endregion
#region Boolean Operators - And, Or, Not
/// <summary>
/// Creates an <see cref="DbAndExpression"/> that performs the logical And of the left and right arguments.
/// </summary>
/// <param name="left">A Boolean expression that specifies the left argument.</param>
/// <param name="right">A Boolean expression that specifies the right argument.</param>
/// <returns>A new DbAndExpression with the specified arguments.</returns>
/// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
/// <exception cref="ArgumentException">
/// <paramref name="left"/> or <paramref name="right"/> does not have a Boolean result type.
/// </exception>
public static DbAndExpression And(this DbExpression left, DbExpression right)
{
TypeUsage resultType = ArgumentValidation.ValidateAnd(left, right);
return new DbAndExpression(resultType, left, right);
}
/// <summary>
/// Creates an <see cref="DbOrExpression"/> that performs the logical Or of the left and right arguments.
/// </summary>
/// <param name="left">A Boolean expression that specifies the left argument.</param>
/// <param name="right">A Boolean expression that specifies the right argument.</param>
/// <returns>A new DbOrExpression with the specified arguments.</returns>
/// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
/// <exception cref="ArgumentException">
/// <paramref name="left"/> or <paramref name="right"/> does not have a Boolean result type.
/// </exception>
public static DbOrExpression Or(this DbExpression left, DbExpression right)
{
TypeUsage resultType = ArgumentValidation.ValidateOr(left, right);
return new DbOrExpression(resultType, left, right);
}
/// <summary>
/// Creates a <see cref="DbNotExpression"/> that performs the logical negation of the given argument.
/// </summary>
/// <param name="argument">A Boolean expression that specifies the argument.</param>
/// <returns>A new DbNotExpression with the specified argument.</returns>
/// <exception cref="ArgumentNullException"><paramref name="argument"/> is null</exception>
/// <exception cref="ArgumentException">
/// <paramref name="argument"/> does not have a Boolean result type.
/// </exception>
public static DbNotExpression Not(this DbExpression argument)
{
TypeUsage resultType = ArgumentValidation.ValidateNot(argument);
return new DbNotExpression(resultType, argument);
}
#endregion
#region Arithmetic Operators - Divide, Minus, Modulo, Multiply, Plus, UnaryMinus
private static DbArithmeticExpression CreateArithmetic(DbExpressionKind kind, DbExpression left, DbExpression right)
{
TypeUsage numericResultType;
DbExpressionList arguments = ArgumentValidation.ValidateArithmetic(left, right, out numericResultType);
return new DbArithmeticExpression(kind, numericResultType, arguments);
}
/// <summary>
/// Creates a new <see cref="DbArithmeticExpression"/> that divides the left argument by the right argument.
/// </summary>
/// <param name="left">An expression that specifies the left argument.</param>
/// <param name="right">An expression that specifies the right argument.</param>
/// <returns>A new DbArithmeticExpression representing the division operation.</returns>
/// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
/// <exception cref="ArgumentException">
/// No common numeric result type exists between <paramref name="left"/> and <paramref name="right"/>.
/// </exception>
public static DbArithmeticExpression Divide(this DbExpression left, DbExpression right)
{
return CreateArithmetic(DbExpressionKind.Divide, left, right);
}
/// <summary>
/// Creates a new <see cref="DbArithmeticExpression"/> that subtracts the right argument from the left argument.
/// </summary>
/// <param name="left">An expression that specifies the left argument.</param>
/// <param name="right">An expression that specifies the right argument.</param>
/// <returns>A new DbArithmeticExpression representing the subtraction operation.</returns>
/// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
/// <exception cref="ArgumentException">
/// No common numeric result type exists between <paramref name="left"/> and <paramref name="right"/>.
/// </exception>
public static DbArithmeticExpression Minus(this DbExpression left, DbExpression right)
{
return CreateArithmetic(DbExpressionKind.Minus, left, right);
}
/// <summary>
/// Creates a new <see cref="DbArithmeticExpression"/> that computes the remainder of the left argument divided by the right argument.
/// </summary>
/// <param name="left">An expression that specifies the left argument.</param>
/// <param name="right">An expression that specifies the right argument.</param>
/// <returns>A new DbArithmeticExpression representing the modulo operation.</returns>
/// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
/// <exception cref="ArgumentException">
/// No common numeric result type exists between <paramref name="left"/> and <paramref name="right"/>.
/// </exception>
public static DbArithmeticExpression Modulo(this DbExpression left, DbExpression right)
{
return CreateArithmetic(DbExpressionKind.Modulo, left, right);
}
/// <summary>
/// Creates a new <see cref="DbArithmeticExpression"/> that multiplies the left argument by the right argument.
/// </summary>
/// <param name="left">An expression that specifies the left argument.</param>
/// <param name="right">An expression that specifies the right argument.</param>
/// <returns>A new DbArithmeticExpression representing the multiplication operation.</returns>
/// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
/// <exception cref="ArgumentException">
/// No common numeric result type exists between <paramref name="left"/> and <paramref name="right"/>.
/// </exception>
public static DbArithmeticExpression Multiply(this DbExpression left, DbExpression right)
{
return CreateArithmetic(DbExpressionKind.Multiply, left, right);
}
/// <summary>
/// Creates a new <see cref="DbArithmeticExpression"/> that adds the left argument to the right argument.
/// </summary>
/// <param name="left">An expression that specifies the left argument.</param>
/// <param name="right">An expression that specifies the right argument.</param>
/// <returns>A new DbArithmeticExpression representing the addition operation.</returns>
/// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
/// <exception cref="ArgumentException">
/// No common numeric result type exists between <paramref name="left"/> and <paramref name="right"/>.
/// </exception>
public static DbArithmeticExpression Plus(this DbExpression left, DbExpression right)
{
return CreateArithmetic(DbExpressionKind.Plus, left, right);
}
/// <summary>
/// Creates a new <see cref="DbArithmeticExpression"/> that negates the value of the argument.
/// </summary>
/// <param name="argument">An expression that specifies the argument.</param>
/// <returns>A new DbArithmeticExpression representing the negation operation.</returns>
/// <exception cref="ArgumentNullException"><paramref name="argument"/> is null</exception>
/// <exception cref="ArgumentException">
/// No numeric result type exists for <paramref name="argument"/>.
/// </exception>
public static DbArithmeticExpression UnaryMinus(this DbExpression argument)
{
TypeUsage resultType;
DbExpressionList args = ArgumentValidation.ValidateArithmetic(argument, out resultType);
return new DbArithmeticExpression(DbExpressionKind.UnaryMinus, resultType, args);
}
/// <summary>
/// Creates a new <see cref="DbArithmeticExpression"/> that negates the value of the argument.
/// </summary>
/// <param name="argument">An expression that specifies the argument.</param>
/// <returns>A new DbArithmeticExpression representing the negation operation.</returns>
/// <exception cref="ArgumentNullException"><paramref name="argument"/> is null</exception>
/// <exception cref="ArgumentException">
/// No numeric result type exists for <paramref name="argument"/>.
/// </exception>
public static DbArithmeticExpression Negate(this DbExpression argument)
{
return DbExpressionBuilder.UnaryMinus(argument);
}
#endregion
#region Comparison Operators - Equal, NotEqual, GreaterThan, LessThan, GreaterThanEqual, LessThanEqual, IsNull, Like
private static DbComparisonExpression CreateComparison(DbExpressionKind kind, DbExpression left, DbExpression right)
{
TypeUsage resultType = ArgumentValidation.ValidateComparison(kind, left, right);
return new DbComparisonExpression(kind, resultType, left, right);
}
/// <summary>
/// Creates a new <see cref="DbComparisonExpression"/> that compares the left and right arguments for equality.
/// </summary>
/// <param name="left">An expression that specifies the left argument.</param>
/// <param name="right">An expression that specifies the right argument.</param>
/// <returns>A new DbComparisonExpression representing the equality comparison.</returns>
/// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
/// <exception cref="ArgumentException">
/// No common equality-comparable result type exists between <paramref name="left"/> and <paramref name="right"/>.
/// </exception>
public static DbComparisonExpression Equal(this DbExpression left, DbExpression right)
{
return DbExpressionBuilder.CreateComparison(DbExpressionKind.Equals, left, right);
}
/// <summary>
/// Creates a new <see cref="DbComparisonExpression"/> that compares the left and right arguments for inequality.
/// </summary>
/// <param name="left">An expression that specifies the left argument.</param>
/// <param name="right">An expression that specifies the right argument.</param>
/// <returns>A new DbComparisonExpression representing the inequality comparison.</returns>
/// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
/// <exception cref="ArgumentException">
/// No common equality-comparable result type exists between <paramref name="left"/> and <paramref name="right"/>.
/// </exception>
public static DbComparisonExpression NotEqual(this DbExpression left, DbExpression right)
{
return DbExpressionBuilder.CreateComparison(DbExpressionKind.NotEquals, left, right);
}
/// <summary>
/// Creates a new <see cref="DbComparisonExpression"/> that determines whether the left argument is greater than the right argument.
/// </summary>
/// <param name="left">An expression that specifies the left argument.</param>
/// <param name="right">An expression that specifies the right argument.</param>
/// <returns>A new DbComparisonExpression representing the greater-than comparison.</returns>
/// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
/// <exception cref="ArgumentException">
/// No common order-comparable result type exists between <paramref name="left"/> and <paramref name="right"/>.
/// </exception>
public static DbComparisonExpression GreaterThan(this DbExpression left, DbExpression right)
{
return DbExpressionBuilder.CreateComparison(DbExpressionKind.GreaterThan, left, right);
}
/// <summary>
/// Creates a new <see cref="DbComparisonExpression"/> that determines whether the left argument is less than the right argument.
/// </summary>
/// <param name="left">An expression that specifies the left argument.</param>
/// <param name="right">An expression that specifies the right argument.</param>
/// <returns>A new DbComparisonExpression representing the less-than comparison.</returns>
/// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
/// <exception cref="ArgumentException">
/// No common order-comparable result type exists between <paramref name="left"/> and <paramref name="right"/>.
/// </exception>
public static DbComparisonExpression LessThan(this DbExpression left, DbExpression right)
{
return DbExpressionBuilder.CreateComparison(DbExpressionKind.LessThan, left, right);
}
/// <summary>
/// Creates a new <see cref="DbComparisonExpression"/> that determines whether the left argument is greater than or equal to the right argument.
/// </summary>
/// <param name="left">An expression that specifies the left argument.</param>
/// <param name="right">An expression that specifies the right argument.</param>
/// <returns>A new DbComparisonExpression representing the greater-than-or-equal-to comparison.</returns>
/// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
/// <exception cref="ArgumentException">
/// No common result type that is both equality- and order-comparable exists between <paramref name="left"/> and <paramref name="right"/>.
/// </exception>
public static DbComparisonExpression GreaterThanOrEqual(this DbExpression left, DbExpression right)
{
return DbExpressionBuilder.CreateComparison(DbExpressionKind.GreaterThanOrEquals, left, right);
}
/// <summary>
/// Creates a new <see cref="DbComparisonExpression"/> that determines whether the left argument is less than or equal to the right argument.
/// </summary>
/// <param name="left">An expression that specifies the left argument.</param>
/// <param name="right">An expression that specifies the right argument.</param>
/// <returns>A new DbComparisonExpression representing the less-than-or-equal-to comparison.</returns>
/// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
/// <exception cref="ArgumentException">
/// No common result type that is both equality- and order-comparable exists between <paramref name="left"/> and <paramref name="right"/>.
/// </exception>
public static DbComparisonExpression LessThanOrEqual(this DbExpression left, DbExpression right)
{
return DbExpressionBuilder.CreateComparison(DbExpressionKind.LessThanOrEquals, left, right);
}
/// <summary>
/// Creates a new <see cref="DbIsNullExpression"/> that determines whether the specified argument is null.
/// </summary>
/// <param name="argument">An expression that specifies the argument.</param>
/// <returns>A new DbIsNullExpression with the specified argument.</returns>
/// <exception cref="ArgumentNullException"><paramref name="argument"/> is null</exception>
/// <exception cref="ArgumentException"><paramref name="argument"/> has a collection result type.</exception>
public static DbIsNullExpression IsNull(this DbExpression argument)
{
TypeUsage resultType = ArgumentValidation.ValidateIsNull(argument);
return new DbIsNullExpression(resultType, argument, false);
}
/// <summary>
/// Creates a new <see cref="DbLikeExpression"/> that compares the specified input string to the given pattern.
/// </summary>
/// <param name="argument">An expression that specifies the input string.</param>
/// <param name="pattern">An expression that specifies the pattern string.</param>
/// <returns>A new DbLikeExpression with the specified input, pattern and a null escape.</returns>
/// <exception cref="ArgumentNullException"><paramref name="argument"/> or <paramref name="pattern"/> is null</exception>
/// <exception cref="ArgumentException"><paramref name="argument"/> or <paramref name="pattern"/> does not have a string result type.</exception>
public static DbLikeExpression Like(this DbExpression argument, DbExpression pattern)
{
TypeUsage resultType = ArgumentValidation.ValidateLike(argument, pattern);
DbExpression escape = DbExpressionBuilder.Null(pattern.ResultType);
return new DbLikeExpression(resultType, argument, pattern, escape);
}
/// <summary>
/// Creates a new <see cref="DbLikeExpression"/> that compares the specified input string to the given pattern using the optional escape.
/// </summary>
/// <param name="argument">An expression that specifies the input string.</param>
/// <param name="pattern">An expression that specifies the pattern string.</param>
/// <param name="escape">An optional expression that specifies the escape string.</param>
/// <returns>A new DbLikeExpression with the specified input, pattern and escape.</returns>
/// <exception cref="ArgumentNullException"><paramref name="argument"/>, <paramref name="pattern"/> or <paramref name="escape"/> is null</exception>
/// <exception cref="ArgumentException"><paramref name="argument"/>, <paramref name="pattern"/> or <paramref name="escape"/> does not have a string result type.</exception>
public static DbLikeExpression Like(this DbExpression argument, DbExpression pattern, DbExpression escape)
{
TypeUsage resultType = ArgumentValidation.ValidateLike(argument, pattern, escape);
return new DbLikeExpression(resultType, argument, pattern, escape);
}
#endregion
#region Type Operators - Cast, Treat, OfType, OfTypeOnly, IsOf, IsOfOnly
/// <summary>
/// Creates a new <see cref="DbCastExpression"/> that applies a cast operation to a polymorphic argument.
/// </summary>
/// <param name="argument">The argument to which the cast should be applied.</param>
/// <param name="toType">Type metadata that specifies the type to cast to.</param>
/// <returns>A new DbCastExpression with the specified argument and target type.</returns>
/// <exception cref="ArgumentNullException"><paramref name="argument"/> or <paramref name="toType"/> is null</exception>
/// <exception cref="ArgumentException">The specified cast is not valid.</exception>
public static DbCastExpression CastTo(this DbExpression argument, TypeUsage toType)
{
ArgumentValidation.ValidateCastTo(argument, toType);
return new DbCastExpression(toType, argument);
}
/// <summary>
/// Creates a new <see cref="DbTreatExpression"/>.
/// </summary>
/// <param name="argument">An expression that specifies the instance.</param>
/// <param name="treatType">Type metadata for the treat-as type.</param>
/// <returns>A new DbTreatExpression with the specified argument and type.</returns>
/// <exception cref="ArgumentNullException"><paramref name="argument"/> or <paramref name="treatType"/> is null</exception>
/// <exception cref="ArgumentException"><paramref name="treatType"/> is not in the same type hierarchy as the result type of <paramref name="argument"/>.
/// </exception>
/// <remarks>
/// DbTreatExpression requires that <paramref name="argument"/> has a polymorphic result type,
/// and that <paramref name="treatType"/> is a type from the same type hierarchy as that result type.
/// </remarks>
public static DbTreatExpression TreatAs(this DbExpression argument, TypeUsage treatType)
{
ArgumentValidation.ValidateTreatAs(argument, treatType);
return new DbTreatExpression(treatType, argument);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="argument">A <see cref="DbExpression"/> that specifies the input set.</param>
/// <param name="type">Type metadata for the type that elements of the input set must have to be included in the resulting set.</param>
/// <returns>A new DbOfTypeExpression with the specified set argument and type, and an ExpressionKind of <see cref="DbExpressionKind.OfType"/>.</returns>
/// <exception cref="ArgumentNullException"><paramref name="argument"/> or <paramref name="type"/> is null</exception>
/// <exception cref="ArgumentException">
/// <paramref name="argument"/> does not have a collection result type, or
/// <paramref name="type"/> is not a type in the same type hierarchy as the element type of the
/// collection result type of <paramref name="argument"/>.
/// </exception>
/// <remarks>
/// DbOfTypeExpression requires that <paramref name="argument"/> has a collection result type with
/// a polymorphic element type, and that <paramref name="type"/> is a type from the same type hierarchy as that element type.
/// </remarks>
public static DbOfTypeExpression OfType(this DbExpression argument, TypeUsage type)
{
TypeUsage collectionOfTypeResultType = ArgumentValidation.ValidateOfType(argument, type);
return new DbOfTypeExpression(DbExpressionKind.OfType, collectionOfTypeResultType, argument, type);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="argument">An <see cref="DbExpression"/> that specifies the input set.</param>
/// <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>
/// <returns>A new DbOfTypeExpression with the specified set argument and type, and an ExpressionKind of <see cref="DbExpressionKind.OfTypeOnly"/>.</returns>
/// <exception cref="ArgumentNullException"><paramref name="argument"/> or <paramref name="type"/> is null</exception>
/// <exception cref="ArgumentException">
/// <paramref name="argument"/> does not have a collection result type, or
/// <paramref name="type"/> is not a type in the same type hierarchy as the element type of the
/// collection result type of <paramref name="argument"/>.
/// </exception>
/// <remarks>
/// DbOfTypeExpression requires that <paramref name="argument"/> has a collection result type with
/// a polymorphic element type, and that <paramref name="type"/> is a type from the same type hierarchy as that element type.
/// </remarks>
public static DbOfTypeExpression OfTypeOnly(this DbExpression argument, TypeUsage type)
{
TypeUsage collectionOfTypeResultType = ArgumentValidation.ValidateOfType(argument, type);
return new DbOfTypeExpression(DbExpressionKind.OfTypeOnly, collectionOfTypeResultType, argument, type);
}
/// <summary>
/// Creates a new <see cref="DbIsOfExpression"/> that determines whether the given argument is of the specified type or a subtype.
/// </summary>
/// <param name="argument">An expression that specifies the instance.</param>
/// <param name="type">Type metadata that specifies the type that the instance's result type should be compared to.</param>
/// <returns>A new DbIsOfExpression with the specified instance and type and DbExpressionKind IsOf.</returns>
/// <exception cref="ArgumentNullException"><paramref name="argument"/> or <paramref name="type"/> is null</exception>
/// <exception cref="ArgumentException">
/// <paramref name="type"/> is not in the same type hierarchy as the result type of <paramref name="argument"/>.
/// </exception>
/// <remarks>
/// DbIsOfExpression requires that <paramref name="argument"/> has a polymorphic result type,
/// and that <paramref name="type"/> is a type from the same type hierarchy as that result type.
/// </remarks>
public static DbIsOfExpression IsOf(this DbExpression argument, TypeUsage type)
{
TypeUsage booleanResultType = ArgumentValidation.ValidateIsOf(argument, type);
return new DbIsOfExpression(DbExpressionKind.IsOf, booleanResultType, argument, type);
}
/// <summary>
/// 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).
/// </summary>
/// <param name="argument">An expression that specifies the instance.</param>
/// <param name="type">Type metadata that specifies the type that the instance's result type should be compared to.</param>
/// <returns>A new DbIsOfExpression with the specified instance and type and DbExpressionKind IsOfOnly.</returns>
/// <exception cref="ArgumentNullException"><paramref name="argument"/> or <paramref name="type"/> is null</exception>
/// <exception cref="ArgumentException">
/// <paramref name="type"/> is not in the same type hierarchy as the result type of <paramref name="argument"/>.
/// </exception>
/// <remarks>
/// DbIsOfExpression requires that <paramref name="argument"/> has a polymorphic result type,
/// and that <paramref name="type"/> is a type from the same type hierarchy as that result type.
/// </remarks>
public static DbIsOfExpression IsOfOnly(this DbExpression argument, TypeUsage type)
{
TypeUsage booleanResultType = ArgumentValidation.ValidateIsOf(argument, type);
return new DbIsOfExpression(DbExpressionKind.IsOfOnly, booleanResultType, argument, type);
}
#endregion
#region Ref Operators - Deref, EntityRef, Ref, RefKey, RelationshipNavigation
/// <summary>
/// Creates a new <see cref="DbDerefExpression"/> that retrieves a specific Entity given a reference expression
/// </summary>
/// <param name="argument">An <see cref="DbExpression"/> that provides the reference. This expression must have a reference Type</param>
/// <returns>A new DbDerefExpression that retrieves the specified Entity</returns>
/// <exception cref="ArgumentNullException"><paramref name="argument"/> is null</exception>
/// <exception cref="ArgumentException"><paramref name="argument"/> does not have a reference result type.</exception>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Deref")]
public static DbDerefExpression Deref(this DbExpression argument)
{
TypeUsage entityResultType = ArgumentValidation.ValidateDeref(argument);
return new DbDerefExpression(entityResultType, argument);
}
/// <summary>
/// Creates a new <see cref="DbEntityRefExpression"/> that retrieves the ref of the specifed entity in structural form.
/// </summary>
/// <param name="argument">The expression that provides the entity. This expression must have an entity result type.</param>
/// <returns>A new DbEntityRefExpression that retrieves a reference to the specified entity.</returns>
/// <exception cref="ArgumentNullException"><paramref name="argument"/> is null</exception>
/// <exception cref="ArgumentException"><paramref name="argument"/> does not have an entity result type.</exception>
public static DbEntityRefExpression GetEntityRef(this DbExpression argument)
{
TypeUsage refResultType = ArgumentValidation.ValidateGetEntityRef(argument);
return new DbEntityRefExpression(refResultType, argument);
}
/// <summary>
/// Creates a new <see cref="DbRefExpression"/> that encodes a reference to a specific entity based on key values.
/// </summary>
/// <param name="entitySet">The entity set in which the referenced element resides.</param>
/// <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>
/// <returns>A new DbRefExpression that references the element with the specified key values in the given entity set.</returns>
/// <exception cref="ArgumentNullException"><paramref name="entitySet"/> is null, or <paramref name="keyValues"/> is null or contains null.</exception>
/// <exception cref="ArgumentException">
/// The count of <paramref name="keyValues"/> does not match the count of key members declared by the <paramref name="entitySet"/>'s element type,
/// or <paramref name="keyValues"/> contains an expression with a result type that is not compatible with the type of the corresponding key member.
/// </exception>
public static DbRefExpression CreateRef(this EntitySet entitySet, IEnumerable<DbExpression> keyValues)
{
return CreateRefExpression(entitySet, keyValues);
}
/// <summary>
/// Creates a new <see cref="DbRefExpression"/> that encodes a reference to a specific entity based on key values.
/// </summary>
/// <param name="entitySet">The entity set in which the referenced element resides.</param>
/// <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>
/// <returns>A new DbRefExpression that references the element with the specified key values in the given entity set.</returns>
/// <exception cref="ArgumentNullException"><paramref name="entitySet"/> is null, or <paramref name="keyValues"/> is null or contains null.</exception>
/// <exception cref="ArgumentException">
/// The count of <paramref name="keyValues"/> does not match the count of key members declared by the <paramref name="entitySet"/>'s element type,
/// or <paramref name="keyValues"/> contains an expression with a result type that is not compatible with the type of the corresponding key member.
/// </exception>
public static DbRefExpression CreateRef(this EntitySet entitySet, params DbExpression[] keyValues)
{
return CreateRefExpression(entitySet, keyValues);
}
/// <summary>
/// Creates a new <see cref="DbRefExpression"/> that encodes a reference to a specific entity of a given type based on key values.
/// </summary>
/// <param name="entitySet">The entity set in which the referenced element resides.</param>
/// <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>
/// <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>
/// <returns>A new DbRefExpression that references the element with the specified key values in the given entity set.</returns>
/// <exception cref="ArgumentNullException"><paramref name="entitySet"/> or <paramref name="entityType"/> is null, or <paramref name="keyValues"/> is null or contains null.</exception>
/// <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>
/// <exception cref="ArgumentException">
/// The count of <paramref name="keyValues"/> does not match the count of key members declared by the <paramref name="entitySet"/>'s element type,
/// or <paramref name="keyValues"/> contains an expression with a result type that is not compatible with the type of the corresponding key member.
/// </exception>
public static DbRefExpression CreateRef(this EntitySet entitySet, EntityType entityType, IEnumerable<DbExpression> keyValues)
{
return CreateRefExpression(entitySet, entityType, keyValues);
}
/// <summary>
/// Creates a new <see cref="DbRefExpression"/> that encodes a reference to a specific entity of a given type based on key values.
/// </summary>
/// <param name="entitySet">The entity set in which the referenced element resides.</param>
/// <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>
/// <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>
/// <returns>A new DbRefExpression that references the element with the specified key values in the given entity set.</returns>
/// <exception cref="ArgumentNullException"><paramref name="entitySet"/> or <paramref name="entityType"/> is null, or <paramref name="keyValues"/> is null or contains null.</exception>
/// <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>
/// <exception cref="ArgumentException">
/// The count of <paramref name="keyValues"/> does not match the count of key members declared by the <paramref name="entitySet"/>'s element type,
/// or <paramref name="keyValues"/> contains an expression with a result type that is not compatible with the type of the corresponding key member.
/// </exception>
public static DbRefExpression CreateRef(this EntitySet entitySet, EntityType entityType, params DbExpression[] keyValues)
{
return CreateRefExpression(entitySet, entityType, keyValues);
}
private static DbRefExpression CreateRefExpression(EntitySet entitySet, IEnumerable<DbExpression> keyValues)
{
DbExpression keyConstructor;
TypeUsage refResultType = ArgumentValidation.ValidateCreateRef(entitySet, keyValues, out keyConstructor);
return new DbRefExpression(refResultType, entitySet, keyConstructor);
}
private static DbRefExpression CreateRefExpression(EntitySet entitySet, EntityType entityType, IEnumerable<DbExpression> keyValues)
{
DbExpression keyConstructor;
TypeUsage refResultType = ArgumentValidation.ValidateCreateRef(entitySet, entityType, keyValues, out keyConstructor);
return new DbRefExpression(refResultType, entitySet, keyConstructor);
}
/// <summary>
/// Creates a new <see cref="DbRefExpression"/> that encodes a reference to a specific Entity based on key values.
/// </summary>
/// <param name="entitySet">The Entity set in which the referenced element resides.</param>
/// <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>
/// <returns>A new DbRefExpression that references the element with the specified key values in the given Entity set.</returns>
/// <exception cref="ArgumentNullException"><paramref name="entitySet"/> or <paramref name="keyRow"/> is null</exception>
/// <exception cref="ArgumentException">
/// <paramref name="keyRow"/> does not have a record result type that matches the key properties of the referenced entity set's entity type.
/// </exception>
/// <remarks>
/// <paramref name="keyRow"/> should be an expression that specifies the key values that identify the referenced entity within the given entity set.
/// The result type of <paramref name="keyRow"/> should contain a corresponding column for each key property defined by <paramref name="entitySet"/>'s entity type.
/// </remarks>
public static DbRefExpression RefFromKey(this EntitySet entitySet, DbExpression keyRow)
{
TypeUsage refResultType = ArgumentValidation.ValidateRefFromKey(entitySet, keyRow);
return new DbRefExpression(refResultType, entitySet, keyRow);
}
/// <summary>
/// Creates a new <see cref="DbRefExpression"/> that encodes a reference to a specific Entity based on key values.
/// </summary>
/// <param name="entitySet">The Entity set in which the referenced element resides.</param>
/// <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>
/// <param name="entityType">The type of the Entity that the reference should refer to.</param>
/// <returns>A new DbRefExpression that references the element with the specified key values in the given Entity set.</returns>
/// <exception cref="ArgumentNullException"><paramref name="entitySet"/>, <paramref name="keyRow"/> or <paramref name="entityType"/> is null</exception>
/// <exception cref="ArgumentException">
/// <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
/// record result type that matches the key properties of the referenced entity set's entity type.
/// </exception>
/// <remarks>
/// <paramref name="keyRow"/> should be an expression that specifies the key values that identify the referenced entity within the given entity set.
/// The result type of <paramref name="keyRow"/> should contain a corresponding column for each key property defined by <paramref name="entitySet"/>'s entity type.
/// </remarks>
public static DbRefExpression RefFromKey(this EntitySet entitySet, DbExpression keyRow, EntityType entityType)
{
TypeUsage refResultType = ArgumentValidation.ValidateRefFromKey(entitySet, keyRow, entityType);
return new DbRefExpression(refResultType, entitySet, keyRow);
}
/// <summary>
/// Creates a new <see cref="DbRefKeyExpression"/> that retrieves the key values of the specifed reference in structural form.
/// </summary>
/// <param name="argument">The expression that provides the reference. This expression must have a reference Type with an Entity element type.</param>
/// <returns>A new DbRefKeyExpression that retrieves the key values of the specified reference.</returns>
/// <exception cref="ArgumentNullException"><paramref name="argument"/> is null</exception>
/// <exception cref="ArgumentException"><paramref name="argument"/> does not have a reference result type.</exception>
public static DbRefKeyExpression GetRefKey(this DbExpression argument)
{
TypeUsage rowResultType = ArgumentValidation.ValidateGetRefKey(argument);
return new DbRefKeyExpression(rowResultType, argument);
}
/// <summary>
/// Creates a new <see cref="DbRelationshipNavigationExpression"/> representing the navigation of a composition or association relationship.
/// </summary>
/// <param name="navigateFrom">An expression the specifies the instance from which navigation should occur</param>
/// <param name="fromEnd">Metadata for the property that represents the end of the relationship from which navigation should occur</param>
/// <param name="toEnd">Metadata for the property that represents the end of the relationship to which navigation should occur</param>
/// <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>
/// <exception cref="ArgumentNullException"><paramref name="fromEnd"/>, <paramref name="toEnd"/> or <paramref name="navigateFrom"/> is null</exception>
/// <exception cref="ArgumentException">
/// <paramref name="fromEnd"/> and <paramref name="toEnd"/> are not declared by the same relationship type, or
/// <paramref name="navigateFrom"/> has a result type that is not compatible with the property type of <paramref name="fromEnd"/>.
/// </exception>
/// <remarks>
/// <see cref="DbRelationshipNavigationExpression"/> requires that navigation always occur from a reference, and so <paramref name="navigateFrom"/> must always have a reference result type.
/// </remarks>
public static DbRelationshipNavigationExpression Navigate(this DbExpression navigateFrom, RelationshipEndMember fromEnd, RelationshipEndMember toEnd)
{
RelationshipType relType;
TypeUsage resultType = ArgumentValidation.ValidateNavigate(navigateFrom, fromEnd, toEnd, out relType, allowAllRelationshipsInSameTypeHierarchy: false);
return new DbRelationshipNavigationExpression(resultType, relType, fromEnd, toEnd, navigateFrom);
}
/// <summary>
/// Creates a new <see cref="DbRelationshipNavigationExpression"/> representing the navigation of a composition or association relationship.
/// </summary>
/// <param name="type">Metadata for the relation type that represents the relationship</param>
/// <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>
/// <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>
/// <param name="navigateFrom">An expression the specifies the instance from which naviagtion should occur</param>
/// <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>
/// <exception cref="ArgumentNullException">
/// <paramref name="type"/>, <paramref name="fromEndName"/>, <paramref name="toEndName"/> or <paramref name="navigateFrom"/> is null.
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="type"/> is not associated with this command tree's metadata workspace or <paramref name="navigateFrom"/> is associated with a different command tree,
/// or <paramref name="type"/> does not declare a relation end property with name <paramref name="toEndName"/> or <paramref name="fromEndName"/>,
/// 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"/>.
/// </exception>
/// <remarks>
/// <see cref="DbRelationshipNavigationExpression"/> requires that navigation always occur from a reference, and so <paramref name="navigateFrom"/> must always have a reference result type.
/// </remarks>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
public static DbRelationshipNavigationExpression Navigate(this RelationshipType type, string fromEndName, string toEndName, DbExpression navigateFrom)
{
RelationshipEndMember fromEnd;
RelationshipEndMember toEnd;
TypeUsage resultType = ArgumentValidation.ValidateNavigate(navigateFrom, type, fromEndName, toEndName, out fromEnd, out toEnd);
return new DbRelationshipNavigationExpression(resultType, type, fromEnd, toEnd, navigateFrom);
}
#endregion
#region Unary and Binary Set Operators - Distinct, Element, IsEmpty, Except, Intersect, UnionAll, Limit
/// <summary>
/// Creates a new <see cref="DbDistinctExpression"/> that removes duplicates from the given set argument.
/// </summary>
/// <param name="argument">An expression that defines the set over which to perfom the distinct operation.</param>
/// <returns>A new DbDistinctExpression that represents the distinct operation applied to the specified set argument.</returns>
/// <exception cref="ArgumentNullException"><paramref name="argument"/> is null</exception>
/// <exception cref="ArgumentException"><paramref name="argument"/> does not have a collection result type.</exception>
public static DbDistinctExpression Distinct(this DbExpression argument)
{
TypeUsage resultType = ArgumentValidation.ValidateDistinct(argument);
return new DbDistinctExpression(resultType, argument);
}
/// <summary>
/// Creates a new <see cref="DbElementExpression"/> that converts a set into a singleton.
/// </summary>
/// <param name="argument">An expression that specifies the input set.</param>
/// <returns>A DbElementExpression that represents the conversion of the set argument to a singleton.</returns>
/// <exception cref="ArgumentNullException"><paramref name="argument"/> is null</exception>
/// <exception cref="ArgumentException"><paramref name="argument"/> does not have a collection result type.</exception>
public static DbElementExpression Element(this DbExpression argument)
{
TypeUsage resultType = ArgumentValidation.ValidateElement(argument);
return new DbElementExpression(resultType, argument);
}
/// <summary>
/// Creates a new <see cref="DbIsEmptyExpression"/> that determines whether the specified set argument is an empty set.
/// </summary>
/// <param name="argument">An expression that specifies the input set</param>
/// <returns>A new DbIsEmptyExpression with the specified argument.</returns>
/// <exception cref="ArgumentNullException"><paramref name="argument"/> is null</exception>
/// <exception cref="ArgumentException"><paramref name="argument"/> does not have a collection result type.</exception>
public static DbIsEmptyExpression IsEmpty(this DbExpression argument)
{
TypeUsage booleanResultType = ArgumentValidation.ValidateIsEmpty(argument);
return new DbIsEmptyExpression(booleanResultType, argument);
}
/// <summary>
/// Creates a new <see cref="DbExceptExpression"/> that computes the subtraction of the right set argument from the left set argument.
/// </summary>
/// <param name="left">An expression that defines the left set argument.</param>
/// <param name="right">An expression that defines the right set argument.</param>
/// <returns>A new DbExceptExpression that represents the difference of the left argument from the right argument.</returns>
/// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
/// <exception cref="ArgumentException">No common collection result type exists between <paramref name="left"/> and <paramref name="right"/>.</exception>
public static DbExceptExpression Except(this DbExpression left, DbExpression right)
{
TypeUsage resultType = ArgumentValidation.ValidateExcept(left, right);
return new DbExceptExpression(resultType, left, right);
}
/// <summary>
/// Creates a new <see cref="DbIntersectExpression"/> that computes the intersection of the left and right set arguments.
/// </summary>
/// <param name="left">An expression that defines the left set argument.</param>
/// <param name="right">An expression that defines the right set argument.</param>
/// <returns>A new DbIntersectExpression that represents the intersection of the left and right arguments.</returns>
/// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
/// <exception cref="ArgumentException">No common collection result type exists between <paramref name="left"/> and <paramref name="right"/>.</exception>
public static DbIntersectExpression Intersect(this DbExpression left, DbExpression right)
{
TypeUsage resultType = ArgumentValidation.ValidateIntersect(left, right);
return new DbIntersectExpression(resultType, left, right);
}
/// <summary>
/// Creates a new <see cref="DbUnionAllExpression"/> that computes the union of the left and right set arguments and does not remove duplicates.
/// </summary>
/// <param name="left">An expression that defines the left set argument.</param>
/// <param name="right">An expression that defines the right set argument.</param>
/// <returns>A new DbUnionAllExpression that union, including duplicates, of the the left and right arguments.</returns>
/// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
/// <exception cref="ArgumentException">No common collection result type exists between <paramref name="left"/> and <paramref name="right"/>.</exception>
public static DbUnionAllExpression UnionAll(this DbExpression left, DbExpression right)
{
TypeUsage resultType = ArgumentValidation.ValidateUnionAll(left, right);
return new DbUnionAllExpression(resultType, left, right);
}
/// <summary>
/// Creates a new <see cref="DbLimitExpression"/> that restricts the number of elements in the Argument collection to the specified count Limit value.
/// Tied results are not included in the output.
/// </summary>
/// <param name="argument">An expression that specifies the input collection.</param>
/// <param name="count">An expression that specifies the limit value.</param>
/// <returns>A new DbLimitExpression with the specified argument and count limit values that does not include tied results.</returns>
/// <exception cref="ArgumentNullException"><paramref name="argument"/> or <paramref name="count"/> is null</exception>
/// <exception cref="ArgumentException">
/// <paramref name="argument"/> does not have a collection result type,
/// or <paramref name="count"/> does not have a result type that is equal or promotable to a 64-bit integer type.
/// </exception>
public static DbLimitExpression Limit(this DbExpression argument, DbExpression count)
{
TypeUsage resultType = ArgumentValidation.ValidateLimit(argument, count);
return new DbLimitExpression(resultType, argument, count, false);
}
#endregion
#region General Operators - Case, Function, NewInstance, Property
/// <summary>
/// Creates a new <see cref="DbCaseExpression"/>.
/// </summary>
/// <param name="whenExpressions">A list of expressions that provide the conditional for of each case.</param>
/// <param name="thenExpressions">A list of expressions that provide the result of each case.</param>
/// <param name="elseExpression">An expression that defines the result when no case is matched.</param>
/// <returns>A new DbCaseExpression with the specified cases and default result.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="whenExpressions"/> or <paramref name="thenExpressions"/> is null or contains null,
/// or <paramref name="elseExpression"/> is null.
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="whenExpressions"/> or <paramref name="thenExpressions"/> is empty or <paramref name="whenExpressions"/> contains an expression with a non-Boolean result type, or
/// No common result type exists for all expressions in <paramref name="thenExpressions"/> and <paramref name="elseExpression"/>.
/// </exception>
public static DbCaseExpression Case(IEnumerable<DbExpression> whenExpressions, IEnumerable<DbExpression> thenExpressions, DbExpression elseExpression)
{
DbExpressionList validWhens;
DbExpressionList validThens;
TypeUsage resultType = ArgumentValidation.ValidateCase(whenExpressions, thenExpressions, elseExpression, out validWhens, out validThens);
return new DbCaseExpression(resultType, validWhens, validThens, elseExpression);
}
/// <summary>
/// Creates a new <see cref="DbFunctionExpression"/> representing the invocation of the specified function with the given arguments.
/// </summary>
/// <param name="function">Metadata for the function to invoke.</param>
/// <param name="arguments">A list of expressions that provide the arguments to the function.</param>
/// <returns>A new DbFunctionExpression representing the function invocation.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="function"/> is null, or <paramref name="arguments"/> is null or contains null.
/// </exception>
/// <exception cref="ArgumentException">
/// The count of <paramref name="arguments"/> does not equal the number of parameters declared by <paramref name="function"/>,
/// or <paramref name="arguments"/> contains an expression that has a result type that is not equal or promotable
/// to the corresponding function parameter type.
/// </exception>
public static DbFunctionExpression Invoke(this EdmFunction function, IEnumerable<DbExpression> arguments)
{
return InvokeFunction(function, arguments);
}
/// <summary>
/// Creates a new <see cref="DbFunctionExpression"/> representing the invocation of the specified function with the given arguments.
/// </summary>
/// <param name="function">Metadata for the function to invoke.</param>
/// <param name="arguments">Expressions that provide the arguments to the function.</param>
/// <returns>A new DbFunctionExpression representing the function invocation.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="function"/> is null, or <paramref name="arguments"/> is null or contains null.
/// </exception>
/// <exception cref="ArgumentException">
/// The count of <paramref name="arguments"/> does not equal the number of parameters declared by <paramref name="function"/>,
/// or <paramref name="arguments"/> contains an expression that has a result type that is not equal or promotable
/// to the corresponding function parameter type.
/// </exception>
public static DbFunctionExpression Invoke(this EdmFunction function, params DbExpression[] arguments)
{
return InvokeFunction(function, arguments);
}
private static DbFunctionExpression InvokeFunction(EdmFunction function, IEnumerable<DbExpression> arguments)
{
DbExpressionList validArguments;
TypeUsage resultType = ArgumentValidation.ValidateFunction(function, arguments, out validArguments);
return new DbFunctionExpression(resultType, function, validArguments);
}
/// <summary>
/// Creates a new <see cref="DbLambdaExpression"/> representing the application of the specified Lambda function to the given arguments.
/// </summary>
/// <param name="lambda">A <see cref="DbLambda"/> instance representing the Lambda function to apply.</param>
/// <param name="arguments">A list of expressions that provide the arguments.</param>
/// <returns>A new DbLambdaExpression representing the Lambda function application.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="lambda"/> is null, or <paramref name="arguments"/> is null or contains null.
/// </exception>
/// <exception cref="ArgumentException">
/// The count of <paramref name="arguments"/> does not equal the number of variables declared by <paramref name="lambda"/>,
/// or <paramref name="arguments"/> contains an expression that has a result type that is not equal or promotable
/// to the corresponding variable type.
/// </exception>
public static DbLambdaExpression Invoke(this DbLambda lambda, IEnumerable<DbExpression> arguments)
{
return InvokeLambda(lambda, arguments);
}
/// <summary>
/// Creates a new <see cref="DbLambdaExpression"/> representing the application of the specified Lambda function to the given arguments.
/// </summary>
/// <param name="lambda">A <see cref="DbLambda"/> instance representing the Lambda function to apply.</param>
/// <param name="arguments">Expressions that provide the arguments.</param>
/// <returns>A new DbLambdaExpression representing the Lambda function application.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="lambda"/> is null, or <paramref name="arguments"/> is null or contains null.
/// </exception>
/// <exception cref="ArgumentException">
/// The count of <paramref name="arguments"/> does not equal the number of variables declared by <paramref name="lambda"/>,
/// or <paramref name="arguments"/> contains an expression that has a result type that is not equal or promotable
/// to the corresponding variable type.
/// </exception>
public static DbLambdaExpression Invoke(this DbLambda lambda, params DbExpression[] arguments)
{
return InvokeLambda(lambda, arguments);
}
private static DbLambdaExpression InvokeLambda(DbLambda lambda, IEnumerable<DbExpression> arguments)
{
DbExpressionList validArguments;
TypeUsage resultType = ArgumentValidation.ValidateInvoke(lambda, arguments, out validArguments);
return new DbLambdaExpression(resultType, lambda, validArguments);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="instanceType">The type of the new instance.</param>
/// <param name="arguments">Expressions that specify values of the new instances, interpreted according to the instance's type.</param>
/// <returns>A new DbNewInstanceExpression with the specified type and arguments.</returns>
/// <exception cref="ArgumentNullException"><paramref name="instanceType"/> or <paramref name="arguments"/> is null, or <paramref name="arguments"/> contains null</exception>
/// <exception cref="ArgumentException">
/// <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).
/// </exception>
/// <remarks>
/// <para>
/// 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"/>.
/// </para>
/// <para>
/// if <paramref name="instanceType"/> is a row type, <paramref name="arguments"/> must contain as many expressions as there are columns in the row
/// 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.
/// </para>
/// <para>
/// if <paramref name="instanceType"/> is an entity type, <paramref name="arguments"/> must contain as many expressions as there are properties defined by the type,
/// and the result type of each expression must be equal or promotable to the type of the corresponding property.
/// </para>
/// </remarks>
public static DbNewInstanceExpression New(this TypeUsage instanceType, IEnumerable<DbExpression> arguments)
{
return NewInstance(instanceType, arguments);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="instanceType">The type of the new instance.</param>
/// <param name="arguments">Expressions that specify values of the new instances, interpreted according to the instance's type.</param>
/// <returns>A new DbNewInstanceExpression with the specified type and arguments.</returns>
/// <exception cref="ArgumentNullException"><paramref name="instanceType"/> or <paramref name="arguments"/> is null, or <paramref name="arguments"/> contains null</exception>
/// <exception cref="ArgumentException">
/// <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).
/// </exception>
/// <remarks>
/// <para>
/// 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"/>.
/// </para>
/// <para>
/// if <paramref name="instanceType"/> is a row type, <paramref name="arguments"/> must contain as many expressions as there are columns in the row
/// 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.
/// </para>
/// <para>
/// if <paramref name="instanceType"/> is an entity type, <paramref name="arguments"/> must contain as many expressions as there are properties defined by the type,
/// and the result type of each expression must be equal or promotable to the type of the corresponding property.
/// </para>
/// </remarks>
public static DbNewInstanceExpression New(this TypeUsage instanceType, params DbExpression[] arguments)
{
return NewInstance(instanceType, arguments);
}
private static DbNewInstanceExpression NewInstance(TypeUsage instanceType, IEnumerable<DbExpression> arguments)
{
DbExpressionList validArguments;
TypeUsage resultType = ArgumentValidation.ValidateNew(instanceType, arguments, out validArguments);
return new DbNewInstanceExpression(resultType, validArguments);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="elements">A list of expressions that provide the elements of the collection</param>
/// <returns>A new DbNewInstanceExpression with the specified collection type and arguments.</returns>
/// <exception cref="ArgumentNullException"><paramref name="elements"/> is null, or contains null</exception>
/// <exception cref="ArgumentException">
/// <paramref name="elements"/> is empty or contains expressions for which no common result type exists.
/// </exception>
public static DbNewInstanceExpression NewCollection(IEnumerable<DbExpression> elements)
{
return CreateNewCollection(elements);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="elements">A list of expressions that provide the elements of the collection</param>
/// <returns>A new DbNewInstanceExpression with the specified collection type and arguments.</returns>
/// <exception cref="ArgumentNullException"><paramref name="elements"/> is null, or contains null</exception>
/// <exception cref="ArgumentException">
/// <paramref name="elements"/> is empty or contains expressions for which no common result type exists.
/// </exception>
public static DbNewInstanceExpression NewCollection(params DbExpression[] elements)
{
return CreateNewCollection(elements);
}
private static DbNewInstanceExpression CreateNewCollection(IEnumerable<DbExpression> elements)
{
DbExpressionList validElements;
TypeUsage collectionResultType = ArgumentValidation.ValidateNewCollection(elements, out validElements);
return new DbNewInstanceExpression(collectionResultType, validElements);
}
/// <summary>
/// Creates a new <see cref="DbNewInstanceExpression"/> that constructs an empty collection of the specified collection type.
/// </summary>
/// <param name="collectionType">The type metadata for the collection to create</param>
/// <returns>A new DbNewInstanceExpression with the specified collection type and an empty <code>Arguments</code> list.</returns>
/// <exception cref="ArgumentNullException"><paramref name="collectionType"/> is null</exception>
/// <exception cref="ArgumentException"><paramref name="collectionType"/> is not a collection type</exception>
public static DbNewInstanceExpression NewEmptyCollection(this TypeUsage collectionType)
{
DbExpressionList validElements;
TypeUsage validResultType = ArgumentValidation.ValidateNewEmptyCollection(collectionType, out validElements);
return new DbNewInstanceExpression(validResultType, validElements);
}
/// <summary>
/// Creates a new <see cref="DbNewInstanceExpression"/> that produces a row with the specified named columns and the given values, specified as expressions.
/// </summary>
/// <param name="columnValues">A list of string-DbExpression key-value pairs that defines the structure and values of the row.</param>
/// <returns>A new DbNewInstanceExpression that represents the construction of the row.</returns>
/// <exception cref="ArgumentNullException"><paramref name="columnValues"/> is null or contains an element with a null column name or expression</exception>
/// <exception cref="ArgumentException">
/// <paramref name="columnValues"/> is empty, or contains a duplicate or invalid column name
/// </exception>
public static DbNewInstanceExpression NewRow(IEnumerable<KeyValuePair<string, DbExpression>> columnValues)
{
DbExpressionList validElements;
TypeUsage resultType = ArgumentValidation.ValidateNewRow(columnValues, out validElements);
return new DbNewInstanceExpression(resultType, validElements);
}
/// <summary>
/// Creates a new <see cref="DbPropertyExpression"/> representing the retrieval of the specified property.
/// </summary>
/// <param name="instance">The instance from which to retrieve the property. May be null if the property is static.</param>
/// <param name="propertyMetadata">Metadata for the property to retrieve.</param>
/// <returns>A new DbPropertyExpression representing the property retrieval.</returns>
/// <exception cref="ArgumentNullException"><paramref name="propertyMetadata"/> is null or <paramref name="instance"/> is null and the property is not static.</exception>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "required for this feature")]
public static DbPropertyExpression Property(this DbExpression instance, EdmProperty propertyMetadata)
{
return PropertyFromMember(instance, propertyMetadata, "propertyMetadata");
}
/// <summary>
/// Creates a new <see cref="DbPropertyExpression"/> representing the retrieval of the specified navigation property.
/// </summary>
/// <param name="instance">The instance from which to retrieve the navigation property.</param>
/// <param name="navigationProperty">Metadata for the navigation property to retrieve.</param>
/// <returns>A new DbPropertyExpression representing the navigation property retrieval.</returns>
/// <exception cref="ArgumentNullException"><paramref name="navigationProperty"/> is null or <paramref name="instance"/> is null.</exception>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "required for this feature")]
public static DbPropertyExpression Property(this DbExpression instance, NavigationProperty navigationProperty)
{
return PropertyFromMember(instance, navigationProperty, "navigationProperty");
}
/// <summary>
/// Creates a new <see cref="DbPropertyExpression"/> representing the retrieval of the specified relationship end member.
/// </summary>
/// <param name="instance">The instance from which to retrieve the relationship end member.</param>
/// <param name="relationshipEnd">Metadata for the relationship end member to retrieve.</param>
/// <returns>A new DbPropertyExpression representing the relationship end member retrieval.</returns>
/// <exception cref="ArgumentNullException"><paramref name="relationshipEnd"/> is null or <paramref name="instance"/> is null and the property is not static.</exception>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "required for this feature")]
public static DbPropertyExpression Property(this DbExpression instance, RelationshipEndMember relationshipEnd)
{
return PropertyFromMember(instance, relationshipEnd, "relationshipEnd");
}
/// <summary>
/// Creates a new <see cref="DbPropertyExpression"/> representing the retrieval of the instance property with the specified name from the given instance.
/// </summary>
/// <param name="propertyName">The name of the property to retrieve.</param>
/// <param name="instance">The instance from which to retrieve the property.</param>
/// <returns>A new DbPropertyExpression that represents the property retrieval</returns>
/// <exception cref="ArgumentNullException"><paramref name="propertyName"/> is null or <paramref name="instance"/> is null and the property is not static.</exception>
/// <exception cref="ArgumentOutOfRangeException">No property with the specified name is declared by the type of <paramref name="instance"/>.</exception>
public static DbPropertyExpression Property(this DbExpression instance, string propertyName)
{
return PropertyByName(instance, propertyName, false);
}
private static DbPropertyExpression PropertyFromMember(DbExpression instance, EdmMember property, string propertyArgumentName)
{
TypeUsage resultType = ArgumentValidation.ValidateProperty(instance, property, propertyArgumentName);
return new DbPropertyExpression(resultType, property, instance);
}
private static DbPropertyExpression PropertyByName(DbExpression instance, string propertyName, bool ignoreCase)
{
EdmMember property;
TypeUsage resultType = ArgumentValidation.ValidateProperty(instance, propertyName, ignoreCase, out property);
return new DbPropertyExpression(resultType, property, instance);
}
#endregion
#region Lambda-based methods: All, Any, Cross|OuterApply, Cross|FullOuter|Inner|LeftOuterJoin, Filter, GroupBy, Project, Skip, Sort
private static string ExtractAlias(MethodInfo method)
{
Debug.Assert(method != null, "Ensure method is non-null before calling ExtractAlias");
string[] aliases = ExtractAliases(method);
Debug.Assert(aliases.Length > 0, "Incompatible method: at least one parameter is required");
return aliases[0];
}
internal static string[] ExtractAliases(MethodInfo method)
{
Debug.Assert(method != null, "Ensure method is non-null before calling ExtractAlias");
ParameterInfo[] methodParams = method.GetParameters();
int start;
int paramCount;
if (method.IsStatic && typeof(System.Runtime.CompilerServices.Closure) == methodParams[0].ParameterType)
{
// Static lambda method has additional first closure parameter
start = 1;
paramCount = methodParams.Length - 1;
}
else
{
// Otherwise, method parameters align directly with arguments
start = 0;
paramCount = methodParams.Length;
}
string[] paramNames = new string[paramCount];
bool generateNames = methodParams.Skip(start).Any(p => p.Name == null);
for (int idx = start; idx < methodParams.Length; idx++)
{
paramNames[idx - start] = (generateNames ? _bindingAliases.Next() : methodParams[idx].Name);
}
return paramNames;
}
private static DbExpressionBinding ConvertToBinding<TResult>(DbExpression source, Func<DbExpression, TResult> argument, string argumentName, out TResult argumentResult)
{
return ConvertToBinding(source, "source", argument, argumentName, out argumentResult);
}
private static DbExpressionBinding ConvertToBinding<TResult>(DbExpression source, string sourceName, Func<DbExpression, TResult> argument, string argumentName, out TResult argumentResult)
{
EntityUtil.CheckArgumentNull(source, sourceName);
EntityUtil.CheckArgumentNull(argument, argumentName);
string alias = ExtractAlias(argument.Method);
DbExpressionBinding binding = DbExpressionBuilder.BindAs(source, alias);
argumentResult = argument(binding.Variable);
return binding;
}
private static DbExpressionBinding[] ConvertToBinding(DbExpression left, string leftArgumentName, DbExpression right, string rightArgumentName, Func<DbExpression, DbExpression, DbExpression> argument, string argumentName, out DbExpression argumentExp)
{
EntityUtil.CheckArgumentNull(left, leftArgumentName);
EntityUtil.CheckArgumentNull(right, rightArgumentName);
EntityUtil.CheckArgumentNull(argument, argumentName);
string[] aliases = ExtractAliases(argument.Method);
DbExpressionBinding leftBinding = DbExpressionBuilder.BindAs(left, aliases[0]);
DbExpressionBinding rightBinding = DbExpressionBuilder.BindAs(right, aliases[1]);
argumentExp = argument(leftBinding.Variable, rightBinding.Variable);
return new[] { leftBinding, rightBinding };
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
private static bool TryGetAnonymousTypeValues<TInstance, TRequired>(object instance, out List<KeyValuePair<string, TRequired>> values)
{
Debug.Assert(instance != null, "Ensure instance is non-null before calling TryGetAnonymousTypeValues");
// The following heuristic is used to approximate whether or not TInstance is an anonymous type:
// - Derived directly from System.Object
// - Declares only public instance properties
// - All public instance properties are readable and of an appropriate type
values = null;
if (typeof(TInstance).BaseType.Equals(typeof(object)) &&
typeof(TInstance).GetProperties(BindingFlags.Static).Length == 0 &&
typeof(TInstance).GetProperties(BindingFlags.Instance | BindingFlags.NonPublic).Length == 0)
{
List<KeyValuePair<string, TRequired>> foundValues = null;
foreach (PropertyInfo pi in typeof(TInstance).GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
if (pi.CanRead && typeof(TRequired).IsAssignableFrom(pi.PropertyType))
{
if (foundValues == null)
{
foundValues = new List<KeyValuePair<string, TRequired>>();
}
foundValues.Add(new KeyValuePair<string, TRequired>(pi.Name, (TRequired)pi.GetValue(instance, null)));
}
else
{
foundValues = null;
break;
}
}
values = foundValues;
}
return (values != null);
}
private static bool TryResolveToConstant(Type type, object value, out DbExpression constantOrNullExpression)
{
constantOrNullExpression = null;
Type valueType = type;
if (type.IsGenericType && typeof(Nullable<>).Equals(type.GetGenericTypeDefinition()))
{
valueType = type.GetGenericArguments()[0];
}
PrimitiveTypeKind primitiveTypeKind;
if (ClrProviderManifest.Instance.TryGetPrimitiveTypeKind(valueType, out primitiveTypeKind))
{
TypeUsage resultType = TypeHelpers.GetLiteralTypeUsage(primitiveTypeKind);
if (null == value)
{
constantOrNullExpression = DbExpressionBuilder.Null(resultType);
}
else
{
constantOrNullExpression = DbExpressionBuilder.Constant(resultType, value);
}
}
return (constantOrNullExpression != null);
}
private static DbExpression ResolveToExpression<TArgument>(TArgument argument)
{
object untypedArgument = argument;
DbExpression constantResult;
if (TryResolveToConstant(typeof(TArgument), untypedArgument, out constantResult))
{
return constantResult;
}
if (null == untypedArgument)
{
return (DbExpression)null;
}
// Direct DbExpression result
if (typeof(DbExpression).IsAssignableFrom(typeof(TArgument)))
{
return (DbExpression)untypedArgument;
}
// Row
if (typeof(Row).Equals(typeof(TArgument)))
{
return ((Row)untypedArgument).ToExpression();
}
// Conversion from anonymous type instance to DbNewInstanceExpression of a corresponding row type
List<KeyValuePair<string, DbExpression>> columnValues;
if (TryGetAnonymousTypeValues<TArgument, DbExpression>(untypedArgument, out columnValues))
{
return DbExpressionBuilder.NewRow(columnValues);
}
// The specified instance cannot be resolved to a DbExpression
throw EntityUtil.NotSupported(Strings.Cqt_Factory_MethodResultTypeNotSupported(typeof(TArgument).FullName));
}
private static DbApplyExpression CreateApply(DbExpression source, Func<DbExpression, KeyValuePair<string, DbExpression>> apply, Func<DbExpressionBinding, DbExpressionBinding, DbApplyExpression> resultBuilder)
{
KeyValuePair<string, DbExpression> applyTemplate;
DbExpressionBinding sourceBinding = ConvertToBinding(source, apply, "apply", out applyTemplate);
DbExpressionBinding applyBinding = DbExpressionBuilder.BindAs(applyTemplate.Value, applyTemplate.Key);
return resultBuilder(sourceBinding, applyBinding);
}
/// <summary>
/// Creates a new <see cref="DbQuantifierExpression"/> that determines whether the given predicate holds for all elements of the input set.
/// </summary>
/// <param name="source">
/// An expression that specifies the input set.
/// </param>
/// <param name="predicate">
/// A method representing a predicate to evaluate for each member of the input set.
/// This method must produce an expression with a Boolean result type that provides
/// the predicate logic.
/// </param>
/// <returns>A new DbQuantifierExpression that represents the All operation.</returns>
/// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="predicate"/> is null</exception>
/// <exception cref="ArgumentNullException">The expression produced by <paramref name="predicate"/> is null</exception>
/// <exception cref="ArgumentException"><paramref name="source"/> does not have a collection result type.</exception>
/// <exception cref="ArgumentException">
/// The expression produced by <paramref name="predicate"/> does not have a Boolean result type.
/// </exception>
public static DbQuantifierExpression All(this DbExpression source, Func<DbExpression, DbExpression> predicate)
{
DbExpression predicateExp;
DbExpressionBinding input = ConvertToBinding(source, predicate, "predicate", out predicateExp);
return DbExpressionBuilder.All(input, predicateExp);
}
/// <summary>
/// Creates a new <see cref="DbExpression"/> that determines whether the specified set argument is non-empty.
/// </summary>
/// <param name="source">An expression that specifies the input set</param>
/// <returns>A new <see cref="DbNotExpression"/> applied to a new <see cref="DbIsEmptyExpression"/> with the specified argument.</returns>
/// <exception cref="ArgumentNullException"><paramref name="source"/> is null</exception>
/// <exception cref="ArgumentException"><paramref name="source"/> does not have a collection result type.</exception>
public static DbExpression Any(this DbExpression source)
{
return DbExpressionBuilder.Exists(source);
}
/// <summary>
/// Creates a new <see cref="DbExpression"/> that determines whether the specified set argument is non-empty.
/// </summary>
/// <param name="argument">An expression that specifies the input set</param>
/// <returns>A new <see cref="DbNotExpression"/> applied to a new <see cref="DbIsEmptyExpression"/> with the specified argument.</returns>
/// <exception cref="ArgumentNullException"><paramref name="argument"/> is null</exception>
/// <exception cref="ArgumentException"><paramref name="argument"/> does not have a collection result type.</exception>
public static DbExpression Exists(this DbExpression argument)
{
return DbExpressionBuilder.Not(DbExpressionBuilder.IsEmpty(argument));
}
/// <summary>
/// Creates a new <see cref="DbQuantifierExpression"/> that determines whether the given predicate holds for any element of the input set.
/// </summary>
/// <param name="source">
/// An expression that specifies the input set.
/// </param>
/// <param name="predicate">
/// A method representing the predicate to evaluate for each member of the input set.
/// This method must produce an expression with a Boolean result type that provides
/// the predicate logic.
/// </param>
/// <returns>A new DbQuantifierExpression that represents the Any operation.</returns>
/// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="predicate"/> is null</exception>
/// <exception cref="ArgumentNullException">The expression produced by <paramref name="predicate"/> is null</exception>
/// <exception cref="ArgumentException"><paramref name="source"/> does not have a collection result type.</exception>
/// <exception cref="ArgumentException">
/// The expression produced by <paramref name="predicate"/> does not have a Boolean result type.
/// </exception>
public static DbQuantifierExpression Any(this DbExpression source, Func<DbExpression, DbExpression> predicate)
{
DbExpression predicateExp;
DbExpressionBinding input = ConvertToBinding(source, predicate, "predicate", out predicateExp);
return DbExpressionBuilder.Any(input, predicateExp);
}
/// <summary>
/// Creates a new <see cref="DbApplyExpression"/> that evaluates the given <paramref name="apply"/> expression once for each element of a given input set,
/// 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.
/// </summary>
/// <param name="source">
/// A <see cref="DbExpression"/> that specifies the input set.
/// </param>
/// <param name="apply">
/// A method that specifies the logic to evaluate once for each member of the input set.
/// </param>
/// <returns>An new DbApplyExpression with the specified input and apply bindings and an <see cref="DbExpressionKind"/> of CrossApply.</returns>
/// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="apply"/> is null</exception>
/// <exception cref="ArgumentException"><paramref name="source"/> does not have a collection result type.</exception>
/// <exception cref="ArgumentNullException">The result of <paramref name="apply"/> contains a name or expression that is null.</exception>
/// <exception cref="ArgumentException">The result of <paramref name="apply"/> contains a name or expression that is not valid in an expression binding.</exception>
public static DbApplyExpression CrossApply(this DbExpression source, Func<DbExpression, KeyValuePair<string, DbExpression>> apply)
{
return CreateApply(source, apply, DbExpressionBuilder.CrossApply);
}
//
/// <summary>
/// Creates a new <see cref="DbApplyExpression"/> that evaluates the given <paramref name="apply"/> expression once for each element of a given input set,
/// 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>.
/// </summary>
/// <param name="source">
/// A <see cref="DbExpression"/> that specifies the input set.
/// </param>
/// <param name="apply">
/// A method that specifies the logic to evaluate once for each member of the input set.
/// </param>
/// <returns>An new DbApplyExpression with the specified input and apply bindings and an <see cref="DbExpressionKind"/> of OuterApply.</returns>
/// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="apply"/> is null</exception>
/// <exception cref="ArgumentException"><paramref name="source"/> does not have a collection result type.</exception>
/// <exception cref="ArgumentNullException">The result of <paramref name="apply"/> contains a name or expression that is null.</exception>
/// <exception cref="ArgumentException">The result of <paramref name="apply"/> contains a name or expression that is not valid in an expression binding.</exception>
public static DbApplyExpression OuterApply(this DbExpression source, Func<DbExpression, KeyValuePair<string, DbExpression>> apply)
{
return CreateApply(source, apply, DbExpressionBuilder.OuterApply);
}
//
//
/// <summary>
/// Creates a new <see cref="DbJoinExpression"/> that joins the sets specified by the left and right expressions,
/// on the specified join condition, using FullOuterJoin as the <see cref="DbExpressionKind"/>.
/// </summary>
/// <param name="left">A <see cref="DbExpression"/> that specifies the left set argument.</param>
/// <param name="right">A <see cref="DbExpression"/> that specifies the right set argument.</param>
/// <param name="joinCondition">
/// A method representing the condition on which to join.
/// This method must produce an expression with a Boolean result type that provides the
/// logic of the join condition.
/// </param>
/// <returns>
/// A new DbJoinExpression, with an <see cref="DbExpressionKind"/> of FullOuterJoin, that represents the full outer join operation
/// applied to the left and right input sets under the given join condition.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="left"/>, <paramref name="right"/> or <paramref name="joinCondition"/> is null.
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="left"/> or <paramref name="right"/> does not have a collection result type.
/// </exception>
/// <exception cref="ArgumentNullException">
/// The expression produced by <paramref name="joinCondition"/> is null.
/// </exception>
/// <exception cref="ArgumentException">
/// The expression produced by <paramref name="joinCondition"/> does not have a Boolean result type.
/// </exception>
public static DbJoinExpression FullOuterJoin(this DbExpression left, DbExpression right, Func<DbExpression, DbExpression, DbExpression> joinCondition)
{
DbExpression condExp;
DbExpressionBinding[] inputs = ConvertToBinding(left, "left", right, "right", joinCondition, "joinCondition", out condExp);
return DbExpressionBuilder.FullOuterJoin(inputs[0], inputs[1], condExp);
}
/// <summary>
/// Creates a new <see cref="DbJoinExpression"/> that joins the sets specified by the left and right expressions,
/// on the specified join condition, using InnerJoin as the <see cref="DbExpressionKind"/>.
/// </summary>
/// <param name="left">A <see cref="DbExpression"/> that specifies the left set argument.</param>
/// <param name="right">A <see cref="DbExpression"/> that specifies the right set argument.</param>
/// <param name="joinCondition">
/// A method representing the condition on which to join.
/// This method must produce an expression with a Boolean result type that provides the
/// logic of the join condition.
/// </param>
/// <returns>
/// A new DbJoinExpression, with an <see cref="DbExpressionKind"/> of InnerJoin, that represents the inner join operation
/// applied to the left and right input sets under the given join condition.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="left"/>, <paramref name="right"/> or <paramref name="joinCondition"/> is null.
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="left"/> or <paramref name="right"/> does not have a collection result type.
/// </exception>
/// <exception cref="ArgumentNullException">
/// The expression produced by <paramref name="joinCondition"/> is null.
/// </exception>
/// <exception cref="ArgumentException">
/// The expression produced by <paramref name="joinCondition"/> does not have a Boolean result type.
/// </exception>
public static DbJoinExpression InnerJoin(this DbExpression left, DbExpression right, Func<DbExpression, DbExpression, DbExpression> joinCondition)
{
DbExpression condExp;
DbExpressionBinding[] inputs = ConvertToBinding(left, "left", right, "right", joinCondition, "joinCondition", out condExp);
return DbExpressionBuilder.InnerJoin(inputs[0], inputs[1], condExp);
}
/// <summary>
/// Creates a new <see cref="DbJoinExpression"/> that joins the sets specified by the left and right expressions,
/// on the specified join condition, using LeftOuterJoin as the <see cref="DbExpressionKind"/>.
/// </summary>
/// <param name="left">A <see cref="DbExpression"/> that specifies the left set argument.</param>
/// <param name="right">A <see cref="DbExpression"/> that specifies the right set argument.</param>
/// <param name="joinCondition">
/// A method representing the condition on which to join.
/// This method must produce an expression with a Boolean result type that provides the
/// logic of the join condition.
/// </param>
/// <returns>
/// A new DbJoinExpression, with an <see cref="DbExpressionKind"/> of LeftOuterJoin, that represents the left outer join operation
/// applied to the left and right input sets under the given join condition.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="left"/>, <paramref name="right"/> or <paramref name="joinCondition"/> is null.
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="left"/> or <paramref name="right"/> does not have a collection result type.
/// </exception>
/// <exception cref="ArgumentNullException">
/// The expression produced by <paramref name="joinCondition"/> is null.
/// </exception>
/// <exception cref="ArgumentException">
/// The expression produced by <paramref name="joinCondition"/> does not have a Boolean result type.
/// </exception>
public static DbJoinExpression LeftOuterJoin(this DbExpression left, DbExpression right, Func<DbExpression, DbExpression, DbExpression> joinCondition)
{
DbExpression condExp;
DbExpressionBinding[] inputs = ConvertToBinding(left, "left", right, "right", joinCondition, "joinCondition", out condExp);
return DbExpressionBuilder.LeftOuterJoin(inputs[0], inputs[1], condExp);
}
/// <summary>
/// Creates a new <see cref="DbJoinExpression"/> that joins the sets specified by the outer and inner expressions,
/// on an equality condition between the specified outer and inner keys, using InnerJoin as the <see cref="DbExpressionKind"/>.
/// </summary>
/// <param name="outer">A <see cref="DbExpression"/> that specifies the outer set argument.</param>
/// <param name="inner">A <see cref="DbExpression"/> that specifies the inner set argument.</param>
/// <param name="outerKey">A method that specifies how the outer key value should be derived from an element of the outer set.</param>
/// <param name="innerKey">A method that specifies how the inner key value should be derived from an element of the inner set.</param>
/// <returns>
/// A new DbJoinExpression, with an <see cref="DbExpressionKind"/> of InnerJoin, that represents the inner join operation
/// applied to the left and right input sets under a join condition that compares the outer and inner key values for equality.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="outer"/>, <paramref name="inner"/>, <paramref name="outerKey"/> or <paramref name="innerKey"/> is null.
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="outer"/> or <paramref name="inner"/> does not have a collection result type.
/// </exception>
/// <exception cref="ArgumentNullException">
/// The expression produced by <paramref name="outerKey"/> or <paramref name="innerKey"/> is null.
/// </exception>
/// <exception cref="ArgumentException">
/// The expressions produced by <paramref name="outerKey"/> and <paramref name="innerKey"/> are not comparable for equality.
/// </exception>
public static DbJoinExpression Join(this DbExpression outer, DbExpression inner, Func<DbExpression, DbExpression> outerKey, Func<DbExpression, DbExpression> innerKey)
{
DbExpression leftOperand;
DbExpressionBinding leftBinding = ConvertToBinding(outer, "outer", outerKey, "outerKey", out leftOperand);
DbExpression rightOperand;
DbExpressionBinding rightBinding = ConvertToBinding(inner, "inner", innerKey, "innerKey", out rightOperand);
DbExpression joinCondition = DbExpressionBuilder.Equal(leftOperand, rightOperand);
return DbExpressionBuilder.InnerJoin(leftBinding, rightBinding, joinCondition);
}
/// <summary>
/// Creates a new <see cref="DbProjectExpression"/> that projects the specified selector over the sets specified by the outer and inner
/// expressions, joined on an equality condition between the specified outer and inner keys, using InnerJoin as the <see cref="DbExpressionKind"/>.
/// </summary>
/// <param name="outer">A <see cref="DbExpression"/> that specifies the outer set argument.</param>
/// <param name="inner">A <see cref="DbExpression"/> that specifies the inner set argument.</param>
/// <param name="outerKey">A method that specifies how the outer key value should be derived from an element of the outer set.</param>
/// <param name="innerKey">A method that specifies how the inner key value should be derived from an element of the inner set.</param>
/// <param name="selector">
/// A method that specifies how an element of the result set should be derived from elements of the inner and outer sets.
/// This method must produce an instance of a type that is compatible with Join and can be resolved
/// into a <see cref="DbExpression"/>.
/// Compatibility requirements for <typeparamref name="TSelector"/> are described in remarks.
/// </param>
/// <returns>
/// A new DbProjectExpression with the specified selector as its projection, and a new DbJoinExpression as its input.
/// The input DbJoinExpression is created with an <see cref="DbExpressionKind"/> of InnerJoin, that represents the inner join operation
/// applied to the left and right input sets under a join condition that compares the outer and inner key values for equality.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="outer"/>, <paramref name="inner"/>, <paramref name="outerKey"/>, <paramref name="innerKey"/> or <paramref name="selector"/> is null.
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="outer"/> or <paramref name="inner"/> does not have a collection result type.
/// </exception>
/// <exception cref="ArgumentNullException">
/// The expression produced by <paramref name="outerKey"/> or <paramref name="innerKey"/> is null.
/// </exception>
/// <exception cref="ArgumentNullException">
/// The result of <paramref name="selector"/> is null after conversion to DbExpression.
/// </exception>
/// <exception cref="ArgumentException">
/// The expressions produced by <paramref name="outerKey"/> and <paramref name="innerKey"/> are not comparable for equality.
/// </exception>
/// <exception cref="ArgumentException">
/// The result of <paramref name="selector"/> is not compatible with SelectMany.
/// </exception>
/// <remarks>
/// To be compatible with Join, <typeparamref name="TSelector"/> must be derived from <see cref="DbExpression"/>,
/// or must be an anonymous type with DbExpression-derived properties.
/// <para>
/// The following are examples of supported types for <typeparamref name="TSelector"/>:
/// <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"/>).
/// <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).
/// </para>
/// </remarks>
public static DbProjectExpression Join<TSelector>(this DbExpression outer, DbExpression inner, Func<DbExpression, DbExpression> outerKey, Func<DbExpression, DbExpression> innerKey, Func<DbExpression, DbExpression, TSelector> selector)
{
// Defer argument validation for all but the selector to the selector-less overload of Join
DbJoinExpression joinExpression = DbExpressionBuilder.Join(outer, inner, outerKey, innerKey);
// Ensure that the selector is non-null;
EntityUtil.CheckArgumentNull(selector, "selector");
// Bind the join expression and produce the selector based on the left and right inputs
DbExpressionBinding joinBinding = DbExpressionBuilder.Bind(joinExpression);
DbExpression left = DbExpressionBuilder.Property(joinBinding.Variable, joinExpression.Left.VariableName);
DbExpression right = DbExpressionBuilder.Property(joinBinding.Variable, joinExpression.Right.VariableName);
TSelector intermediateSelector = selector(left, right);
DbExpression projection = DbExpressionBuilder.ResolveToExpression(intermediateSelector);
// Project the selector over the join expression and return the resulting DbProjectExpression
return DbExpressionBuilder.Project(joinBinding, projection);
}
/// <summary>
/// Creates a new <see cref="DbSortExpression"/> that sorts the given input set by the specified sort key,
/// with ascending sort order and default collation.
/// </summary>
/// <param name="source">An expression that specifies the input set.</param>
/// <param name="sortKey">
/// A method that specifies how to derive the sort key expression given a member of the input set.
/// This method must produce an expression with an order-comparable result type that provides the
/// sort key definition.
/// </param>
/// <returns>A new DbSortExpression that represents the order-by operation.</returns>
/// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="sortKey"/> is null.</exception>
/// <exception cref="ArgumentNullException">The expression produced by <paramref name="sortKey"/> is null.</exception>
/// <exception cref="ArgumentException"><paramref name="source"/> does not have a collection result type.</exception>
/// <exception cref="ArgumentException">
/// The expression produced by <paramref name="sortKey"/> does not have an order-comparable result type.
/// </exception>
public static DbSortExpression OrderBy(this DbExpression source, Func<DbExpression, DbExpression> sortKey)
{
DbExpression keyExpression;
DbExpressionBinding input = ConvertToBinding(source, sortKey, "sortKey", out keyExpression);
DbSortClause sortClause = DbExpressionBuilder.ToSortClause(keyExpression);
return DbExpressionBuilder.Sort(input, new DbSortClause[] { sortClause });
}
/// <summary>
/// Creates a new <see cref="DbSortExpression"/> that sorts the given input set by the specified sort key,
/// with ascending sort order and the specified collation.
/// </summary>
/// <param name="source">An expression that specifies the input set.</param>
/// <param name="sortKey">
/// A method that specifies how to derive the sort key expression given a member of the input set.
/// This method must produce an expression with an order-comparable result type that provides the
/// sort key definition.
/// </param>
/// <param name="collation">The collation to sort under</param>
/// <returns>A new DbSortExpression that represents the order-by operation.</returns>
/// <exception cref="ArgumentNullException"><paramref name="source"/>, <paramref name="sortKey"/> or <paramref name="collation"/> is null.</exception>
/// <exception cref="ArgumentNullException">The expression produced by <paramref name="sortKey"/> is null.</exception>
/// <exception cref="ArgumentException"><paramref name="source"/> does not have a collection result type.</exception>
/// <exception cref="ArgumentException">
/// The expression produced by <paramref name="sortKey"/> does not have an order-comparable string result type.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="collation"/> is empty or contains only space characters</exception>
public static DbSortExpression OrderBy(this DbExpression source, Func<DbExpression, DbExpression> sortKey, string collation)
{
DbExpression keyExpression;
DbExpressionBinding input = ConvertToBinding(source, sortKey, "sortKey", out keyExpression);
DbSortClause sortClause = DbExpressionBuilder.ToSortClause(keyExpression, collation);
return DbExpressionBuilder.Sort(input, new DbSortClause[] { sortClause });
}
/// <summary>
/// Creates a new <see cref="DbSortExpression"/> that sorts the given input set by the specified sort key,
/// with descending sort order and default collation.
/// </summary>
/// <param name="source">An expression that specifies the input set.</param>
/// <param name="sortKey">
/// A method that specifies how to derive the sort key expression given a member of the input set.
/// This method must produce an expression with an order-comparable result type that provides the
/// sort key definition.
/// </param>
/// <returns>A new DbSortExpression that represents the order-by operation.</returns>
/// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="sortKey"/> is null.</exception>
/// <exception cref="ArgumentNullException">The expression produced by <paramref name="sortKey"/> is null.</exception>
/// <exception cref="ArgumentException"><paramref name="source"/> does not have a collection result type.</exception>
/// <exception cref="ArgumentException">
/// The expression produced by <paramref name="sortKey"/> does not have an order-comparable result type.
/// </exception>
public static DbSortExpression OrderByDescending(this DbExpression source, Func<DbExpression, DbExpression> sortKey)
{
DbExpression keyExpression;
DbExpressionBinding input = ConvertToBinding(source, sortKey, "sortKey", out keyExpression);
DbSortClause sortClause = DbExpressionBuilder.ToSortClauseDescending(keyExpression);
return DbExpressionBuilder.Sort(input, new DbSortClause[] { sortClause });
}
/// <summary>
/// Creates a new <see cref="DbSortExpression"/> that sorts the given input set by the specified sort key,
/// with descending sort order and the specified collation.
/// </summary>
/// <param name="source">An expression that specifies the input set.</param>
/// <param name="sortKey">
/// A method that specifies how to derive the sort key expression given a member of the input set.
/// This method must produce an expression with an order-comparable result type that provides the
/// sort key definition.
/// </param>
/// <param name="collation">The collation to sort under</param>
/// <returns>A new DbSortExpression that represents the order-by operation.</returns>
/// <exception cref="ArgumentNullException"><paramref name="source"/>, <paramref name="sortKey"/> or <paramref name="collation"/> is null.</exception>
/// <exception cref="ArgumentNullException">The expression produced by <paramref name="sortKey"/> is null.</exception>
/// <exception cref="ArgumentException"><paramref name="source"/> does not have a collection result type.</exception>
/// <exception cref="ArgumentException">
/// The expression produced by <paramref name="sortKey"/> does not have an order-comparable string result type.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="collation"/> is empty or contains only space characters</exception>
public static DbSortExpression OrderByDescending(this DbExpression source, Func<DbExpression, DbExpression> sortKey, string collation)
{
DbExpression keyExpression;
DbExpressionBinding input = ConvertToBinding(source, sortKey, "sortKey", out keyExpression);
DbSortClause sortClause = DbExpressionBuilder.ToSortClauseDescending(keyExpression, collation);
return DbExpressionBuilder.Sort(input, new DbSortClause[] { sortClause });
}
/// <summary>
/// Creates a new <see cref="DbProjectExpression"/> that selects the specified expression over the given input set.
/// </summary>
/// <param name="source">An expression that specifies the input set.</param>
/// <param name="projection">
/// A method that specifies how to derive the projected expression given a member of the input set.
/// This method must produce an instance of a type that is compatible with Select and can be resolved
/// into a <see cref="DbExpression"/>.
/// Compatibility requirements for <typeparamref name="TProjection"/> are described in remarks.
/// </param>
/// <typeparam name="TProjection">The method result type of <paramref name="projection"/>.</typeparam>
/// <returns>A new DbProjectExpression that represents the select operation.</returns>
/// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="projection"/> is null</exception>
/// <exception cref="ArgumentNullException">The result of <paramref name="projection"/> is null.</exception>
/// <remarks>
/// To be compatible with Select, <typeparamref name="TProjection"/> must be derived from <see cref="DbExpression"/>,
/// or must be an anonymous type with DbExpression-derived properties.
/// <para>
/// The following are examples of supported types for <typeparamref name="TProjection"/>:
/// <code>source.Select(x => x.Property("Name"))</code> (<typeparamref name="TProjection"/> is <see cref="DbPropertyExpression"/>).
/// <code>source.Select(x => new { Name = x.Property("Name") })</code> (<typeparamref name="TProjection"/> is an anonymous type with a DbExpression-derived property).
/// </para>
/// </remarks>
public static DbProjectExpression Select<TProjection>(this DbExpression source, Func<DbExpression, TProjection> projection)
{
EntityUtil.CheckArgumentNull(projection, "projection");
TProjection intermediateProjection;
DbExpressionBinding input = ConvertToBinding(source, projection, "projection", out intermediateProjection);
DbExpression projectionExp = ResolveToExpression(intermediateProjection);
return DbExpressionBuilder.Project(input, projectionExp);
}
/// <summary>
/// Creates a new <see cref="DbApplyExpression"/> that evaluates the given <paramref name="apply"/> expression once for each element of a given input set,
/// 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.
/// 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.
/// </summary>
/// <param name="source">
/// A <see cref="DbExpression"/> that specifies the input set.
/// </param>
/// <param name="apply">
/// A method that represents the logic to evaluate once for each member of the input set.
/// </param>
/// <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>
/// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="apply"/> is null.</exception>
/// <exception cref="ArgumentNullException">The expression produced by <paramref name="apply"/> is null.</exception>
/// <exception cref="ArgumentException"><paramref name="source"/> does not have a collection result type.</exception>
/// <exception cref="ArgumentException">The expression produced by <paramref name="apply"/> does not have a collection type.</exception>
public static DbProjectExpression SelectMany(this DbExpression source, Func<DbExpression, DbExpression> apply)
{
DbExpression functorResult;
DbExpressionBinding inputBinding = ConvertToBinding(source, apply, "apply", out functorResult);
DbExpressionBinding functorBinding = DbExpressionBuilder.Bind(functorResult);
DbApplyExpression intermediateApply = DbExpressionBuilder.CrossApply(inputBinding, functorBinding);
DbExpressionBinding projectionBinding = DbExpressionBuilder.Bind(intermediateApply);
return DbExpressionBuilder.Project(projectionBinding, DbExpressionBuilder.Property(projectionBinding.Variable, functorBinding.VariableName));
}
/// <summary>
/// Creates a new <see cref="DbApplyExpression"/> that evaluates the given <paramref name="apply"/> expression once for each element of a given input set,
/// 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.
/// A <see cref="DbProjectExpression"/> is then created that selects the specified <paramref name="selector"/> over each row, producing the overall collection of results.
/// </summary>
/// <typeparam name="TSelector">The method result type of <paramref name="selector"/>.</typeparam>
/// <param name="source">
/// A <see cref="DbExpression"/> that specifies the input set.
/// </param>
/// <param name="apply">
/// A method that represents the logic to evaluate once for each member of the input set.
/// </param>
/// <param name="selector">
/// A method that specifies how an element of the result set should be derived given an element of the input and apply sets.
/// This method must produce an instance of a type that is compatible with SelectMany and can be resolved into a <see cref="DbExpression"/>.
/// Compatibility requirements for <typeparamref name="TSelector"/> are described in remarks.
/// </param>
/// <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>
/// <exception cref="ArgumentNullException"><paramref name="source"/>, <paramref name="apply"/> or <paramref name="selector"/> is null.</exception>
/// <exception cref="ArgumentNullException">The expression produced by <paramref name="apply"/> is null.</exception>
/// <exception cref="ArgumentNullException">The result of <paramref name="selector"/> is null on conversion to DbExpression</exception>
/// <exception cref="ArgumentException"><paramref name="source"/> does not have a collection result type.</exception>
/// <exception cref="ArgumentException">The expression produced by <paramref name="apply"/> does not have a collection type.</exception>
/// <remarks>
/// To be compatible with SelectMany, <typeparamref name="TSelector"/> must be derived from <see cref="DbExpression"/>,
/// or must be an anonymous type with DbExpression-derived properties.
/// <para>
/// The following are examples of supported types for <typeparamref name="TSelector"/>:
/// <code>source.SelectMany(x => x.Property("RelatedCollection"), (source, apply) => apply.Property("Name"))</code> (<typeparamref name="TSelector"/> is <see cref="DbPropertyExpression"/>).
/// <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).
/// </para>
/// </remarks>
public static DbProjectExpression SelectMany<TSelector>(this DbExpression source, Func<DbExpression, DbExpression> apply, Func<DbExpression, DbExpression, TSelector> selector)
{
DbExpression functorResult;
DbExpressionBinding inputBinding = ConvertToBinding(source, apply, "apply", out functorResult);
EntityUtil.CheckArgumentNull(selector, "selector");
DbExpressionBinding functorBinding = DbExpressionBuilder.Bind(functorResult);
DbApplyExpression intermediateApply = DbExpressionBuilder.CrossApply(inputBinding, functorBinding);
DbExpressionBinding projectionBinding = DbExpressionBuilder.Bind(intermediateApply);
DbExpression left = DbExpressionBuilder.Property(projectionBinding.Variable, inputBinding.VariableName);
DbExpression right = DbExpressionBuilder.Property(projectionBinding.Variable, functorBinding.VariableName);
TSelector selectorResult = selector(left, right);
DbExpression projection = ResolveToExpression(selectorResult);
return DbExpressionBuilder.Project(projectionBinding, projection);
}
/// <summary>
/// Creates a new <see cref="DbSkipExpression"/> that skips the specified number of elements from the given sorted input set.
/// </summary>
/// <param name="argument">A <see cref="DbSortExpression"/> that specifies the sorted input set.</param>
/// <param name="count">An expression the specifies how many elements of the ordered set to skip.</param>
/// <returns>A new DbSkipExpression that represents the skip operation.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="argument"/> or <paramref name="count"/> is null.
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="count"/> is not <see cref="DbConstantExpression"/> or <see cref="DbParameterReferenceExpression"/> or has a
/// result type that is not equal or promotable to a 64-bit integer type.
/// </exception>
public static DbSkipExpression Skip(this DbSortExpression argument, DbExpression count)
{
EntityUtil.CheckArgumentNull(argument, "argument");
return DbExpressionBuilder.Skip(argument.Input, argument.SortOrder, count);
}
/// <summary>
/// Creates a new <see cref="DbLimitExpression"/> that restricts the number of elements in the Argument collection to the specified count Limit value.
/// Tied results are not included in the output.
/// </summary>
/// <param name="argument">An expression that specifies the input collection.</param>
/// <param name="count">An expression that specifies the limit value.</param>
/// <returns>A new DbLimitExpression with the specified argument and count limit values that does not include tied results.</returns>
/// <exception cref="ArgumentNullException"><paramref name="argument"/> or <paramref name="count"/> is null</exception>
/// <exception cref="ArgumentException">
/// <paramref name="argument"/> does not have a collection result type,
/// or <paramref name="count"/> does not have a result type that is equal or promotable to a 64-bit integer type.
/// </exception>
public static DbLimitExpression Take(this DbExpression argument, DbExpression count)
{
return DbExpressionBuilder.Limit(argument, count);
}
private static DbSortExpression CreateThenBy(DbSortExpression source, Func<DbExpression, DbExpression> sortKey, bool ascending, string collation, bool useCollation)
{
EntityUtil.CheckArgumentNull(source, "source");
EntityUtil.CheckArgumentNull(sortKey, "sortKey");
DbExpression sortKeyResult = sortKey(source.Input.Variable);
DbSortClause sortClause;
if (useCollation)
{
sortClause = (ascending ? DbExpressionBuilder.ToSortClause(sortKeyResult, collation) : DbExpressionBuilder.ToSortClauseDescending(sortKeyResult, collation));
}
else
{
sortClause = (ascending ? DbExpressionBuilder.ToSortClause(sortKeyResult) : DbExpressionBuilder.ToSortClauseDescending(sortKeyResult));
}
List<DbSortClause> newSortOrder = new List<DbSortClause>(source.SortOrder.Count + 1);
newSortOrder.AddRange(source.SortOrder);
newSortOrder.Add(sortClause);
return DbExpressionBuilder.Sort(source.Input, newSortOrder);
}
/// <summary>
/// Creates a new <see cref="DbSortExpression"/> that with a sort order that includes the sort order
/// of the given order input set together with the specified sort key in ascending sort order and
/// with default collation.
/// </summary>
/// <param name="source">A DbSortExpression that specifies the ordered input set.</param>
/// <param name="sortKey">
/// A method that specifies how to derive the additional sort key expression given a member of the
/// input set.
/// This method must produce an expression with an order-comparable result type that provides the
/// sort key definition.
/// </param>
/// <returns>A new DbSortExpression that represents the new overall order-by operation.</returns>
/// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="sortKey"/> is null.</exception>
/// <exception cref="ArgumentNullException">The expression produced by <paramref name="sortKey"/> is null.</exception>
/// <exception cref="ArgumentException"><paramref name="source"/> does not have a collection result type.</exception>
/// <exception cref="ArgumentException">
/// The expression produced by <paramref name="sortKey"/> does not have an order-comparable result type.
/// </exception>
public static DbSortExpression ThenBy(this DbSortExpression source, Func<DbExpression, DbExpression> sortKey)
{
return CreateThenBy(source, sortKey, true, null, false);
}
/// <summary>
/// Creates a new <see cref="DbSortExpression"/> that with a sort order that includes the sort order
/// of the given order input set together with the specified sort key in ascending sort order and
/// with the specified collation.
/// </summary>
/// <param name="source">A DbSortExpression that specifies the ordered input set.</param>
/// <param name="sortKey">
/// A method that specifies how to derive the additional sort key expression given a member of the
/// input set.
/// This method must produce an expression with an order-comparable result type that provides the
/// sort key definition.
/// </param>
/// <param name="collation">The collation to sort under</param>
/// <returns>A new DbSortExpression that represents the new overall order-by operation.</returns>
/// <exception cref="ArgumentNullException"><paramref name="source"/>, <paramref name="sortKey"/> or <paramref name="collation"/> is null.</exception>
/// <exception cref="ArgumentNullException">The expression produced by <paramref name="sortKey"/> is null.</exception>
/// <exception cref="ArgumentException"><paramref name="source"/> does not have a collection result type.</exception>
/// <exception cref="ArgumentException">
/// The expression produced by <paramref name="sortKey"/> does not have an order-comparable string result type.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="collation"/> is empty or contains only space characters</exception>
public static DbSortExpression ThenBy(this DbSortExpression source, Func<DbExpression, DbExpression> sortKey, string collation)
{
return CreateThenBy(source, sortKey, true, collation, true);
}
/// <summary>
/// Creates a new <see cref="DbSortExpression"/> that with a sort order that includes the sort order
/// of the given order input set together with the specified sort key in descending sort order and
/// with default collation.
/// </summary>
/// <param name="source">A DbSortExpression that specifies the ordered input set.</param>
/// <param name="sortKey">
/// A method that specifies how to derive the additional sort key expression given a member of the
/// input set.
/// This method must produce an expression with an order-comparable result type that provides the
/// sort key definition.
/// </param>
/// <returns>A new DbSortExpression that represents the new overall order-by operation.</returns>
/// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="sortKey"/> is null.</exception>
/// <exception cref="ArgumentNullException">The expression produced by <paramref name="sortKey"/> is null.</exception>
/// <exception cref="ArgumentException"><paramref name="source"/> does not have a collection result type.</exception>
/// <exception cref="ArgumentException">
/// The expression produced by <paramref name="sortKey"/> does not have an order-comparable result type.
/// </exception>
public static DbSortExpression ThenByDescending(this DbSortExpression source, Func<DbExpression, DbExpression> sortKey)
{
return CreateThenBy(source, sortKey, false, null, false);
}
/// <summary>
/// Creates a new <see cref="DbSortExpression"/> that with a sort order that includes the sort order
/// of the given order input set together with the specified sort key in descending sort order and
/// with the specified collation.
/// </summary>
/// <param name="source">A DbSortExpression that specifies the ordered input set.</param>
/// <param name="sortKey">
/// A method that specifies how to derive the additional sort key expression given a member of the
/// input set.
/// This method must produce an expression with an order-comparable result type that provides the
/// sort key definition.
/// </param>
/// <param name="collation">The collation to sort under</param>
/// <returns>A new DbSortExpression that represents the new overall order-by operation.</returns>
/// <exception cref="ArgumentNullException"><paramref name="source"/>, <paramref name="sortKey"/> or <paramref name="collation"/> is null.</exception>
/// <exception cref="ArgumentNullException">The expression produced by <paramref name="sortKey"/> is null.</exception>
/// <exception cref="ArgumentException"><paramref name="source"/> does not have a collection result type.</exception>
/// <exception cref="ArgumentException">
/// The expression produced by <paramref name="sortKey"/> does not have an order-comparable string result type.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="collation"/> is empty or contains only space characters</exception>
public static DbSortExpression ThenByDescending(this DbSortExpression source, Func<DbExpression, DbExpression> sortKey, string collation)
{
return CreateThenBy(source, sortKey, false, collation, true);
}
/// <summary>
/// Creates a new <see cref="DbFilterExpression"/> that filters the elements in the given input set using the specified predicate.
/// </summary>
/// <param name="source">
/// An expression that specifies the input set.
/// </param>
/// <param name="predicate">
/// A method representing the predicate to evaluate for each member of the input set.
/// This method must produce an expression with a Boolean result type that provides
/// the predicate logic.
/// </param>
/// <returns>A new DbQuantifierExpression that represents the Any operation.</returns>
/// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="predicate"/> is null</exception>
/// <exception cref="ArgumentNullException">The expression produced by <paramref name="predicate"/> is null</exception>
/// <exception cref="ArgumentException">
/// The expression produced by <paramref name="predicate"/> does not have a Boolean result type.
/// </exception>
public static DbFilterExpression Where(this DbExpression source, Func<DbExpression, DbExpression> predicate)
{
DbExpression predicateExp;
DbExpressionBinding input = ConvertToBinding(source, predicate, "predicate", out predicateExp);
return DbExpressionBuilder.Filter(input, predicateExp);
}
/// <summary>
/// Creates a new <see cref="DbExpression"/> that computes the union of the left and right set arguments with duplicates removed.
/// </summary>
/// <param name="left">An expression that defines the left set argument.</param>
/// <param name="right">An expression that defines the right set argument.</param>
/// <returns>A new DbExpression that computes the union, without duplicates, of the the left and right arguments.</returns>
/// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null</exception>
/// <exception cref="ArgumentException">No common collection result type with an equality-comparable element type exists between <paramref name="left"/> and <paramref name="right"/>.</exception>
public static DbExpression Union(this DbExpression left, DbExpression right)
{
return DbExpressionBuilder.Distinct(DbExpressionBuilder.UnionAll(left, right));
}
#endregion
#region Internal Helper API - ideally these methods should be removed
internal static AliasGenerator AliasGenerator
{
get { return _bindingAliases; }
}
internal static DbNullExpression CreatePrimitiveNullExpression(PrimitiveTypeKind primitiveType)
{
switch(primitiveType)
{
case PrimitiveTypeKind.Binary:
return _binaryNull;
case PrimitiveTypeKind.Boolean:
return _boolNull;
case PrimitiveTypeKind.Byte:
return _byteNull;
case PrimitiveTypeKind.DateTime:
return _dateTimeNull;
case PrimitiveTypeKind.DateTimeOffset:
return _dateTimeOffsetNull;
case PrimitiveTypeKind.Decimal:
return _decimalNull;
case PrimitiveTypeKind.Double:
return _doubleNull;
case PrimitiveTypeKind.Geography:
return _geographyNull;
case PrimitiveTypeKind.Geometry:
return _geometryNull;
case PrimitiveTypeKind.Guid:
return _guidNull;
case PrimitiveTypeKind.Int16:
return _int16Null;
case PrimitiveTypeKind.Int32:
return _int32Null;
case PrimitiveTypeKind.Int64:
return _int64Null;
case PrimitiveTypeKind.SByte:
return _sbyteNull;
case PrimitiveTypeKind.Single:
return _singleNull;
case PrimitiveTypeKind.String:
return _stringNull;
case PrimitiveTypeKind.Time:
return _timeNull;
default:
throw EntityUtil.InvalidEnumerationValue(typeof(PrimitiveTypeKind), (int)primitiveType);
}
}
internal static DbApplyExpression CreateApplyExpressionByKind(DbExpressionKind applyKind, DbExpressionBinding input, DbExpressionBinding apply)
{
Debug.Assert(DbExpressionKind.CrossApply == applyKind || DbExpressionKind.OuterApply == applyKind, "Invalid ApplyType");
switch (applyKind)
{
case DbExpressionKind.CrossApply:
return CrossApply(input, apply);
case DbExpressionKind.OuterApply:
return OuterApply(input, apply);
default:
throw EntityUtil.InvalidEnumerationValue(typeof(DbExpressionKind), (int)applyKind);
}
}
internal static DbExpression CreateJoinExpressionByKind(DbExpressionKind joinKind, DbExpression joinCondition, DbExpressionBinding input1, DbExpressionBinding input2)
{
Debug.Assert(DbExpressionKind.CrossJoin == joinKind ||
DbExpressionKind.FullOuterJoin == joinKind ||
DbExpressionKind.InnerJoin == joinKind ||
DbExpressionKind.LeftOuterJoin == joinKind,
"Invalid DbExpressionKind for CreateJoinExpressionByKind");
if (DbExpressionKind.CrossJoin == joinKind)
{
Debug.Assert(null == joinCondition, "Condition should not be specified for CrossJoin");
return CrossJoin(new DbExpressionBinding[2] { input1, input2 });
}
else
{
Debug.Assert(joinCondition != null, "Condition must be specified for non-CrossJoin");
switch (joinKind)
{
case DbExpressionKind.InnerJoin:
return InnerJoin(input1, input2, joinCondition);
case DbExpressionKind.LeftOuterJoin:
return LeftOuterJoin(input1, input2, joinCondition);
case DbExpressionKind.FullOuterJoin:
return FullOuterJoin(input1, input2, joinCondition);
default:
throw EntityUtil.InvalidEnumerationValue(typeof(DbExpressionKind), (int)joinKind);
}
}
}
/// <summary>
/// Used only by span rewriter, when a row could be specified as an argument
/// </summary>
internal static DbIsNullExpression CreateIsNullExpressionAllowingRowTypeArgument(DbExpression argument)
{
TypeUsage resultType = ArgumentValidation.ValidateIsNull(argument, true);
return new DbIsNullExpression(resultType, argument, true);
}
/// <summary>
/// Creates a new <see cref="DbElementExpression"/> that converts a single-member set with a single property
/// into a singleton. The result type of the created <see cref="DbElementExpression"/> equals the result type
/// of the single property of the element of the argument.
///
/// This method should only be used when the argument is of a collection type with
/// element of structured type with only one property.
/// </summary>
/// <param name="argument">An expression that specifies the input set.</param>
/// <returns>A DbElementExpression that represents the conversion of the single-member set argument to a singleton.</returns>
/// <exception cref="ArgumentNullException"><paramref name="argument"/> is null</exception>
/// <exception cref="ArgumentException">
/// <paramref name="argument"/> is associated with a different command tree,
/// or does not have a collection result type, or its element type is not a structured type
/// with only one property
/// </exception>
internal static DbElementExpression CreateElementExpressionUnwrapSingleProperty(DbExpression argument)
{
TypeUsage resultType = ArgumentValidation.ValidateElement(argument);
// Change the result type of the element expression to the type of the
// single property of the element of its operand.
IList<EdmProperty> properties = TypeHelpers.GetProperties(resultType);
if (properties == null || properties.Count != 1)
{
throw EntityUtil.Argument(System.Data.Entity.Strings.Cqt_Element_InvalidArgumentForUnwrapSingleProperty, "arg");
}
resultType = properties[0].TypeUsage;
return new DbElementExpression(resultType, argument, true);
}
/// <summary>
/// Creates a new <see cref="DbRelatedEntityRef"/> that describes how to satisfy the relationship
/// navigation operation from <paramref name="sourceEnd"/> to <paramref name="targetEnd"/>, which
/// must be declared by the same relationship type.
/// DbRelatedEntityRefs are used in conjuction with <see cref="DbNewInstanceExpression"/>
/// to construct Entity instances that are capable of resolving relationship navigation operations based on
/// the provided DbRelatedEntityRefs without the need for additional navigation operations.
/// Note also that this factory method is not intended to be part of the public Command Tree API
/// since its intent is to support Entity constructors in view definitions that express information about
/// related Entities using the 'WITH RELATIONSHIP' clause in eSQL.
/// </summary>
/// <param name="sourceEnd">The relationship end from which navigation takes place</param>
///<param name="targetEnd">The relationship end to which navigation may be satisifed using the target entity ref</param>
///<param name="targetEntity">An expression that produces a reference to the target entity (and must therefore have a Ref result type)</param>
internal static DbRelatedEntityRef CreateRelatedEntityRef(RelationshipEndMember sourceEnd, RelationshipEndMember targetEnd, DbExpression targetEntity)
{
return new DbRelatedEntityRef(sourceEnd, targetEnd, targetEntity);
}
/// <summary>
/// Creates a new <see cref="DbNewInstanceExpression"/> that constructs an instance of an Entity type
/// together with the specified information about Entities related to the newly constructed Entity by
/// relationship navigations where the target end has multiplicity of at most one.
/// Note that this factory method is not intended to be part of the public Command Tree API since its
/// intent is to support Entity constructors in view definitions that express information about
/// related Entities using the 'WITH RELATIONSHIP' clause in eSQL.
/// </summary>
/// <param name="instanceType">The type of the Entity instance that is being constructed</param>
/// <param name="attributeValues">Values for each (non-relationship) property of the Entity</param>
/// <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>
/// <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>
internal static DbNewInstanceExpression CreateNewEntityWithRelationshipsExpression(EntityType entityType, IList<DbExpression> attributeValues, IList<DbRelatedEntityRef> relationships)
{
DbExpressionList validAttributes;
System.Collections.ObjectModel.ReadOnlyCollection<DbRelatedEntityRef> validRelatedRefs;
TypeUsage resultType = ArgumentValidation.ValidateNewEntityWithRelationships(entityType, attributeValues, relationships, out validAttributes, out validRelatedRefs);
return new DbNewInstanceExpression(resultType, validAttributes, validRelatedRefs);
}
/// <summary>
/// Same as <see cref="Navigate(DbExpression, RelationshipEndMember, RelationshipEndMember)"/> only allows the property type of <paramref name="fromEnd"/>
/// to be any type in the same type hierarchy as the result type of <paramref name="navigateFrom"/>.
/// Only used by relationship span.
/// </summary>
/// <param name="navigateFrom"></param>
/// <param name="fromEnd"></param>
/// <param name="toEnd"></param>
/// <returns></returns>
internal static DbRelationshipNavigationExpression NavigateAllowingAllRelationshipsInSameTypeHierarchy(this DbExpression navigateFrom, RelationshipEndMember fromEnd, RelationshipEndMember toEnd)
{
RelationshipType relType;
TypeUsage resultType = ArgumentValidation.ValidateNavigate(navigateFrom, fromEnd, toEnd, out relType, allowAllRelationshipsInSameTypeHierarchy: true);
return new DbRelationshipNavigationExpression(resultType, relType, fromEnd, toEnd, navigateFrom);
}
internal static DbPropertyExpression CreatePropertyExpressionFromMember(DbExpression instance, EdmMember member)
{
return PropertyFromMember(instance, member, "member");
}
#if ENABLE_NESTAGGREGATE
/// <summary>
/// Creates a new <see cref="NestAggregate"/> over the specified argument
/// </summary>
/// <param name="argument">The argument over which to perform the nest operation</param>
/// <returns>A new nest aggregate with a reference to the given argument.</returns>
/// <exception cref="ArgumentNullException"><paramref name="argument"/> is null</exception>
/// <exception cref="ArgumentException"><paramref name="argument"/> is associated with a different command tree</exception>
/*CQT_PUBLIC_API(*/internal/*)*/ NestAggregate CreateNestAggregate(Expression argument)
{
return new NestAggregate(this, argument);
}
#endif
#if METHOD_EXPRESSION
/// <summary>
/// Creates a new <see cref="MethodExpression"/> representing the invocation of the specified method on the given instance with the given arguments.
/// </summary>
/// <param name="methodInfo">The metadata for the method to invoke.</param>
/// <param name="instance">The invocation target.</param>
/// <param name="args">The arguments to the method.</param>
/// <returns>A new MethodExpression that represents the method invocation.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="methodInfo"/> or <paramref name="instance"/> is null,
/// or <paramref name="args"/> is null or contains null
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="methodInfo"/> is not associated with this command tree's metadata workspace,
/// <paramref name="instance"/> is associated with a different command tree
/// or has a result type that is not equal or promotable to the declaring type of the method,
/// or <paramref name="args"/> contains an incorrect number of expressions,
/// an expression with a result type that is not equal or promotable to the type of the corresponding
/// method parameter, or an expression that is associated with a different command tree.
/// </exception>
/*CQT_PUBLIC_API(*/internal/*)*/ MethodExpression CreateInstanceMethodExpression(MethodMetadata methodInfo, Expression instance, IList<Expression> args)
{
if (methodInfo != null && methodInfo.IsStatic)
{
throw EntityUtil.Argument(System.Data.Entity.Strings.Cqt_Factory_InstanceMethodRequired, "methodInfo");
}
return new MethodExpression(this, methodInfo, args, instance);
}
/// <summary>
/// Creates a new <see cref="MethodExpression"/> representing the invocation of the specified method with the given arguments.
/// </summary>
/// <param name="methodInfo">The metadata for the method to invoke.</param>
/// <param name="args">The arguments to the method.</param>
/// <returns>A new MethodExpression that represents the method invocation.</returns>
/// <exception cref="ArgumentNullException"><paramref name="methodInfo"/> is null, or <paramref name="args"/> is null or contains null</exception>
/// <exception cref="ArgumentException">
/// <paramref name="methodInfo"/> is not associated with this command tree's metadata workspace,
/// or <paramref name="args"/> contains an incorrect number of expressions,
/// an expression with a result type that is not equal or promotable to the type of the corresponding
/// method parameter, or an expression that is associated with a different command tree.
/// </exception>
/*CQT_PUBLIC_API(*/internal/*)*/ MethodExpression CreateStaticMethodExpression(MethodMetadata methodInfo, IList<Expression> args)
{
if (methodInfo != null && !methodInfo.IsStatic)
{
throw EntityUtil.Argument(System.Data.Entity.Strings.Cqt_Factory_StaticMethodRequired, "methodInfo");
}
return new MethodExpression(this, methodInfo, args, null);
}
#endif
#endregion
}
}
|