public virtual void BuildSelect(Expression selectExpression, TranslationContext context, Type expectedResultType = null) { // collect columns, split Expression in // - things we will do in CLR // - things we will do in SQL expectedResultType = expectedResultType ?? selectExpression.Type; LambdaExpression recordReaderExpr; var dataRecordParameter = Expression.Parameter(typeof(IDataRecord), "dataRecord"); var sessionParameter = Expression.Parameter(typeof(EntitySession), "session"); // if we have a GroupByExpression, the result type is not the same: // - we need to read what is going to be the Key expression // - the final row generator builds a IGrouping<K,T> instead of T var selectGroupExpression = selectExpression as GroupExpression; if (selectGroupExpression != null) { var sqlOutExpr = CutOutSqlTierLambda(selectGroupExpression.GroupedExpression, dataRecordParameter, sessionParameter, null, context); var selectKeyExpr = CutOutSqlTierLambda(selectGroupExpression.KeyExpression, dataRecordParameter, sessionParameter, null, context); recordReaderExpr = sqlOutExpr; if (selectGroupExpression.UseClrGrouping) { recordReaderExpr = BuildGroupByPairsReader(sqlOutExpr, selectKeyExpr, dataRecordParameter, sessionParameter, context); var grouper = QueryResultsProcessor.CreateGroupBy(selectKeyExpr.Body.Type, sqlOutExpr.Body.Type); context.CurrentSelect.ResultsProcessor = grouper; context.CurrentSelect.Group.Remove(selectGroupExpression); } } else { recordReaderExpr = CutOutSqlTierLambda(selectExpression, dataRecordParameter, sessionParameter, expectedResultType, context); } context.CurrentSelect.Reader = recordReaderExpr; }
private TranslatedLinqCommand TranslateSelect(LinqCommand command) { LinqCommandPreprocessor.PreprocessCommand(_dbModel.EntityApp.Model, command); var context = new TranslationContext(_dbModel, command); var cmdInfo = command.Info; // convert lambda params into an initial set of ExternalValueExpression objects; foreach (var prm in cmdInfo.Lambda.Parameters) { var inpParam = new ExternalValueExpression(prm); context.ExternalValues.Add(inpParam); } //Analyze/transform query expression var exprChain = ExpressionChain.Build(cmdInfo.Lambda.Body); var selectExpr = BuildSelectExpression(exprChain, context); // Analyze external values (parameters?), create DbParameters var commandParams = BuildParameters(command, context); // If there's at least one parameter that must be converted to literal (ex: value list), we cannot cache the query bool canCache = !context.ExternalValues.Any(v => v.SqlUse == ExternalValueSqlUse.Literal); if (!canCache) { command.Info.Flags |= LinqCommandFlags.NoQueryCache; } //Build SQL, compile object materializer var sqlBuilder = new SqlBuilder(_dbModel); var sqlStatement = sqlBuilder.BuildSelect(selectExpr); // Parameters are represented as {2}, {3}, etc. // Braces in string literals are escaped and are represented as '{0}' and '{1}' var sqlTemplate = sqlStatement.ToString(); var sql = FormatSql(sqlTemplate, commandParams); var objMaterializer = CompileObjectMaterializer(context); var outType = context.CurrentSelect.Reader.Body.Type; var resultListCreator = ReflectionHelper.GetCompiledGenericListCreator(outType); //check if we need to create implicit result set processor if (selectExpr.ResultsProcessor == null) { var returnsResultSet = typeof(IQueryable).IsAssignableFrom(cmdInfo.Lambda.Body.Type); if (!returnsResultSet) { selectExpr.ResultsProcessor = QueryResultsProcessor.CreateFirstSingleLast("First", outType); } } var sqlQuery = new TranslatedLinqCommand(sqlTemplate, sql, commandParams, command.Info.Flags, objMaterializer, selectExpr.ResultsProcessor, resultListCreator); return(sqlQuery); }