Skip to content

Instantly share code, notes, and snippets.

@nour-s
Forked from rionmonster/IQueryableExtensions
Last active January 30, 2020 14:02
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save nour-s/3bbf9b2588faa6b849393639a8b39757 to your computer and use it in GitHub Desktop.
Save nour-s/3bbf9b2588faa6b849393639a8b39757 to your computer and use it in GitHub Desktop.
Resolve the SQL being executed behind the scenes in Entity Framework Core
using System.Reflection;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.EntityFrameworkCore.Query.Internal;
using Microsoft.EntityFrameworkCore.Storage;
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;
}
}
@sunilshahi
Copy link

sunilshahi commented May 29, 2019

I think where TEntity : class is not needed. If we remove that, the method will work when a select is mapped to non reference type. eg:
MyDatabaseContext.MyTable.Select(t => t.Id).ToSql();
otherwise above will not compile.

@iamkinetic
Copy link

Anyone knows how to port this to .net core 3? QueryModelGenerator, RelationalQueryModelVisitor and queryCompilationContext.CreateQuerymodelVisitor() all seems to have vanished.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment