Mig*_*ura 48 entity-framework-core
我正在使用Entity Framework 7 Core RC2(重命名为:EF Core),我需要查看正在生成哪个SQL代码.在先前版本的Entity Framework中,我可以使用以下内容:
String sql = ((System.Data.Objects.ObjectQuery)query).ToTraceString();
Run Code Online (Sandbox Code Playgroud)
其中query是IQueryable对象...但是EF Core中没有ToTraceString.
我怎样才能在EF Core中做类似的事情?
Nik*_*tov 55
由于EF 7重命名为Entity Framework Core,因此我将总结EF Core的选项.
记录SQL语句有3种方法IQueryable<>
:
这是疯狂的反射代码(扩展方法):
public static class IQueryableExtensions
{
private static readonly TypeInfo QueryCompilerTypeInfo = typeof(QueryCompiler).GetTypeInfo();
private static readonly FieldInfo QueryCompilerField = typeof(EntityQueryProvider).GetTypeInfo().DeclaredFields.First(x => x.Name == "_queryCompiler");
private static readonly FieldInfo QueryModelGeneratorField = QueryCompilerTypeInfo.DeclaredFields.First(x => x.Name == "_queryModelGenerator");
private static readonly FieldInfo DataBaseField = QueryCompilerTypeInfo.DeclaredFields.Single(x => x.Name == "_database");
private static readonly PropertyInfo DatabaseDependenciesField = typeof(Database).GetTypeInfo().DeclaredProperties.Single(x => x.Name == "Dependencies");
public static string ToSql<TEntity>(this IQueryable<TEntity> query) where TEntity : class
{
var queryCompiler = (QueryCompiler)QueryCompilerField.GetValue(query.Provider);
var modelGenerator = (QueryModelGenerator)QueryModelGeneratorField.GetValue(queryCompiler);
var queryModel = modelGenerator.ParseQuery(query.Expression);
var database = (IDatabase)DataBaseField.GetValue(queryCompiler);
var databaseDependencies = (DatabaseDependencies)DatabaseDependenciesField.GetValue(database);
var queryCompilationContext = databaseDependencies.QueryCompilationContextFactory.Create(false);
var modelVisitor = (RelationalQueryModelVisitor)queryCompilationContext.CreateQueryModelVisitor();
modelVisitor.CreateQueryExecutor<TEntity>(queryModel);
var sql = modelVisitor.Queries.First().ToString();
return sql;
}
}
Run Code Online (Sandbox Code Playgroud)
将此扩展方法添加到代码后,您可以使用以下方法:
// Build a query using Entity Framework
var query = _context.Widgets.Where(w => w.IsReal && w.Id == 42);
// Get the generated SQL
var sql = query.ToSql();
Run Code Online (Sandbox Code Playgroud)
推荐:http://rion.io/2016/10/19/accessing-entity-framework-core-queries-behind-the-scenes-in-asp-net-core/和https://gist.github.com/rionmonster/2c59f449e67edf8cd6164e9fe66c545a
更新:已编辑,以便支持EF Core 2.1
Tho*_*ter 22
对于EF Core 2.1.2,您可以使用它.
public static class QueryableExtensions
{
private static readonly TypeInfo QueryCompilerTypeInfo = typeof(QueryCompiler).GetTypeInfo();
private static readonly FieldInfo QueryCompilerField = typeof(EntityQueryProvider).GetTypeInfo().DeclaredFields.First(x => x.Name == "_queryCompiler");
private static readonly FieldInfo QueryModelGeneratorField = typeof(QueryCompiler).GetTypeInfo().DeclaredFields.First(x => x.Name == "_queryModelGenerator");
private static readonly FieldInfo DataBaseField = QueryCompilerTypeInfo.DeclaredFields.Single(x => x.Name == "_database");
private static readonly PropertyInfo DatabaseDependenciesField = typeof(Database).GetTypeInfo().DeclaredProperties.Single(x => x.Name == "Dependencies");
public static string ToSql<TEntity>(this IQueryable<TEntity> query)
{
var queryCompiler = (QueryCompiler) QueryCompilerField.GetValue(query.Provider);
var queryModelGenerator = (QueryModelGenerator)QueryModelGeneratorField.GetValue(queryCompiler);
var queryModel = queryModelGenerator.ParseQuery(query.Expression);
var database = DataBaseField.GetValue(queryCompiler);
var databaseDependencies = (DatabaseDependencies) DatabaseDependenciesField.GetValue(database);
var queryCompilationContext = databaseDependencies.QueryCompilationContextFactory.Create(false);
var modelVisitor = (RelationalQueryModelVisitor) queryCompilationContext.CreateQueryModelVisitor();
modelVisitor.CreateQueryExecutor<TEntity>(queryModel);
var sql = modelVisitor.Queries.First().ToString();
return sql;
}
}
Run Code Online (Sandbox Code Playgroud)
tom*_*dox 18
对于只想诊断一次性未解决的EF Core查询或类似问题并且不想更改其代码的任何人,有两种选择:
如果安装了SQL Server Management Studio(SSMS),则可以从SSMS的“工具”菜单中启动SQL事件探查器:
一旦它打开,然后启动在SQL Profiler中运行的新跟踪。
然后,您将能够看到来自EF的传入SQL请求,它们通常结构良好且易于阅读。
在我的VS2019副本中,使用EF2.2,我可以更改输出窗口以显示Web服务器的输出(在“输出”窗格顶部的“显示输出来自”组合中选择应用程序和Web服务器的名称)传出的SQL也显示在其中。我已经检查了我的代码,据我所知我还没有做任何事情来启用它,所以我认为默认情况下它必须这样做:
小智 11
对于上述 EF Core 3.1 解决方案,您System.InvalidCastException
在使用myQueryable.Where(x => ids.Contains(x.Id))
.
(生成以下形式的 sql 语句SELECT ... FROM ... WHERE ID IN (...)
)
System.InvalidCastException
Message=Unable to cast object of type 'Microsoft.EntityFrameworkCore.Query.SqlExpressions.SqlParameterExpression' to type 'Microsoft.EntityFrameworkCore.Query.SqlExpressions.SqlConstantExpression'.
Source=Microsoft.EntityFrameworkCore.Relational
StackTrace:
at Microsoft.EntityFrameworkCore.Query.QuerySqlGenerator.VisitIn(InExpression inExpression) in /_/src/EFCore.Relational/Query/QuerySqlGenerator.cs:line 577
at Microsoft.EntityFrameworkCore.Query.SqlExpressionVisitor.VisitExtension(Expression extensionExpression) in /_/src/EFCore.Relational/Query/SqlExpressionVisitor.cs:line 37
at System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor) in /_/src/System.Linq.Expressions/src/System/Linq/Expressions/Expression.cs:line 164
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node) in /_/src/System.Linq.Expressions/src/System/Linq/Expressions/ExpressionVisitor.cs:line 34
Run Code Online (Sandbox Code Playgroud)
为了解决这个问题,请将代码调整为类似的内容:
System.InvalidCastException
Message=Unable to cast object of type 'Microsoft.EntityFrameworkCore.Query.SqlExpressions.SqlParameterExpression' to type 'Microsoft.EntityFrameworkCore.Query.SqlExpressions.SqlConstantExpression'.
Source=Microsoft.EntityFrameworkCore.Relational
StackTrace:
at Microsoft.EntityFrameworkCore.Query.QuerySqlGenerator.VisitIn(InExpression inExpression) in /_/src/EFCore.Relational/Query/QuerySqlGenerator.cs:line 577
at Microsoft.EntityFrameworkCore.Query.SqlExpressionVisitor.VisitExtension(Expression extensionExpression) in /_/src/EFCore.Relational/Query/SqlExpressionVisitor.cs:line 37
at System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor) in /_/src/System.Linq.Expressions/src/System/Linq/Expressions/Expression.cs:line 164
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node) in /_/src/System.Linq.Expressions/src/System/Linq/Expressions/ExpressionVisitor.cs:line 34
Run Code Online (Sandbox Code Playgroud)
我的看法基于@nikolay-kostov 的回答。
不同之处在于,我获取的 SQL 命令带有提取的参数,而不是硬编码的参数,这更符合 EF Core 将命令发送到数据库的方式。另外,如果您想编辑命令并将其发送到数据库,最好使用参数。
private static class IQueryableUtils
{
private static readonly TypeInfo QueryCompilerTypeInfo = typeof(QueryCompiler).GetTypeInfo();
private static readonly FieldInfo QueryCompilerField = typeof(EntityQueryProvider).GetTypeInfo().DeclaredFields.First(x => x.Name == "_queryCompiler");
private static readonly FieldInfo QueryModelGeneratorField = QueryCompilerTypeInfo.DeclaredFields.First(x => x.Name == "_queryModelGenerator");
private static readonly FieldInfo queryContextFactoryField = QueryCompilerTypeInfo.DeclaredFields.First(x => x.Name == "_queryContextFactory");
private static readonly FieldInfo loggerField = QueryCompilerTypeInfo.DeclaredFields.First(x => x.Name == "_logger");
private static readonly FieldInfo DataBaseField = QueryCompilerTypeInfo.DeclaredFields.Single(x => x.Name == "_database");
private static readonly PropertyInfo DatabaseDependenciesField = typeof(Database).GetTypeInfo().DeclaredProperties.Single(x => x.Name == "Dependencies");
public static (string sql, IReadOnlyDictionary<string, object> parameters) ToSql<TEntity>(IQueryable<TEntity> query) where TEntity : class
{
var queryCompiler = (QueryCompiler)QueryCompilerField.GetValue(query.Provider);
var queryContextFactory = (IQueryContextFactory)queryContextFactoryField.GetValue(queryCompiler);
var logger = (Microsoft.EntityFrameworkCore.Diagnostics.IDiagnosticsLogger<DbLoggerCategory.Query>)loggerField.GetValue(queryCompiler);
var queryContext = queryContextFactory.Create();
var modelGenerator = (QueryModelGenerator)QueryModelGeneratorField.GetValue(queryCompiler);
var newQueryExpression = modelGenerator.ExtractParameters(logger, query.Expression, queryContext);
var queryModel = modelGenerator.ParseQuery(newQueryExpression);
var database = (IDatabase)DataBaseField.GetValue(queryCompiler);
var databaseDependencies = (DatabaseDependencies)DatabaseDependenciesField.GetValue(database);
var queryCompilationContext = databaseDependencies.QueryCompilationContextFactory.Create(false);
var modelVisitor = (RelationalQueryModelVisitor)queryCompilationContext.CreateQueryModelVisitor();
modelVisitor.CreateQueryExecutor<TEntity>(queryModel);
var command = modelVisitor.Queries.First().CreateDefaultQuerySqlGenerator()
.GenerateSql(queryContext.ParameterValues);
return (command.CommandText, queryContext.ParameterValues);
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
29759 次 |
最近记录: |