예제 #1
0
        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);
        }