public static void PreprocessCommand(EntityModel model, LinqCommand command) { if (command.Info.Lambda != null) return; var preProc = new LinqCommandPreprocessor(); preProc.Preprocess(model, command); }
public LinqTranslationException(string message, LinqCommand command, Exception inner = null) : base(message, inner) { Command = command; if (Command != null) this.Data["LinqCommand"] = Command.ToString(); }
public NonQueryLinqCommandData(LinqCommand baseLinqCommand, SelectExpression baseSelect, TableExpression targetTable, bool isSingleTable) { BaseLinqCommand = baseLinqCommand; BaseSelect = baseSelect; TargetTable = targetTable; IsSingleTableCommand = isSingleTable; }
public static void RunIncludeQueries(IEntitySession session, LinqCommand command, object mainQueryResult) { // initial checks if there's anything to run var resultShape = command.Info.ResultShape; if (mainQueryResult == null || resultShape == QueryResultShape.Object) return; var allIncludes = session.Context.GetMergedIncludes(command.Info.Includes); if (allIncludes.Count == 0) return; // Get records from query result var records = new List<EntityRecord>(); switch (resultShape) { case QueryResultShape.Entity: records.Add(EntityHelper.GetRecord(mainQueryResult)); break; case QueryResultShape.EntityList: var list = mainQueryResult as IList; if (list.Count == 0) return; foreach (var ent in list) records.Add(EntityHelper.GetRecord(ent)); break; }//switch; // actually run the includes var entityType = records[0].EntityInfo.EntityType; var helper = new IncludeQueryHelper(session, allIncludes); helper.RunIncludeQueries(entityType, records); }
public TranslatedLinqCommand Translate(LinqCommand command) { if (command.Info == null) LinqCommandAnalyzer.Analyze(_dbModel.EntityApp.Model, command); try { switch(command.CommandType) { case LinqCommandType.Select: return TranslateSelect(command); case LinqCommandType.Update: case LinqCommandType.Delete: case LinqCommandType.Insert: return TranslateNonQuery(command); default: ThrowTranslationFailed(command, "Unsupported LINQ command type."); return null; } } catch(LinqTranslationException) { throw; // if it is alread Linq translation exception, pass it up. } catch (Exception ex) { var message = "Linq to SQL translation failed: " + ex.Message + "\r\nPossibly facilities you are trying to use are not supported. " + "\r\nTry to reformulate/simplify the query. Hint: do not use c# functions/methods inside query directly. "; throw new LinqTranslationException(message, command, ex); } }
private object ExecuteLinqNonQuery(LinqCommand linqCommand, EntitySession session, DataConnection connection) { var translCmd = GetTranslateLinqCommand(linqCommand); var dbCommand = CreateLinqDbCommand(connection, linqCommand, translCmd); var result = ExecuteDbCommand(dbCommand, connection, DbExecutionType.NonQuery); return result; }
public static void PreprocessCommand(EntityModel model, LinqCommand command) { if (command.Info.Lambda != null) { return; } var preProc = new LinqCommandPreprocessor(); preProc.Preprocess(model, command); }
public TranslationContext(TranslationContext source) { this.DbModel = source.DbModel; this.Command = source.Command; this.CallStack = source.CallStack; this.ExternalValues = source.ExternalValues; this.MetaTables = source.MetaTables; this.SelectExpressions = source.SelectExpressions; this.LambdaParameters = source.LambdaParameters; this._currentScopeIndex = source._currentScopeIndex; }
public TranslationContext(DbModel dbModel, LinqCommand command) { DbModel = dbModel; Command = command; CallStack = new Stack<MethodInfo>(); SelectExpressions = new List<SelectExpression>(); _currentScopeIndex = SelectExpressions.Count; SelectExpressions.Add(new SelectExpression()); ExternalValues = new List<ExternalValueExpression>(); MetaTables = new List<MetaTableExpression>(); LambdaParameters = new Dictionary<string, Expression>(); }
public static LinqCommandInfo Analyze(EntityModel model, LinqCommand command) { // if the query was already analyzed, return the old object; otherwise analyze and save in query's field if (command.Info != null) { return(command.Info); } var analyzer = new LinqCommandAnalyzer(); command.Info = analyzer.AnalyzeCommand(model, command); return(command.Info); }
object IQueryProvider.Execute(Expression expression) { // if session is null, it means that query is not executable - it should be used only to DEFINE a query and translate it to SQL // but not execute it. Example: DbView definition Util.Check(Session != null, "The query is not executable. Query: {0}", expression); var elemType = expression.Type.IsGenericType ? expression.Type.GenericTypeArguments[0] : typeof(object); var query = new EntityQuery(this, elemType, expression); var command = new LinqCommand(query, LinqCommandType.Select, LinqCommandKind.DynamicSql, null); var result = Session.ExecuteLinqCommand(command); return(result); }
public LinqCommandInfo(LinqCommand command, QueryOptions options, LinqCommandFlags flags, List <Type> entityTypes, string cacheKey, List <ParameterExpression> externalParameters, List <LambdaExpression> includes) { CommandType = command.CommandType; CommandKind = command.Kind; Options = options; Flags = flags; EntityTypes = entityTypes; CacheKey = cacheKey; ExternalParameters = externalParameters; Includes = includes; }
public LinqCommandInfo(LinqCommand command, QueryOptions options, LinqCommandFlags flags, List<Type> entityTypes, string cacheKey, List<ParameterExpression> externalParameters, List<LambdaExpression> includes) { CommandType = command.CommandType; CommandKind = command.Kind; Options = options; Flags = flags; EntityTypes = entityTypes; CacheKey = cacheKey; ExternalParameters = externalParameters; Includes = includes; }
private IDbCommand CreateLinqDbCommand(DataConnection connection, LinqCommand linqCommand, TranslatedLinqCommand translatedCommand) { var cmd = connection.DbConnection.CreateCommand(); cmd.CommandType = CommandType.Text; cmd.CommandText = translatedCommand.Sql; foreach (var qParam in translatedCommand.Parameters) { var value = qParam.ReadValue(linqCommand.ParameterValues) ?? DBNull.Value; var dbParam = cmd.CreateParameter(); //DbModel.Driver.AddParameter(cmd, // dbParam.ParameterName = qParam.Name; //Value and parameter may need some tweaking, depending on server type DbModel.LinqSqlProvider.SetDbParameterValue(dbParam, value); cmd.Parameters.Add(dbParam); } return cmd; }
public object ExecuteLinqCommand(EntitySession session, LinqCommand command) { var conn = GetLinqCommandConnection(session, command.Info.Flags); try { object result = command.CommandType == LinqCommandType.Select ? ExecuteLinqSelect(command, session, conn) : ExecuteLinqNonQuery(command, session, conn); ReleaseConnection(conn); return result; } catch (Exception dex) { ReleaseConnection(conn, inError: true); dex.AddValue(DataAccessException.KeyLinqQuery, command.QueryExpression); throw; } }
private void Preprocess(EntityModel model, LinqCommand command) { _model = model; _command = command; _parameters = new List <ParameterExpression>(); //create parameters for (int i = 0; i < _command.Locals.Count; i++) { var prmExpr = _command.Locals[i]; var prm = prmExpr.NodeType == ExpressionType.Parameter ? (ParameterExpression)prmExpr : Expression.Parameter(prmExpr.Type, "@P" + i); _parameters.Add(prm); } var body = this.Visit(_command.Query.Expression); _command.Info.Lambda = Expression.Lambda(body, _parameters); }
public object ExecuteLinqCommand(EntitySession session, LinqCommand command) { object result; if(command.CommandType == LinqCommandType.Select && Cache != null && Cache.TryExecuteLinqQuery(session, command, out result)) return result; result = Database.ExecuteLinqCommand(session, command); //If we are returning entities, cache them if(command.CommandType == LinqCommandType.Select) { var recs = result as IList<EntityRecord>; if(Cache != null && recs != null) Cache.CacheRecords(recs); //adds to sparse cache } else { // Update/Insert/Delete statemetns if (Cache != null && command.TargetEntity.CacheType != CacheType.None) Cache.Invalidate(); } return result; }
public static void RunIncludeQueries(IEntitySession session, LinqCommand command, object mainQueryResult) { // initial checks if there's anything to run var resultShape = command.Info.ResultShape; if (mainQueryResult == null || resultShape == QueryResultShape.Object) { return; } var allIncludes = session.Context.GetMergedIncludes(command.Info.Includes); if (allIncludes.Count == 0) { return; } // Get records from query result var records = new List <EntityRecord>(); switch (resultShape) { case QueryResultShape.Entity: records.Add(EntityHelper.GetRecord(mainQueryResult)); break; case QueryResultShape.EntityList: var list = mainQueryResult as IList; if (list.Count == 0) { return; } foreach (var ent in list) { records.Add(EntityHelper.GetRecord(ent)); } break; }//switch; // actually run the includes var entityType = records[0].EntityInfo.EntityType; var helper = new IncludeQueryHelper(session, allIncludes); helper.RunIncludeQueries(entityType, records); }
private LinqCommandInfo AnalyzeCommand(EntityModel model, LinqCommand command) { _model = model; _command = command; try { //include command type and options value into cache key AddCacheKey(command.CommandType); AnalyzeNode(_command.Query.Expression); _command.Locals = _locals; AddCacheKey(_options); var cacheKey = _cacheKeyBuilder.ToString(); //Build command info var info = new LinqCommandInfo(command, _options, _flags, _entityTypes, cacheKey, _externalParams, _includes); info.ResultShape = GetResultShape(_command.Query.Expression.Type); return(info); } catch (Exception ex) { ex.Data["QueryExperssion"] = command.Query.Expression + string.Empty; throw; } }
public object ExecuteLinqSelect(LinqCommand linqCommand, EntitySession session, DataConnection conn) { var translCmd = GetTranslateLinqCommand(linqCommand); //Locks require ongoing transaction object result; var dbCommand = CreateLinqDbCommand(conn, linqCommand, translCmd); IList resultList = translCmd.ResultListCreator(); ExecuteDbCommand(dbCommand, conn, DbExecutionType.Reader, reader => { while(reader.Read()) { var row = translCmd.ObjectMaterializer(reader, session); //row might be null if authorization filtered it out or if it is empty value set from outer join if(row != null) resultList.Add(row); } return resultList.Count; }); //Post processor is extra selection op from the query (Fist,Single,Last) var postProcessor = translCmd.ResultsPostProcessor; if (postProcessor != null) result = postProcessor.ProcessRows(resultList); else result = resultList; return result; }
private void Preprocess(EntityModel model, LinqCommand command) { _model = model; _command = command; _parameters = new List<ParameterExpression>(); //create parameters for (int i = 0; i < _command.Locals.Count; i++) { var prmExpr = _command.Locals[i]; var prm = prmExpr.NodeType == ExpressionType.Parameter ? (ParameterExpression)prmExpr : Expression.Parameter(prmExpr.Type, "@P" + i); _parameters.Add(prm); } var body = this.Visit(_command.Query.Expression); _command.Info.Lambda = Expression.Lambda(body, _parameters); }
private static void ThrowTranslationFailed(LinqCommand command, string message, params object[] args) { var msg = StringHelper.SafeFormat(message, args) + "\r\n Query:" + command.ToString(); var exc = new LinqTranslationException(msg, command); throw exc; }
// Looks up SQL query in query cache; if not found, builds SqlQuery object and saves in cache. private TranslatedLinqCommand GetTranslateLinqCommand(LinqCommand command) { var cmdInfo = command.Info; //Lookup in cache SQL query or build it var translCmd = this.DbModel.QueryCache.Lookup(cmdInfo.CacheKey); if(translCmd != null) return translCmd; //Build sqlQuery if not found var engine = new Vita.Data.Linq.Translation.LinqEngine(this.DbModel); translCmd = engine.Translate(command); // save in cache var canCache = !cmdInfo.Options.IsSet(QueryOptions.NoQueryCache) && !translCmd.Flags.IsSet(LinqCommandFlags.NoQueryCache); if (canCache) DbModel.QueryCache.Add(cmdInfo.CacheKey, translCmd); return translCmd; }
public bool TryExecuteLinqQuery(EntitySession session, LinqCommand command, out object result) { result = null; if(!Settings.CacheEnabled || session.CacheDisabled || command.Info.Options.IsSet(QueryOptions.NoEntityCache)) return false; if(_fullSetCache.TryExecuteDynamicQuery(session, command, out result)) { return true; } return false; }
public LinqCommandEventArgs(IEntitySession session, LinqCommand command) : base(session) { Command = command; }
internal void OnExecutedQuery(EntitySession session, LinqCommand command) { if (ExecutedQuery != null) ExecutedQuery(session, new LinqCommandEventArgs(session, command)); }
// analyzes external values and creates db parameters private List<LinqCommandParameter> BuildParameters(LinqCommand command, TranslationContext context) { var sqlProvider = _dbModel.LinqSqlProvider; var parameters = new List<LinqCommandParameter>(); foreach (var extValue in context.ExternalValues) { if (extValue.SqlUseCount == 0) extValue.SqlUse = ExternalValueSqlUse.NotUsed; else _dbModel.LinqSqlProvider.CheckQueryParameter(extValue); switch (extValue.SqlUse) { case ExternalValueSqlUse.NotUsed: continue; //next value case ExternalValueSqlUse.Literal: // We cannot use this value as a parameter (ex: list/array of values with Contains() method); // in this case we transform it into literal value - it will be embedded into SQL directly. // The query becomes non-cacheable (because of this embedded literal) var paramReadValue = BuildParameterValueReader(command.Info.Lambda.Parameters, extValue.SourceExpression); extValue.LiteralValue = paramReadValue(context.Command.ParameterValues); break; case ExternalValueSqlUse.Parameter: var valueReader = BuildParameterValueReader(command.Info.Lambda.Parameters, extValue.SourceExpression); var dbParamName = _dbModel.LinqSqlProvider.GetParameterName("P" + parameters.Count); extValue.LinqParameter = new LinqCommandParameter(dbParamName, parameters.Count, extValue.SourceExpression.Type, valueReader); parameters.Add(extValue.LinqParameter); break; }//switch }//foreach extValue return parameters; }
private TranslatedLinqCommand TranslateNonQuery(LinqCommand command) { LinqCommandPreprocessor.PreprocessCommand(_dbModel.EntityApp.Model, command); var rewriterContext = 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); rewriterContext.ExternalValues.Add(inpParam); } //Analyze/transform base select query var exprChain = ExpressionChain.Build(cmdInfo.Lambda.Body); var selectExpr = BuildSelectExpression(exprChain, rewriterContext); // Analyze external values (parameters?), create DbParameters var cmdParams = BuildParameters(command, rewriterContext); var flags = command.Info.Flags; // If there's at least one parameter that must be converted to literal (ex: value list), we cannot cache the query bool canCache = !rewriterContext.ExternalValues.Any(v => v.SqlUse == ExternalValueSqlUse.Literal); if (!canCache) flags |= LinqCommandFlags.NoQueryCache; // !!! Before that, everyting is the same as in TranslateSelect var targetEnt = command.TargetEntity; var targetTableInfo = _dbModel.GetTable(targetEnt.EntityType); TableExpression targetTable; bool isSingleTable = selectExpr.Tables.Count == 1 && selectExpr.Tables[0].TableInfo == targetTableInfo; if(isSingleTable) { targetTable = selectExpr.Tables[0]; } else targetTable = _translator.CreateTable(targetEnt.EntityType, rewriterContext); var commandData = new NonQueryLinqCommandData(command, selectExpr, targetTable, isSingleTable); // Analyze base query output expression var readerBody = selectExpr.Reader.Body; switch(command.CommandType) { case LinqCommandType.Update: case LinqCommandType.Insert: Util.Check(readerBody.NodeType == ExpressionType.New, "Query for LINQ {0} command must return New object", commandData.CommandType); var newExpr = readerBody as NewExpression; var outValues = selectExpr.Operands.ToList(); for(int i = 0; i < newExpr.Members.Count; i++) { var memberName = newExpr.Members[i].Name; var memberInfo = targetEnt.GetMember(memberName); Util.Check(memberInfo != null, "Member {0} not found in entity {1}.", memberName, targetEnt, targetEnt.EntityType); switch(memberInfo.Kind) { case MemberKind.Column: var col = _translator.CreateColumn(targetTable, memberName, rewriterContext); commandData.TargetColumns.Add(col); commandData.SelectOutputValues.Add(outValues[i]); break; case MemberKind.EntityRef: var fromKey = memberInfo.ReferenceInfo.FromKey; Util.Check(fromKey.ExpandedKeyMembers.Count == 1, "References with composite keys are not supported in LINQ non-query operations. Reference: ", memberName); var pkMember = fromKey.ExpandedKeyMembers[0].Member; var col2 = _translator.CreateColumn(targetTable, pkMember.MemberName, rewriterContext); commandData.TargetColumns.Add(col2); commandData.SelectOutputValues.Add(outValues[i]); break; default: Util.Throw("Property cannot be used in the context: {0}.", memberName); break; } } break; case LinqCommandType.Delete: commandData.SelectOutputValues.Add(readerBody); //should return single value - primary key break; } // Build SQL var sqlBuilder = new SqlBuilder(_dbModel); var sqlStmt = sqlBuilder.BuildNonQuery(commandData); var sqlTemplate = sqlStmt.ToString(); var defaultSql = FormatSql(sqlTemplate, cmdParams); return new TranslatedLinqCommand(sqlTemplate, defaultSql, cmdParams, flags); }
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; }