private DbExpression RewriteRow(DbExpression expression, RowType rowType) { DbLambdaExpression lambdaExpression = expression as DbLambdaExpression; DbNewInstanceExpression newRow; if (lambdaExpression != null) { // NOTE: We rely on the fact that today span cannot be done over queries containing DbLambdaExpressions // created by users, because user-created expressions cannot be used for querying in O-space. // If that were to change, pushing span beyond a LambdaExpression could cause variable name // collisions between the variable names used in the Lambda and the names generated by the // RelationshipNavigationVisitor. newRow = lambdaExpression.Lambda.Body as DbNewInstanceExpression; } else { newRow = expression as DbNewInstanceExpression; } Dictionary <int, DbExpression> unmodifiedColumns = null; Dictionary <int, DbExpression> spannedColumns = null; for (int idx = 0; idx < rowType.Properties.Count; idx++) { // Retrieve the property that represents the current column EdmProperty columnProp = rowType.Properties[idx]; // Construct an expression that defines the current column. DbExpression columnExpr = null; if (newRow != null) { // For a row-constructing NewInstance expression, the corresponding argument can simply be used columnExpr = newRow.Arguments[idx]; } else { // For all other expressions the property corresponding to the column name must be retrieved // from the row-typed expression columnExpr = expression.Property(columnProp.Name); } DbExpression spannedColumn = this.Rewrite(columnExpr); if (!object.ReferenceEquals(spannedColumn, columnExpr)) { // If so, then update the dictionary of column index to span information if (null == spannedColumns) { spannedColumns = new Dictionary <int, DbExpression>(); } spannedColumns[idx] = spannedColumn; } else { // Otherwise, update the dictionary of column index to unmodified expression if (null == unmodifiedColumns) { unmodifiedColumns = new Dictionary <int, DbExpression>(); } unmodifiedColumns[idx] = columnExpr; } } // A new expression need only be built if at least one column was spanned if (null == spannedColumns) { // No columns were spanned, indicate that the original expression should remain. return(expression); } else { // At least one column was spanned, so build a new row constructor that defines the new row, including spanned columns. List <DbExpression> columnArguments = new List <DbExpression>(rowType.Properties.Count); List <EdmProperty> properties = new List <EdmProperty>(rowType.Properties.Count); for (int idx = 0; idx < rowType.Properties.Count; idx++) { EdmProperty columnProp = rowType.Properties[idx]; DbExpression columnDef = null; if (!spannedColumns.TryGetValue(idx, out columnDef)) { columnDef = unmodifiedColumns[idx]; } columnArguments.Add(columnDef); properties.Add(new EdmProperty(columnProp.Name, columnDef.ResultType)); } // Copy over any eLinq initializer metadata (if present, or null if not). // Note that this initializer metadata does not strictly match the new row type // that includes spanned columns, but will be correct once the object materializer // has interpreted the query results to produce the correct value for each colum. RowType rewrittenRow = new RowType(properties, rowType.InitializerMetadata); TypeUsage rewrittenRowTypeUsage = TypeUsage.Create(rewrittenRow); DbExpression rewritten = rewrittenRowTypeUsage.New(columnArguments); // SQLBUDT #554182: If we insert a new projection we should should make sure to // not interfere with the nullability of the input. // In particular, if the input row is null and we construct a new row as a projection over its columns // we would get a row consisting of nulls, instead of a null row. // Thus, given an input X, we rewritte it as: if (X is null) then NULL else rewritten. if (newRow == null) { DbExpression condition = DbExpressionBuilder.CreateIsNullExpressionAllowingRowTypeArgument(expression); DbExpression nullExpression = DbExpressionBuilder.Null(rewrittenRowTypeUsage); rewritten = DbExpressionBuilder.Case( new List <DbExpression>(new DbExpression[] { condition }), new List <DbExpression>(new DbExpression[] { nullExpression }), rewritten); } // Add an entry to the spanned row type => original row type map for the new row type. AddSpannedRowType(rewrittenRow, expression.ResultType); if (lambdaExpression != null && newRow != null) { rewritten = DbLambda.Create(rewritten, lambdaExpression.Lambda.Variables).Invoke(lambdaExpression.Arguments); } return(rewritten); } }
private DbExpression RewriteRow(DbExpression expression, RowType rowType) { DbLambdaExpression lambdaExpression = expression as DbLambdaExpression; DbNewInstanceExpression instanceExpression = lambdaExpression == null ? expression as DbNewInstanceExpression : lambdaExpression.Lambda.Body as DbNewInstanceExpression; Dictionary <int, DbExpression> dictionary1 = (Dictionary <int, DbExpression>)null; Dictionary <int, DbExpression> dictionary2 = (Dictionary <int, DbExpression>)null; for (int index = 0; index < rowType.Properties.Count; ++index) { EdmProperty property = rowType.Properties[index]; DbExpression expression1 = instanceExpression == null ? (DbExpression)expression.Property(property.Name) : instanceExpression.Arguments[index]; DbExpression dbExpression = this.Rewrite(expression1); if (!object.ReferenceEquals((object)dbExpression, (object)expression1)) { if (dictionary2 == null) { dictionary2 = new Dictionary <int, DbExpression>(); } dictionary2[index] = dbExpression; } else { if (dictionary1 == null) { dictionary1 = new Dictionary <int, DbExpression>(); } dictionary1[index] = expression1; } } if (dictionary2 == null) { return(expression); } List <DbExpression> dbExpressionList = new List <DbExpression>(rowType.Properties.Count); List <EdmProperty> edmPropertyList = new List <EdmProperty>(rowType.Properties.Count); for (int key = 0; key < rowType.Properties.Count; ++key) { EdmProperty property = rowType.Properties[key]; DbExpression dbExpression = (DbExpression)null; if (!dictionary2.TryGetValue(key, out dbExpression)) { dbExpression = dictionary1[key]; } dbExpressionList.Add(dbExpression); edmPropertyList.Add(new EdmProperty(property.Name, dbExpression.ResultType)); } RowType spannedType = new RowType((IEnumerable <EdmProperty>)edmPropertyList, rowType.InitializerMetadata); TypeUsage typeUsage = TypeUsage.Create((EdmType)spannedType); DbExpression dbExpression1 = (DbExpression)typeUsage.New((IEnumerable <DbExpression>)dbExpressionList); if (instanceExpression == null) { dbExpression1 = (DbExpression)DbExpressionBuilder.Case((IEnumerable <DbExpression>) new List <DbExpression>((IEnumerable <DbExpression>) new DbExpression[1] { (DbExpression)expression.IsNull() }), (IEnumerable <DbExpression>) new List <DbExpression>((IEnumerable <DbExpression>) new DbExpression[1] { (DbExpression)typeUsage.Null() }), dbExpression1); } this.AddSpannedRowType(spannedType, expression.ResultType); if (lambdaExpression != null && instanceExpression != null) { dbExpression1 = (DbExpression)DbLambda.Create(dbExpression1, (IEnumerable <DbVariableReferenceExpression>)lambdaExpression.Lambda.Variables).Invoke((IEnumerable <DbExpression>)lambdaExpression.Arguments); } return(dbExpression1); }