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;
                    }
                }
コード例 #3
0
        /// <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);
        }
コード例 #4
0
                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;
                    }
                }
コード例 #5
0
        /// <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);
        }
コード例 #6
0
        //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);
        }
コード例 #7
0
        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);
        }
コード例 #8
0
        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;
                    }
                }
コード例 #10
0
                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;
                    }
                }
コード例 #11
0
                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;
                    }
                }
コード例 #12
0
        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);
        }