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 EntityCacheQuery GetCacheQuery(LinqCommand command) { // Try to lookup in query cache var cacheQuery = _queryCache.Lookup(command.Info.CacheKey); if (cacheQuery != null) { return(cacheQuery); } // Build query and save it in entity cache //Preprocess query to get all entity types used LinqCommandPreprocessor.PreprocessCommand(_app.Model, command); foreach (var ent in command.Info.Entities) { if (ent.CacheType != CacheType.FullSet) { return(null); //cannot use cache for this query } } //Rewrite query for cache // string case mode is either case insensitive when query option is set (search queries are case insensitive) // or set to default value for cache (which is the same as DB-s default case value) var queryCaseMode = command.Info.Options.IsSet(QueryOptions.ForceIgnoreCase) ? StringCaseMode.CaseInsensitive : _caseMode; var rewriter = new CacheQueryRewriter(_app.Model, queryCaseMode); var cacheFunc = rewriter.Rewrite(command.Info.Lambda); cacheQuery = new EntityCacheQuery(cacheFunc, command.Info.Lambda.ToString()); _queryCache.Add(command.Info.CacheKey, cacheQuery); return(cacheQuery); }
public virtual bool CanDeleteRecord(EntityRecord record, out Type[] blockingEntities) { Util.Check(record != null, "CanDeleteRecord: record parameter may not be null."); blockingEntities = null; var entInfo = record.EntityInfo; var blockingTypeSet = new HashSet <Type>(); //check all external ref members foreach (var refMember in entInfo.IncomingReferences) { // if it is cascading delete, this member is not a problem if (refMember.Flags.IsSet(EntityMemberFlags.CascadeDelete)) { continue; } var countCmdInfo = refMember.ReferenceInfo.CountCommand; var countCmd = new LinqCommand(countCmdInfo, refMember.ReferenceInfo.ToKey.Entity, new object[] { this, record.EntityInstance }); var count = (int)ExecuteLinqCommand(countCmd); if (count > 0) { blockingTypeSet.Add(refMember.Entity.EntityType); } } if (blockingTypeSet.Count == 0) { return(true); } blockingEntities = blockingTypeSet.ToArray(); return(false); }
public virtual object ExecuteLinqCommand(LinqCommand command, bool withIncludes = true) { try { var result = _dataSource.ExecuteLinqCommand(this, command); switch (command.Operation) { case LinqOperation.Select: Context.App.AppEvents.OnExecutedSelect(this, command); if (withIncludes && (command.Includes?.Count > 0 || Context.HasIncludes())) { IncludeProcessor.RunIncludeQueries(command, result); } //Util.Throw("Include processor disabled."); break; default: Context.App.AppEvents.OnExecutedNonQuery(this, command); NextTransactionId = Guid.NewGuid(); break; } return(result); } catch (Exception ex) { ex.AddValue("entity-command", command + string.Empty); ex.AddValue("parameters", command.ParamValues); throw; } }
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); } }
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); }
internal void OnExecutedNonQuery(EntitySession session, LinqCommand command) { if (ExecutedNonQuery != null) { ExecutedNonQuery(session, new LinqCommandEventArgs(session, command)); } }
} //method 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; }
public bool TryExecuteDynamicQuery(EntitySession session, LinqCommand command, out object result) { result = null; if (!CheckFullSetCacheCurrent(session)) { return(false); } var cmdInfo = command.Info; //try getting previously compiled version or compile it var cacheQuery = GetCacheQuery(command); if (cacheQuery == null) { return(false); } var start = _timeService.ElapsedMilliseconds; result = cacheQuery.CacheFunc(session, this, command.ParameterValues); var end = _timeService.ElapsedMilliseconds; var logEntry = new CacheQueryLogEntry(session.Context, cacheQuery.LogString, command.ParameterValues, _timeService.UtcNow, end - start, GetRowCount(result)); session.AddLogEntry(logEntry); session.Context.EntityCacheVersion = CurrentVersion; return(true); }
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 LinqTranslationException(string message, LinqCommand command, Exception inner = null) : base(message, inner) { Command = command; if (Command != null) { this.Data["LinqExpression"] = Command.Lambda?.ToString(); } }
public ViewDefinition(EntityModule module, Type entityType, EntityQuery query, DbViewOptions options, string name) { Module = module; EntityType = entityType; Options = options; Name = name; Command = new LinqCommand(query, LinqCommandType.Select, LinqCommandKind.View, null); }
public TranslationContext(TranslationContext source) { this.DbModel = source.DbModel; this.Command = source.Command; this.ExternalValues = source.ExternalValues; this.SelectExpressions = source.SelectExpressions; this.LambdaParameters = source.LambdaParameters; this._currentScopeIndex = source._currentScopeIndex; }
public TranslationContext(DbModel dbModel, LinqCommand command) { DbModel = dbModel; Command = command; SelectExpressions = new List <SelectExpression>(); _currentScopeIndex = SelectExpressions.Count; SelectExpressions.Add(new SelectExpression(Command)); ExternalValues = new List <ExternalValueExpression>(); LambdaParameters = new Dictionary <string, Expression>(); }
// Helper methods private SqlStatement GetCachedLinqSql(LinqCommand command) { if (command.Options.IsSet(QueryOptions.NoQueryCache)) { return(null); } Util.Check(!string.IsNullOrEmpty(command.SqlCacheKey), "Fatal: SQL cache key is not set for LINQ query: {0}", command); var sql = _sqlCache.Lookup(command.SqlCacheKey); return(sql); }
private object ExecuteLinqNonQuery(EntitySession session, LinqCommand command, DataConnection conn) { var sql = SqlFactory.GetLinqSql(command); var fmtOptions = command.Options.IsSet(QueryOptions.NoParameters) ? SqlGenMode.NoParameters : SqlGenMode.PreferParam; var cmdBuilder = new DataCommandBuilder(this._driver); cmdBuilder.AddLinqStatement(sql, command.ParamValues); var dataCmd = cmdBuilder.CreateCommand(conn, DbExecutionType.NonQuery, sql.ResultProcessor); ExecuteDataCommand(dataCmd); return(dataCmd.ProcessedResult ?? dataCmd.Result); }
public object ExecuteLinqSelect(EntitySession session, LinqCommand command, DataConnection conn) { var sql = SqlFactory.GetLinqSql(command); var genMode = command.Options.IsSet(QueryOptions.NoParameters) ? SqlGenMode.NoParameters : SqlGenMode.PreferParam; var cmdBuilder = new DataCommandBuilder(this._driver, batchMode: false, mode: genMode); cmdBuilder.AddLinqStatement(sql, command.ParamValues); var dataCmd = cmdBuilder.CreateCommand(conn, DbExecutionType.Reader, sql.ResultProcessor); ExecuteDataCommand(dataCmd); return(dataCmd.ProcessedResult); }
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); }
/// <summary>Executes non-query operation of specified type based on LINQ query. See concrete methods for specific command types /// for more information and requirements to base query in each case. </summary> /// <typeparam name="TEntity">Entity type.</typeparam> /// <param name="query">Base query.</param> /// <param name="commandType">Command type (insert, update or delete).</param> /// <returns></returns> public static int ExecuteNonQuery <TEntity>(this IQueryable query, LinqCommandType commandType) { var entQuery = query as EntityQuery; var prov = entQuery.Provider as EntityQueryProvider; var session = prov.Session; Util.Check(session != null, "Cannot execute query not associated with active entity session."); var targetEnt = session.Context.App.Model.GetEntityInfo(typeof(TEntity)); var command = new LinqCommand(entQuery, commandType, LinqCommandKind.DynamicSql, targetEnt); var objResult = session.ExecuteLinqCommand(command); return((int)objResult); }
//TODO: test and fix the following: // Includes - when including child list, the list initialized only if it's not empty; // if empty, it remains uninitialized, and on touch fwk fires select query with 0 results // Initially found in some external solution, seemed to be broken, but now maybe working. Needs to be retested! internal static void RunIncludeQueries(LinqCommand command, object mainQueryResult) { // initial checks if there's anything to run if (mainQueryResult == null) { return; } var session = command.Session; var allIncludes = session.Context.GetMergedIncludes(command.Includes); if (allIncludes == null || allIncludes.Count == 0) { return; } var resultShape = GetResultShape(session.Context.App.Model, mainQueryResult.GetType()); if (resultShape == QueryResultShape.Object) { 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 IncludeProcessor(session, allIncludes); session.LogMessage("------- Running include queries ----------"); helper.RunIncludeQueries(entityType, records); session.LogMessage("------- Completed include queries ----------"); }
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); }
public NonQueryLinqCommandData(LinqCommand baseLinqCommand, SelectExpression baseSelect, TableExpression targetTable) { BaseLinqCommand = baseLinqCommand; BaseSelect = baseSelect; TargetTable = targetTable; switch(BaseLinqCommand.CommandType) { case LinqCommandType.Insert: UseSimpleCommand = false; break; default: var allTables = BaseSelect.Tables; var usesSkipTakeOrderBy = BaseSelect.Offset != null || BaseSelect.Limit != null; UseSimpleCommand = allTables.Count == 1 && allTables[0].TableInfo == targetTable.TableInfo && !usesSkipTakeOrderBy; break; } }
public virtual bool IsSqlTier(Expression expression, LinqCommand command) { var sqlExpr = expression as SqlExpression; if (sqlExpr != null) { switch (sqlExpr.SqlNodeType) { case SqlExpressionType.Select: case SqlExpressionType.Column: case SqlExpressionType.Table: case SqlExpressionType.ExternalValue: case SqlExpressionType.SqlFunction: return(true); case SqlExpressionType.Group: case SqlExpressionType.DerivedTable: return(false); default: return(true); } } switch (expression.NodeType) { case ExpressionType.ArrayLength: case ExpressionType.ArrayIndex: case ExpressionType.Call: case ExpressionType.Convert: case ExpressionType.ConvertChecked: case ExpressionType.Invoke: case ExpressionType.Lambda: case ExpressionType.ListInit: case ExpressionType.MemberAccess: case ExpressionType.MemberInit: case ExpressionType.New: case ExpressionType.NewArrayInit: case ExpressionType.NewArrayBounds: case ExpressionType.Parameter: case ExpressionType.SubtractChecked: case ExpressionType.TypeAs: case ExpressionType.TypeIs: return(false); default: return(true); } }
public object ExecuteLinqCommand(EntitySession session, LinqCommand command) { object result = null; if (Cache != null && command.Operation == LinqOperation.Select && Cache.TryExecuteSelect(session, command, out result)) { return(result); } result = Database.ExecuteLinqCommand(session, command); //If we are returning entities, cache them; if updating - invalidate if (Cache != null) { Cache.OnCommandExecuted(session, command, result); } return(result); }
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 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, qParam.Type, value); cmd.Parameters.Add(dbParam); } return(cmd); }
public SqlStatement GetLinqSql(LinqCommand command) { // lookup in cache var stmt = GetCachedLinqSql(command); if (stmt != null) { return(stmt); } // not in cache - translate stmt = _linqEngine.Translate(command); _driver.SqlDialect.ReviewSqlStatement(stmt, command); if (!command.Options.IsSet(QueryOptions.NoQueryCache)) { _sqlCache.Add(command.SqlCacheKey, stmt); } return(stmt); }
// Note: Earlier implementation was doing authorization check in Attach method - but this does not work well, this is too early // Instead, checking authorization in ExecuteQuery public override object ExecuteLinqCommand(LinqCommand command) { var result = base.ExecuteLinqCommand(command); if (result == null) { return(null); } if (command.CommandType != LinqCommandType.Select) { return(result); } switch (command.Info.ResultShape) { case QueryResultShape.Entity: var rec = EntityHelper.GetRecord(result); if (!CheckRecordAccess(rec, AccessType.Peek)) { return(null); } return(result); case QueryResultShape.EntityList: // Note that result list is a typed List<TEntity>; we need to filter it. To avoid trouble of creating another typed list, // we filter elements 'in place', iterating it in reverse order var list = result as System.Collections.IList; for (int i = list.Count - 1; i >= 0; i--) { var ent = list[i]; var rec2 = EntityHelper.GetRecord(ent); if (rec2 == null || !CheckRecordAccess(rec2, AccessType.Peek)) { list.RemoveAt(i); } } return(result); default: // if it is auto type or list of auto types, we return it as-is. If auto-object has Entities in properties, they will be there, // even if authorization does not allow the user to access them; // but as soon as the code tries to access properties of these entities, authorization will throw AccessDenied return(result); } }
public object ExecuteLinqCommand(EntitySession session, LinqCommand command) { var conn = GetConnectionWithLock(session, command.LockType); try { object result; if (command.Operation == LinqOperation.Select) { result = ExecuteLinqSelect(session, command, conn); } else { result = ExecuteLinqNonQuery(session, command, conn); } ReleaseConnection(conn); return(result); } catch (Exception dex) { ReleaseConnection(conn, inError: true); dex.AddValue(DataAccessException.KeyLinqQuery, command.ToString()); throw; } }
public virtual object ExecuteLinqCommand(LinqCommand command) { this.LastLinqCommand = command; var cmdInfo = LinqCommandAnalyzer.Analyze(Context.App.Model, command); if (command.Kind == LinqCommandKind.DynamicSql) { command.EvaluateLocalValues(this); } //account for LinkedApps - get any entity involved in query and get the app it is registered in EntityApp targetApp = this.Context.App; if (cmdInfo.EntityTypes.Count > 0) { var someType = cmdInfo.EntityTypes[0]; var someEntInfo = GetEntityInfo(someType); Util.Check(someEntInfo != null, "Type {0} is not a registered entity, cannot execute the query.", someType); targetApp = someEntInfo.Module.App; } var ds = targetApp.DataAccess.GetDataSource(this.Context); var result = ds.ExecuteLinqCommand(this, command); //fire events switch (command.CommandType) { case LinqCommandType.Select: _appEvents.OnExecutedQuery(this, command); break; default: _appEvents.OnExecutedNonQuery(this, command); NextTransactionId = Guid.NewGuid(); break; } if (command.Info.Includes.Count > 0 || Context.HasIncludes()) { IncludeQueryHelper.RunIncludeQueries(this, command, result); } return(result); }