public bool MoveNext() { try { if (_enumerator == null) { var selectExpression = (SelectExpression) new InExpressionValuesExpandingExpressionVisitor( _sqlExpressionFactory, _cosmosQueryContext.ParameterValues).Visit(_selectExpression); var sqlQuery = _querySqlGeneratorFactory.Create().GetSqlQuery( selectExpression, _cosmosQueryContext.ParameterValues); _enumerator = _cosmosQueryContext.CosmosClient .ExecuteSqlQuery( _selectExpression.ContainerName, sqlQuery) .GetEnumerator(); } var hasNext = _enumerator.MoveNext(); Current = hasNext ? _shaper(_cosmosQueryContext, _enumerator.Current) : default; return(hasNext); } catch (Exception exception) { _logger.QueryIterationFailed(_contextType, exception); throw; } }
public async ValueTask<bool> MoveNextAsync() { try { if (_enumerator == null) { var selectExpression = (SelectExpression)new InExpressionValuesExpandingExpressionVisitor( _sqlExpressionFactory, _cosmosQueryContext.ParameterValues).Visit(_selectExpression); _enumerator = _cosmosQueryContext.CosmosClient .ExecuteSqlQueryAsync( _selectExpression.ContainerName, _querySqlGeneratorFactory.Create().GetSqlQuery(selectExpression, _cosmosQueryContext.ParameterValues)) .GetAsyncEnumerator(_cancellationToken); } var hasNext = await _enumerator.MoveNextAsync(); Current = hasNext ? _shaper(_cosmosQueryContext, _enumerator.Current) : default; return hasNext; } catch (Exception exception) { _logger.QueryIterationFailed(_contextType, exception); throw; } }
/// <summary> /// 将linq转换成sql 返回sql和参数(EFCore 3.1) /// 第一个字符串为替换过 参数的sql字符串 /// 第二个字符串为原始的sql字符串 /// 第三个参数为参数 /// </summary> /// <typeparam name="TEntity"></typeparam> /// <param name="query"></param> /// <returns></returns> public static (string, string, IReadOnlyDictionary <string, object>) ToSqlWithParams <TEntity>(this IQueryable <TEntity> query) { var enumerator = query.Provider .Execute <IEnumerable <TEntity> >(query.Expression) .GetEnumerator(); Type enumeratorType = enumerator.GetType(); FieldInfo relationalCommandCacheFieldInfo = enumeratorType.GetField("_relationalCommandCache", bindingFlags) ?? throw new InvalidOperationException( $"cannot find field _relationalCommandCache on type {enumeratorType.Name}"); Type relationalCommandCacheType = relationalCommandCacheFieldInfo.FieldType; //获取查询表达式 var selectFieldInfo = relationalCommandCacheType.GetField("_selectExpression", bindingFlags) ?? throw new InvalidOperationException( $"cannot find field _selectExpression on type {relationalCommandCacheType.Name}"); var sqlGeneratorFieldInfo = relationalCommandCacheType.GetField("_querySqlGeneratorFactory", bindingFlags) ?? throw new InvalidOperationException( $"cannot find field _querySqlGeneratorFactory on type {relationalCommandCacheType.Name}"); var queryContextFieldInfo = enumeratorType.GetField("_relationalQueryContext", bindingFlags) ?? throw new InvalidOperationException( $"cannot find field _relationalQueryContext on type {enumeratorType.Name}"); object relationalCommandCache = relationalCommandCacheFieldInfo.GetValue(enumerator); var selectExpression = selectFieldInfo.GetValue(relationalCommandCache) as SelectExpression ?? throw new InvalidOperationException($"could not get SelectExpression"); var queryContext = queryContextFieldInfo.GetValue(enumerator) as RelationalQueryContext ?? throw new InvalidOperationException($"could not get RelationalQueryContext"); IQuerySqlGeneratorFactory factory = sqlGeneratorFieldInfo.GetValue(relationalCommandCache) as IQuerySqlGeneratorFactory ?? throw new InvalidOperationException($"could not get IQuerySqlGeneratorFactory"); //创建一个查询的对象 var sqlGenerator = factory.Create(); //获取执行的命令 var command = sqlGenerator.GetCommand(selectExpression); //执行sql传递的参数 var parametersDict = queryContext.ParameterValues; //原始的sql执行文本 var sql = command.CommandText; //将参数赋值转换 var converSql = sql; if (parametersDict != null && parametersDict.Count() > 0) { foreach (var item in parametersDict) { converSql = converSql.Replace($"@{item.Key}", $"'{item.Value.ToString()}'"); } } return(converSql, sql, parametersDict); }
public async ValueTask <bool> MoveNextAsync() { try { if (_dataReader == null) { await _relationalQueryContext.Connection.OpenAsync(_cancellationToken); try { var selectExpression = new ParameterValueBasedSelectExpressionOptimizer( _sqlExpressionFactory, _parameterNameGeneratorFactory) .Optimize(_selectExpression, _relationalQueryContext.ParameterValues); var relationalCommand = _querySqlGeneratorFactory.Create().GetCommand(selectExpression); _dataReader = await relationalCommand.ExecuteReaderAsync( _relationalQueryContext.Connection, _relationalQueryContext.ParameterValues, _relationalQueryContext.CommandLogger, _cancellationToken); _resultCoordinator = new ResultCoordinator(); } catch (Exception) { // If failure happens creating the data reader, then it won't be available to // handle closing the connection, so do it explicitly here to preserve ref counting. _relationalQueryContext.Connection.Close(); throw; } } var hasNext = _resultCoordinator.HasNext ?? await _dataReader.ReadAsync(_cancellationToken); _resultCoordinator.HasNext = null; Current = hasNext ? await _shaper(_relationalQueryContext, _dataReader.DbDataReader, _resultCoordinator) : default; return(hasNext); } catch (Exception exception) { _logger.QueryIterationFailed(_contextType, exception); throw; } }
/// <summary> /// parse select statement of queryable /// </summary> /// <typeparam name="TEntity"></typeparam> /// <param name="queryable"></param> /// <param name="ctx"></param> /// <returns></returns> public static SelectParsingResult Parse <TEntity>(this IQueryable <TEntity> queryable, DbContext ctx, bool ignoreQueryFilters) where TEntity : class { if (ignoreQueryFilters) { queryable = queryable.IgnoreQueryFilters(); } SelectParsingResult parsingResult = new SelectParsingResult(); Expression query = queryable.Expression; var databaseDependencies = ctx.GetService <DatabaseDependencies>(); IQueryTranslationPreprocessorFactory _queryTranslationPreprocessorFactory = ctx.GetService <IQueryTranslationPreprocessorFactory>(); IQueryableMethodTranslatingExpressionVisitorFactory _queryableMethodTranslatingExpressionVisitorFactory = ctx.GetService <IQueryableMethodTranslatingExpressionVisitorFactory>(); IQueryTranslationPostprocessorFactory _queryTranslationPostprocessorFactory = ctx.GetService <IQueryTranslationPostprocessorFactory>(); QueryCompilationContext queryCompilationContext = databaseDependencies.QueryCompilationContextFactory.Create(true); IDiagnosticsLogger <DbLoggerCategory.Query> logger = ctx.GetService <IDiagnosticsLogger <DbLoggerCategory.Query> >(); QueryContext queryContext = ctx.GetService <IQueryContextFactory>().Create(); QueryCompiler queryComipler = ctx.GetService <IQueryCompiler>() as QueryCompiler; //parameterize determines if it will use "Declare" or not MethodCallExpression methodCallExpr1 = queryComipler.ExtractParameters(query, queryContext, logger, parameterize: true) as MethodCallExpression; QueryTranslationPreprocessor queryTranslationPreprocessor = _queryTranslationPreprocessorFactory.Create(queryCompilationContext); MethodCallExpression methodCallExpr2 = queryTranslationPreprocessor.Process(methodCallExpr1) as MethodCallExpression; QueryableMethodTranslatingExpressionVisitor queryableMethodTranslatingExpressionVisitor = _queryableMethodTranslatingExpressionVisitorFactory.Create(queryCompilationContext); ShapedQueryExpression shapedQueryExpression1 = queryableMethodTranslatingExpressionVisitor.Visit(methodCallExpr2) as ShapedQueryExpression; QueryTranslationPostprocessor queryTranslationPostprocessor = _queryTranslationPostprocessorFactory.Create(queryCompilationContext); ShapedQueryExpression shapedQueryExpression2 = queryTranslationPostprocessor.Process(shapedQueryExpression1) as ShapedQueryExpression; IRelationalParameterBasedSqlProcessorFactory _relationalParameterBasedSqlProcessorFactory = ctx.GetService <IRelationalParameterBasedSqlProcessorFactory>(); RelationalParameterBasedSqlProcessor _relationalParameterBasedSqlProcessor = _relationalParameterBasedSqlProcessorFactory.Create(true); SelectExpression selectExpression = (SelectExpression)shapedQueryExpression2.QueryExpression; selectExpression = _relationalParameterBasedSqlProcessor.Optimize(selectExpression, queryContext.ParameterValues, out bool canCache); IQuerySqlGeneratorFactory querySqlGeneratorFactory = ctx.GetService <IQuerySqlGeneratorFactory>(); IZackQuerySqlGenerator querySqlGenerator = querySqlGeneratorFactory.Create() as IZackQuerySqlGenerator; if (querySqlGenerator == null) { throw new InvalidOperationException("please add dbContext.UseBatchEF() to OnConfiguring first!"); } querySqlGenerator.IsForBatchEF = true; querySqlGenerator.GetCommand(selectExpression); parsingResult.Parameters = queryContext.ParameterValues; parsingResult.PredicateSQL = querySqlGenerator.PredicateSQL; parsingResult.ProjectionSQL = querySqlGenerator.ProjectionSQL; TableExpression tableExpression = selectExpression.Tables[0] as TableExpression; parsingResult.TableName = tableExpression.Table.Name; return(parsingResult); }
//https://stackoverflow.com/a/51583047 public static string ToSql <TEntity>(this IQueryable <TEntity> query) where TEntity : class { IEnumerator <TEntity> enumerator = query.Provider.Execute <IEnumerable <TEntity> >(query.Expression).GetEnumerator(); object relationalCommandCache = enumerator.Private("_relationalCommandCache"); SelectExpression selectExpression = relationalCommandCache.Private <SelectExpression>("_selectExpression"); IQuerySqlGeneratorFactory factory = relationalCommandCache.Private <IQuerySqlGeneratorFactory>("_querySqlGeneratorFactory"); QuerySqlGenerator sqlGenerator = factory.Create(); Microsoft.EntityFrameworkCore.Storage.IRelationalCommand command = sqlGenerator.GetCommand(selectExpression); string sql = command.CommandText; return(sql); }
public static (string, IEnumerable <SqlParameter>) ToParametrizedSql(this IQueryable query) { string relationalCommandCacheText = "_relationalCommandCache"; string selectExpressionText = "_selectExpression"; string querySqlGeneratorFactoryText = "_querySqlGeneratorFactory"; string relationalQueryContextText = "_relationalQueryContext"; string cannotGetText = "Cannot get"; var enumerator = query.Provider.Execute <IEnumerable>(query.Expression).GetEnumerator(); var relationalCommandCache = enumerator.Private(relationalCommandCacheText) as RelationalCommandCache; var queryContext = enumerator.Private <RelationalQueryContext>(relationalQueryContextText) ?? throw new InvalidOperationException($"{cannotGetText} {relationalQueryContextText}"); var parameterValues = queryContext.ParameterValues; string sql; IList <SqlParameter> parameters; IRelationalCommand command; if (relationalCommandCache != null) { #pragma warning disable EF1001 // Internal EF Core API usage. command = relationalCommandCache.GetRelationalCommand(parameterValues); #pragma warning restore EF1001 // Internal EF Core API usage. } else { SelectExpression selectExpression = enumerator.Private <SelectExpression>(selectExpressionText) ?? throw new InvalidOperationException($"{cannotGetText} {selectExpressionText}"); IQuerySqlGeneratorFactory factory = enumerator.Private <IQuerySqlGeneratorFactory>(querySqlGeneratorFactoryText) ?? throw new InvalidOperationException($"{cannotGetText} {querySqlGeneratorFactoryText}"); command = factory.Create().GetCommand(selectExpression); } sql = command.CommandText; // Use a DbCommand to convert parameter values using ValueConverters to the correct type. using (var dbCommand = new SqlCommand()) { foreach (var param in command.Parameters) { var values = parameterValues[param.InvariantName]; param.AddDbParameter(dbCommand, values); } parameters = new List <SqlParameter>(dbCommand.Parameters.OfType <SqlParameter>()); dbCommand.Parameters.Clear(); } return(sql, parameters); }
public static (string, IEnumerable <SqlParameter>) ToParametrizedSql(this IQueryable query) { string relationalCommandCacheText = "_relationalCommandCache"; string selectExpressionText = "_selectExpression"; string querySqlGeneratorFactoryText = "_querySqlGeneratorFactory"; string relationalQueryContextText = "_relationalQueryContext"; string cannotGetText = "Cannot get"; var enumerator = query.Provider.Execute <IEnumerable>(query.Expression).GetEnumerator(); var relationalCommandCache = enumerator.Private(relationalCommandCacheText) as RelationalCommandCache; var queryContext = enumerator.Private <RelationalQueryContext>(relationalQueryContextText) ?? throw new InvalidOperationException($"{cannotGetText} {relationalQueryContextText}"); var parameterValues = queryContext.ParameterValues; string sql; IList <SqlParameter> parameters; if (relationalCommandCache != null) { #pragma warning disable EF1001 // Internal EF Core API usage. var command = relationalCommandCache.GetRelationalCommand(parameterValues); #pragma warning restore EF1001 // Internal EF Core API usage. var parameterNames = new HashSet <string>(command.Parameters.Select(p => p.InvariantName)); sql = command.CommandText; parameters = parameterValues.Where(pv => parameterNames.Contains(pv.Key)).Select(pv => new SqlParameter("@" + pv.Key, pv.Value)).ToList(); } else { SelectExpression selectExpression = enumerator.Private <SelectExpression>(selectExpressionText) ?? throw new InvalidOperationException($"{cannotGetText} {selectExpressionText}"); IQuerySqlGeneratorFactory factory = enumerator.Private <IQuerySqlGeneratorFactory>(querySqlGeneratorFactoryText) ?? throw new InvalidOperationException($"{cannotGetText} {querySqlGeneratorFactoryText}"); var sqlGenerator = factory.Create(); var command = sqlGenerator.GetCommand(selectExpression); sql = command.CommandText; parameters = parameterValues.Select(pv => new SqlParameter("@" + pv.Key, pv.Value)).ToList(); } return(sql, parameters); }
public async ValueTask <bool> MoveNextAsync() { try { using (_relationalQueryContext.ConcurrencyDetector.EnterCriticalSection()) { if (_dataReader == null) { var selectExpression = new ParameterValueBasedSelectExpressionOptimizer( _sqlExpressionFactory, _parameterNameGeneratorFactory) .Optimize(_selectExpression, _relationalQueryContext.ParameterValues); var relationalCommand = _querySqlGeneratorFactory.Create().GetCommand(selectExpression); _dataReader = await relationalCommand.ExecuteReaderAsync( new RelationalCommandParameterObject( _relationalQueryContext.Connection, _relationalQueryContext.ParameterValues, _relationalQueryContext.Context, _relationalQueryContext.CommandLogger), _cancellationToken); if (selectExpression.IsNonComposedFromSql()) { var projection = _selectExpression.Projection.ToList(); var readerColumns = Enumerable.Range(0, _dataReader.DbDataReader.FieldCount) .ToDictionary(i => _dataReader.DbDataReader.GetName(i), i => i, StringComparer.OrdinalIgnoreCase); _indexMap = new int[projection.Count]; for (var i = 0; i < projection.Count; i++) { if (projection[i].Expression is ColumnExpression columnExpression) { var columnName = columnExpression.Name; if (columnName != null) { if (!readerColumns.TryGetValue(columnName, out var ordinal)) { throw new InvalidOperationException(RelationalStrings.FromSqlMissingColumn(columnName)); } _indexMap[i] = ordinal; } } } } else { _indexMap = null; } _resultCoordinator = new ResultCoordinator(); } var hasNext = _resultCoordinator.HasNext ?? await _dataReader.ReadAsync(); Current = default; if (hasNext) { while (true) { _resultCoordinator.ResultReady = true; _resultCoordinator.HasNext = null; Current = _shaper( _relationalQueryContext, _dataReader.DbDataReader, _resultCoordinator.ResultContext, _indexMap, _resultCoordinator); if (_resultCoordinator.ResultReady) { // We generated a result so null out previously stored values _resultCoordinator.ResultContext.Values = null; break; } if (!await _dataReader.ReadAsync()) { _resultCoordinator.HasNext = false; // Enumeration has ended, materialize last element _resultCoordinator.ResultReady = true; Current = _shaper( _relationalQueryContext, _dataReader.DbDataReader, _resultCoordinator.ResultContext, _indexMap, _resultCoordinator); break; } } } return(hasNext); } } catch (Exception exception) { _logger.QueryIterationFailed(_contextType, exception); throw; } }
public bool MoveNext() { try { if (_dataReader == null) { var selectExpression = new ParameterValueBasedSelectExpressionOptimizer( _sqlExpressionFactory, _parameterNameGeneratorFactory) .Optimize(_selectExpression, _relationalQueryContext.ParameterValues); var relationalCommand = _querySqlGeneratorFactory.Create().GetCommand(selectExpression); _dataReader = relationalCommand.ExecuteReader( new RelationalCommandParameterObject( _relationalQueryContext.Connection, _relationalQueryContext.ParameterValues, _relationalQueryContext.Context, _relationalQueryContext.CommandLogger)); if (selectExpression.IsNonComposedFromSql()) { var projection = _selectExpression.Projection.ToList(); var readerColumns = Enumerable.Range(0, _dataReader.DbDataReader.FieldCount) .ToDictionary(i => _dataReader.DbDataReader.GetName(i), i => i, StringComparer.OrdinalIgnoreCase); _indexMap = new int[projection.Count]; for (var i = 0; i < projection.Count; i++) { if (projection[i].Expression is ColumnExpression columnExpression) { var columnName = columnExpression.Name; if (columnName != null) { if (!readerColumns.TryGetValue(columnName, out var ordinal)) { throw new InvalidOperationException(RelationalStrings.FromSqlMissingColumn(columnName)); } _indexMap[i] = ordinal; } } } } else { _indexMap = null; } _resultCoordinator = new ResultCoordinator(); } var hasNext = _resultCoordinator.HasNext ?? _dataReader.Read(); Current = default; if (hasNext) { while (true) { _resultCoordinator.ResultReady = true; _resultCoordinator.HasNext = null; Current = _shaper(_relationalQueryContext, _dataReader.DbDataReader, Current, _indexMap, _resultCoordinator); if (_resultCoordinator.ResultReady) { break; } if (!_dataReader.Read()) { _resultCoordinator.HasNext = false; break; } } } return(hasNext); } catch (Exception exception) { _logger.QueryIterationFailed(_contextType, exception); throw; } }
public bool MoveNext() { try { if (_dataReader == null) { _relationalQueryContext.Connection.Open(); try { var projection = _selectExpression.Projection.ToList(); var selectExpression = new ParameterValueBasedSelectExpressionOptimizer( _sqlExpressionFactory, _parameterNameGeneratorFactory) .Optimize(_selectExpression, _relationalQueryContext.ParameterValues); var relationalCommand = _querySqlGeneratorFactory.Create().GetCommand(selectExpression); _dataReader = relationalCommand.ExecuteReader( _relationalQueryContext.Connection, _relationalQueryContext.ParameterValues, _relationalQueryContext.CommandLogger); var readerColumns = Enumerable.Range(0, _dataReader.DbDataReader.FieldCount) .Select( i => new { Name = _dataReader.DbDataReader.GetName(i), Ordinal = i }).ToList(); _indexMap = new int[projection.Count]; for (var i = 0; i < projection.Count; i++) { if (projection[i].Expression is ColumnExpression columnExpression) { var columnName = columnExpression.Name; if (columnName != null) { var readerColumn = readerColumns.SingleOrDefault( c => string.Equals(columnName, c.Name, StringComparison.OrdinalIgnoreCase)); if (readerColumn == null) { throw new InvalidOperationException(RelationalStrings.FromSqlMissingColumn(columnName)); } _indexMap[i] = readerColumn.Ordinal; } } } } catch (Exception) { // If failure happens creating the data reader, then it won't be available to // handle closing the connection, so do it explicitly here to preserve ref counting. _relationalQueryContext.Connection.Close(); throw; } } var hasNext = _dataReader.Read(); Current = hasNext ? _shaper(_relationalQueryContext, _dataReader.DbDataReader, _indexMap) : default; return(hasNext); } catch (Exception exception) { _logger.QueryIterationFailed(_contextType, exception); throw; } }
public static (string, IEnumerable <SqlParameter>) ToParametrizedSql(this IQueryable query) { string relationalQueryContextText = "_relationalQueryContext"; string relationalCommandCacheText = "_relationalCommandCache"; string cannotGetText = "Cannot get"; var enumerator = query.Provider.Execute <IEnumerable>(query.Expression).GetEnumerator(); var queryContext = enumerator.Private <RelationalQueryContext>(relationalQueryContextText) ?? throw new InvalidOperationException($"{cannotGetText} {relationalQueryContextText}"); var parameterValues = queryContext.ParameterValues; #pragma warning disable EF1001 // Internal EF Core API usage. var relationalCommandCache = (RelationalCommandCache)enumerator.Private(relationalCommandCacheText); #pragma warning restore EF1001 IRelationalCommand command; if (relationalCommandCache != null) { #pragma warning disable EF1001 // Internal EF Core API usage. command = (IRelationalCommand)relationalCommandCache.GetRelationalCommandTemplate(parameterValues); #pragma warning restore EF1001 } else { string selectExpressionText = "_selectExpression"; string querySqlGeneratorFactoryText = "_querySqlGeneratorFactory"; SelectExpression selectExpression = enumerator.Private <SelectExpression>(selectExpressionText) ?? throw new InvalidOperationException($"{cannotGetText} {selectExpressionText}"); IQuerySqlGeneratorFactory factory = enumerator.Private <IQuerySqlGeneratorFactory>(querySqlGeneratorFactoryText) ?? throw new InvalidOperationException($"{cannotGetText} {querySqlGeneratorFactoryText}"); command = factory.Create().GetCommand(selectExpression); } string sql = command.CommandText; IList <SqlParameter> parameters; try { using (var dbCommand = new SqlCommand()) // Use a DbCommand to convert parameter values using ValueConverters to the correct type. { foreach (var param in command.Parameters) { var values = parameterValues[param.InvariantName]; param.AddDbParameter(dbCommand, values); } parameters = new List <SqlParameter>(dbCommand.Parameters.OfType <SqlParameter>()); dbCommand.Parameters.Clear(); } } catch (Exception ex) // Fix for BatchDelete with 'uint' param on Sqlite. TEST: RunBatchUint { var npgsqlSpecParamMessage = "Npgsql-specific type mapping "; // Full Msg: // "Npgsql-specific type mapping Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.Mapping.NpgsqlArrayListTypeMapping being used with non-Npgsql parameter type SqlParameter" // "Npgsql-specific type mapping NpgsqlTimestampTzTypeMapping being used with non-Npgsql parameter type SqlParameter" // for Batch (a < date) if (ex.Message.StartsWith("No mapping exists from DbType") && ex.Message.EndsWith("to a known SqlDbType.") || // example: "No mapping exists from DbType UInt32 to a known SqlDbType." ex.Message.StartsWith(npgsqlSpecParamMessage)) // Fix for BatchDelete with Contains on PostgreSQL { var parameterNames = new HashSet <string>(command.Parameters.Select(p => p.InvariantName)); parameters = parameterValues.Where(pv => parameterNames.Contains(pv.Key)).Select(pv => new SqlParameter("@" + pv.Key, pv.Value)).ToList(); } else { throw; } } return(sql, parameters); }