在使用 Entity Framework 作为 ORM 的时候,我们可能会根据得到的某个 IQueryable 查询对象,来“翻译”其最终的执行 SQL 以及传入的参数。经过一番拼凑,我得到了以下的方法,在此记录,便于日后学习和使用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
| /// <summary>
/// 根据 IQueryable 对象,获取其查询数据库的 SQL 语句,以及查询条件的参数值
/// </summary>
/// <param name="queryable">查询对象</param>
/// <param name="ctx">数据库上下文</param>
/// <returns></returns>
public static (string Sql, IReadOnlyDictionary<string, object> Parameters) GetSqlAndParameters(
this IQueryable queryable, DbContext ctx)
{
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 queryCompiler = ctx.GetService<IQueryCompiler>() as QueryCompiler;
MethodCallExpression methodCallExpr1 =
queryCompiler.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>();
QuerySqlGenerator querySqlGenerator = querySqlGeneratorFactory.Create();
var cmd = querySqlGenerator.GetCommand(selectExpression);
var parametersDict = queryContext.ParameterValues;
var sql = cmd.CommandText;
return (sql, parametersDict);
}
|