793

How do I view the SQL generated by entity framework ?

(In my particular case I'm using the mysql provider - if it matters)

Sr Julien
  • 494
  • 1
  • 8
  • 27
nos
  • 223,662
  • 58
  • 417
  • 506
  • 3
    The linked "duplicate" question is for LINQ to SQL, so its not actually a duplicate. – jrummell Jul 11 '11 at 15:18
  • 2
    [This](http://msdn.microsoft.com/en-us/magazine/gg490349.aspx) artice from MSDN Magazine describes some profiling options for Entity Framework 4 – Arve Feb 08 '11 at 20:37
  • 3
    When running under debugger, IntelliTrace shows SQL queries made, albeit without their results. – ivan_pozdeev Mar 07 '14 at 10:24
  • 1
    If you're interested in seeing the SQL just while development, you can use [LINQPad](https://www.linqpad.net/). When you run a LINQ query in the results there will be an SQL tab which shows the executed SQL statement. For mySQL you'll have to install a driver. I don't have a mySQL database available, but it should work. – gligoran Apr 24 '15 at 12:19
  • 1
    The amount of complicated answers to this question is making me reconsider EF. This seems like a very basic function in an ORM. – Kellen Stuart Jun 09 '21 at 16:51
  • Most methods I've seen don't seem to work for me but I did get something like this to finally work using EF 6.4 var sql = ((dynamic)result).ToString(); – Jazzeroki Jul 19 '22 at 22:58

24 Answers24

1125

For those using Entity Framework 6 and up (not in EF CORE - see comment below), if you want to view the output SQL in Visual Studio (like I did) you have to use the new logging/interception functionality.

Adding the following line will spit out the generated SQL (along with additional execution-related details) in the Visual Studio output panel:

using (MyDatabaseEntities context = new MyDatabaseEntities())
{
    context.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
    // query the database using EF here.
}

More information about logging in EF6 in this nifty blog series: http://blog.oneunicorn.com/2013/05/08/ef6-sql-logging-part-1-simple-logging/

Note: Make sure you are running your project in DEBUG mode.

surfmuggle
  • 5,527
  • 7
  • 48
  • 77
Matt Nibecker
  • 11,487
  • 2
  • 14
  • 9
  • 115
    This answer deserves more love (if you're using EF6+) - great debug addition, just add it in on the DBContext constructor (this.Database.Log = ...) – keithl8041 Feb 07 '14 at 12:54
  • @vittore - actually, I'm using EF6.1.0; and as you said its not working when building stating: **Cannot create delegate with 'System.Diagnostics.Debug.WriteLine(string)' because it has a Conditional attribute**. However the above answer works fine! – Stephen Lautier Apr 22 '14 at 16:25
  • @StephenLautier I have to rephrase my comment or remove it, in fact without lambda it will work only from Command Window. – vittore Apr 22 '14 at 16:59
  • 23
    Make sure you are running your project in DEBUG MODE, check if the item "Debug" has selected on combobox of Output pane and also check if your debug is not redirecting to Immediate (Tools > Options > Debugging > Redirect all Output Window text to Immediate Window) – rkawano May 21 '14 at 17:41
  • 6
    is there a way to get this to include the variable values directly within the generated sql? Bit of a pain with the bigger ones. – Chris Owens Jun 28 '14 at 07:02
  • YES. or using something like Serilog etc. `context.Database.Log = s => Log.Verbose(s);` – CAD bloke Mar 29 '16 at 23:23
  • For those using a DataContext but stumbled here anyway, you can use `DataContext.Log` https://msdn.microsoft.com/en-us/library/system.data.linq.datacontext.log(v=vs.110).aspx – Protector one Jun 15 '16 at 08:51
  • 39
    @Matt Nibecker This does not work in EF Core. What's the alternative for EF Core? – nam Sep 16 '16 at 04:13
  • 1
    Unfortunately whatever you use assign to .Log will be called multiple times per query (open conn, first part of sql, more parts of sql, close conn). – tymtam Sep 27 '16 at 23:32
  • quite useful! Looks like `context.Database.Log = Debug.WriteLine;` doesn't work.. you sepecifically have to go like `... s => ...(s);` , the way it _is_ in your answer! – Irf Dec 21 '16 at 11:22
  • Hm, it doesn't work when I debug my unit test. I put the statement in the constructor of my DbContext. – Legends Jul 21 '17 at 10:39
  • 20
    WARNING: I implemented this with the intention of it only running in development. When we deployed to our testing environment, we started to abruptly see memory leaks in the IIS Worker Process. After memory profiling, we realized even explicit GC wasn't collecting the entity context objects anymore (yes, they were in using statements). Removing this line returned all to normal. So, while this is a great tool, make sure you only build it into your app for development. – Brandon Barkley Aug 16 '17 at 17:35
  • 1
    Or just add it to your concrete constructor: ```public MyDbContext() : base("name=MyDbContext") { Database.Log = sql => System.Diagnostics.Debug.WriteLine(sql); }``` – GFoley83 Aug 27 '17 at 02:54
  • 2
    How can this be configured using ASP.NET Core? The DbContext is injected automatically and we don't control the creation of it. – SuperJMN Dec 06 '17 at 18:47
  • 2
    how do you do this for core? – Demodave Feb 15 '19 at 22:30
  • 4
    Everyone looking for a solution for ef core. See the answer of Rosdi Kasim further down here: https://stackoverflow.com/a/52686803/1341189 – Hightower Nov 27 '19 at 08:33
  • 1
    For EF Core, mine was already logging the SQL to the output window by default - I just hadn't checked! – Paul Jan 02 '20 at 13:41
  • For anyone still using VB.NET, the syntax is `Me.Database.Log = Sub(s) Logger.Debug(s)` (in my case, I added it directly on the constructor and I used a Logger instead of outputting to the console). – Alicia Jul 07 '22 at 12:53
  • 2
    .NET 6 > Error CS1656: Cannot assign to 'Log' because it is a 'method group' – xRavisher Jul 20 '22 at 01:16
548

You can do the following:

IQueryable query = from x in appEntities
             where x.id == 32
             select x;

var sql = ((System.Data.Objects.ObjectQuery)query).ToTraceString();

or in EF6:

var sql = ((System.Data.Entity.Core.Objects.ObjectQuery)query)
            .ToTraceString();

or in EF6.3+:

var sql = ((dynamic)flooringStoresProducts).Sql;

That will give you the SQL that was generated.

user1477388
  • 20,790
  • 32
  • 144
  • 264
Nick Berardi
  • 54,393
  • 15
  • 113
  • 135
  • 22
    You won't get SQL for queries ending with .Single(), .Count(), .Any(), etc. that way. – springy76 Feb 27 '13 at 12:31
  • 29
    That is because after running `.Single()` your object is no more `IQueryable` I guess. – Suhas Jun 19 '13 at 07:39
  • 14
    with EF6, I could get it only with reflection. but first, I had to convert `result` to `System.Data.Entity.Infrastructure.DbQuery`, then get internal property `InternalQuery` as `(System.Data.Entity.Internal.Linq.InternalQuery)`, and only then, use `ToTraceString()` – itsho Jul 08 '14 at 11:20
  • 9
    add reference to System.Data.Entity, System.Data.Objects.ObjectQuery exist in the above dll – Mahesh Oct 22 '14 at 07:05
  • will this `ToTraceString()` return the final query (with the parameters already plugged in) or will it return the query without the parameters? ie: will the query have variables like `p__linq__i`? – sports Feb 14 '15 at 22:12
  • also System.Data.Objects is no longer available in EF 6 – sports Feb 14 '15 at 22:18
  • 5
    @sports - re:EF 6, System.Data.Objects isn't removed.. it's actually here: System.Data.Entity.Core.Objects.ObjectQuery – bkwdesign Apr 24 '15 at 16:00
  • 69
    In EF6 you can just do `result.ToString()` – Scott Chamberlain Sep 02 '15 at 18:42
  • 4
    @ScottChamberlain It returns the query, but without the binding values. – David Ferenczy Rogožan Jan 08 '16 at 16:04
  • 1
    I'd like to get the `sql` commands for my `add` and `update` operations, It seems that these methods work only with `select` command? – Akbari Jan 19 '16 at 07:30
  • @NickBerardi, I guess that it should be `where x.id == 32`? Your code is `=`. –  Feb 21 '16 at 02:26
  • 7
    @NickBerardi This does not work in EF Core. What's the alternative for EF Core? – nam Sep 16 '16 at 04:12
  • 4
    Does not seem to work when the query is a DTO such as IQueryable Exception Message = "Unable to cast object of type 'System.Data.Entity.Infrastructure.DbQuery`1[My.Controllers.MyDto]' to type 'System.Data.Entity.Core.Objects.ObjectQuery'." – user1040323 Oct 13 '17 at 16:35
  • 2
    In EF6 using `((System.Data.Entity.Core.Objects.ObjectQuery)query).ToTraceString()` I have "threw an exception of type 'System.InvalidCastException'" message. why? Using 'query.ToString()' I can see all tree, but not SQL. – Glauco Cucchiar Mar 30 '18 at 14:57
  • 2
    That doesn't work in EF6; I had to change the cast to DbQuery, e.g.: `var sql = ((System.Data.Entity.Infrastructure.DbQuery)query).Sql;` – BrainSlugs83 Sep 06 '18 at 23:15
  • @BrainSlugs83 I do not see how that is going to give you the parameter value though. ( what is .Sql for ? ) – Tom Stickel Oct 02 '18 at 00:07
  • 1
    I had to use `(System.Data.Entity.Infrastructure.DbQuery)query).Sql` in EF 6.3.0, where `T` is the same as the `IQueryable` – Malte R Jun 30 '21 at 11:21
  • i have a query with parameters; and i can't see the real query with compiled parameters; ToString() and InternalQuery displays a query with parameters placeholders – user5629690 Sep 08 '22 at 08:20
  • your EF 6 didn't work for me on EFCore 6 but this did var sql = (query as Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable)?.DebugView?.Query; – JDPeckham Jul 02 '23 at 17:30
97

Starting with EF6.1 you can use Interceptors to register a database logger. See chapters "Interceptors" and "Logging Database Operations" to a File here

<configuration>
  <entityFramework>
    <interceptors> 
      <interceptor type="System.Data.Entity.Infrastructure.Interception.DatabaseLogger, EntityFramework"> 
        <parameters> 
          <parameter value="C:\Temp\LogOutput.txt"/> 
          <parameter value="true" type="System.Boolean"/> 
        </parameters> 
      </interceptor> 
    </interceptors>
  </entityFramework>
</configuration>
Ian Kemp
  • 28,293
  • 19
  • 112
  • 138
isepise
  • 1,123
  • 8
  • 6
88

If you are using a DbContext, you can do the following to get the SQL:

var result = from i in myContext.appEntities
             select new Model
             {
                 field = i.stuff,
             };
var sql = result.ToString();
Kirk Woll
  • 76,112
  • 22
  • 180
  • 195
Doug Clutter
  • 3,646
  • 2
  • 29
  • 31
  • 16
    `ToString()` will give you the query with variables in it, like `p__linq__0`, instead of the final values (eg: 34563 instead of `p__linq__0`) – sports Feb 14 '15 at 22:15
51

EF Core 5.0+

This loooong-awaited feature is available in EF Core 5.0! This is from the weekly status updates:

var query = context.Set<Customer>().Where(c => c.City == city);
Console.WriteLine(query.ToQueryString())

results in this output when using the SQL Server database provider:

DECLARE p0 nvarchar(4000) = N'London';

SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName],
[c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone],
[c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
WHERE [c].[City] = @__city_0

Notice that declarations for parameters of the correct type are also included in the output. This allows copy/pasting to SQL Server Management Studio, or similar tools, such that the query can be executed for debugging/analysis.

woohoo!!!

(Note: You will need using Microsoft.EntityFrameworkCore;)

Josh Withee
  • 9,922
  • 3
  • 44
  • 62
  • 3
    @ChristianFindlay [here](https://github.com/dotnet/efcore/blob/master/src/EFCore/Query/IQueryingEnumerable.cs) is the interface with the method and [here](https://github.com/dotnet/efcore/blob/master/src/EFCore/Extensions/EntityFrameworkQueryableExtensions.cs) is where it is included in EntityFrameworkQueryableExtensions. Are you using EF Core 5.0? – Josh Withee Jul 20 '20 at 04:20
  • 1
    If you are checking for the query in a watch or inspect window and you haven't added `using Microsoft.EntityFrameworkCore;` to your class you can call the extension method directly by using: `Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToQueryString(query);` – Heitor Marcos Feb 10 '22 at 19:34
31

Applicable for EF 6.0 and above: For those of you wanting to know more about the logging functionality and adding to the some of the answers already given.

Any command sent from the EF to the database can now be logged. To view the generated queries from EF 6.x, use the DBContext.Database.Log property

What Gets Logged

 - SQL for all different kinds of commands. For example:
    - Queries, including normal LINQ queries, eSQL queries, and raw queries from methods such as SqlQuery.
    - Inserts, updates, and deletes generated as part of SaveChanges
    - Relationship loading queries such as those generated by lazy loading
 - Parameters
 - Whether or not the command is being executed asynchronously
 - A timestamp indicating when the command started executing
 - Whether or not the command completed successfully, failed by throwing an exception, or, for async, was canceled
 - Some indication of the result value
 - The approximate amount of time it took to execute the command. Note that this is the time from sending the command to getting the result object back. It does not include time to read the results.

Example:

using (var context = new BlogContext()) 
{ 
    context.Database.Log = Console.Write; 

    var blog = context.Blogs.First(b => b.Title == "One Unicorn"); 

    blog.Posts.First().Title = "Green Eggs and Ham"; 

    blog.Posts.Add(new Post { Title = "I do not like them!" }); 

    context.SaveChangesAsync().Wait(); 
}

Output:

SELECT TOP (1)
    [Extent1].[Id] AS [Id],
    [Extent1].[Title] AS [Title]
    FROM [dbo].[Blogs] AS [Extent1]
    WHERE (N'One Unicorn' = [Extent1].[Title]) AND ([Extent1].[Title] IS NOT NULL)
-- Executing at 10/8/2013 10:55:41 AM -07:00
-- Completed in 4 ms with result: SqlDataReader

SELECT
    [Extent1].[Id] AS [Id],
    [Extent1].[Title] AS [Title],
    [Extent1].[BlogId] AS [BlogId]
    FROM [dbo].[Posts] AS [Extent1]
    WHERE [Extent1].[BlogId] = @EntityKeyValue1
-- EntityKeyValue1: '1' (Type = Int32)
-- Executing at 10/8/2013 10:55:41 AM -07:00
-- Completed in 2 ms with result: SqlDataReader

UPDATE [dbo].[Posts]
SET [Title] = @0
WHERE ([Id] = @1)
-- @0: 'Green Eggs and Ham' (Type = String, Size = -1)
-- @1: '1' (Type = Int32)
-- Executing asynchronously at 10/8/2013 10:55:41 AM -07:00
-- Completed in 12 ms with result: 1

INSERT [dbo].[Posts]([Title], [BlogId])
VALUES (@0, @1)
SELECT [Id]
FROM [dbo].[Posts]
WHERE @@ROWCOUNT > 0 AND [Id] = scope_identity()
-- @0: 'I do not like them!' (Type = String, Size = -1)
-- @1: '1' (Type = Int32)
-- Executing asynchronously at 10/8/2013 10:55:41 AM -07:00
-- Completed in 2 ms with result: SqlDataReader

To log to an external file:

using (var context = new BlogContext()) 
{  
    using (var sqlLogFile = new StreamWriter("C:\\temp\\LogFile.txt"))
    {          
         context.Database.Log = sqlLogFile.Write;     
         var blog = context.Blogs.First(b => b.Title == "One Unicorn"); 
         blog.Posts.First().Title = "Green Eggs and Ham"; 
         context.SaveChanges();
   }
}

More info here: Logging and Intercepting Database Operations

NullReference
  • 2,828
  • 2
  • 30
  • 33
26

You can do the following in EF 4.1:

var result = from x in appEntities
             where x.id = 32
             select x;

System.Diagnostics.Trace.WriteLine(result .ToString());

That will give you the SQL that was generated.

Capriols
  • 269
  • 3
  • 2
  • 1
    Point of fact, I believe this only works when the query returns an anonymous type. If it returns a custom type, the `ToString()` output is the namespace of that custom type. For example, if the above code was `select new CustomType { x = x.Name }`, the returned value would be something like `Company.Models.CustomType` instead of the generated SQL. – Chad Levy Sep 15 '11 at 09:57
  • 12
    This technique produces `System.Data.Objects.ObjectQuery``1[MyProject.Models.Product]` for me. – Carl G Nov 14 '12 at 17:42
  • 1
    @CarlG System.Data.Objects.ObjectQuery is not EF 4.1 (DbContext). Using DbContext it would be System.Data.Entity.Infrastructure.DbQuery`1[MyProject.Models.Product] which indeed outputs it's SQL on a call to "ToString()" – springy76 Feb 27 '13 at 12:37
  • This will give you the SQL that was generated, where, in the output window? which option from the dropdown? – JsonStatham Dec 19 '18 at 16:43
20

My answer addresses EF core. I reference this github issue, and the docs on configuring DbContext:

Simple

Override the OnConfiguring method of your DbContext class (YourCustomDbContext) as shown here to use a ConsoleLoggerProvider; your queries should log to the console:

public class YourCustomDbContext : DbContext
{
    #region DefineLoggerFactory
    public static readonly LoggerFactory MyLoggerFactory
        = new LoggerFactory(new[] {new ConsoleLoggerProvider((_, __) => true, true)});
    #endregion


    #region RegisterLoggerFactory
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder
            .UseLoggerFactory(MyLoggerFactory); // Warning: Do not create a new ILoggerFactory instance each time                
    #endregion
}

Complex

This Complex case avoids overriding the DbContext OnConfiguring method. , which is discouraged in the docs: "This approach does not lend itself to testing, unless the tests target the full database."

This Complex case uses:

  • The IServiceCollection in Startup class ConfigureServices method (instead of overriding the OnConfiguring method; the benefit is a looser coupling between the DbContext and the ILoggerProvider you want to use)
  • An implementation of ILoggerProvider (instead of using the ConsoleLoggerProvider implementation shown above; benefit is our implementation shows how we would log to File (I don't see a File Logging Provider shipped with EF Core))

Like this:

public class Startup

    public void ConfigureServices(IServiceCollection services)
    {
        ...
        var lf = new LoggerFactory();
        lf.AddProvider(new MyLoggerProvider());

        services.AddDbContext<YOUR_DB_CONTEXT>(optionsBuilder => optionsBuilder
                .UseSqlServer(connection_string)
                //Using the LoggerFactory 
                .UseLoggerFactory(lf));
        ...
    }
}

Here's the implementation of a MyLoggerProvider (and its MyLogger which appends its logs to a File you can configure; your EF Core queries will appear in the file.)

public class MyLoggerProvider : ILoggerProvider
{
    public ILogger CreateLogger(string categoryName)
    {
        return new MyLogger();
    }

    public void Dispose()
    { }

    private class MyLogger : ILogger
    {
        public bool IsEnabled(LogLevel logLevel)
        {
            return true;
        }

        public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
        {
            File.AppendAllText(@"C:\temp\log.txt", formatter(state, exception));
            Console.WriteLine(formatter(state, exception));
        }

        public IDisposable BeginScope<TState>(TState state)
        {
            return null;
        }
    } 
}
Barry MSIH
  • 3,525
  • 5
  • 32
  • 53
Nate Anderson
  • 18,334
  • 18
  • 100
  • 135
  • So...there is no begginers way of doing it? – Juan De la Cruz Feb 18 '18 at 00:07
  • 1
    @JuanDelaCruz I simplified my answer; try the simple alternative – Nate Anderson Feb 18 '18 at 00:27
  • 5
    Thank you for posting this. I an flabbergasted that there is no longer a way to do it in the immediate window in .NET Core. I don't want to write code, I just want to debug it. SQL profiler is obviously an option but that is still more complicated than it used to be – EGP Sep 15 '20 at 15:39
17

To have the query always handy, without changing code add this to your DbContext and check it on the output window in visual studio.

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        Database.Log = (query)=> Debug.Write(query);
    }

Similar to @Matt Nibecker answer, but with this you do not have to add it in your current code, every time you need the query.

Gerrie Pretorius
  • 3,381
  • 2
  • 31
  • 34
14

There are two ways:

  1. To view the SQL that will be generated, simply call ToTraceString(). You can add it into your watch window and set a breakpoint to see what the query would be at any given point for any LINQ query.
  2. You can attach a tracer to your SQL server of choice, which will show you the final query in all its gory detail. In the case of MySQL, the easiest way to trace the queries is simply to tail the query log with tail -f. You can learn more about MySQL's logging facilities in the official documentation. For SQL Server, the easiest way is to use the included SQL Server profiler.
Benjamin Pollack
  • 27,594
  • 16
  • 81
  • 105
12

I am doing integration test, and needed this to debug the generated SQL statement in Entity Framework Core 2.1, so I use DebugLoggerProvider or ConsoleLoggerProvider like so:

[Fact]
public async Task MyAwesomeTest
    {
        //setup log to debug sql queries
        var loggerFactory = new LoggerFactory();
        loggerFactory.AddProvider(new DebugLoggerProvider());
        loggerFactory.AddProvider(new ConsoleLoggerProvider(new ConsoleLoggerSettings()));

        var builder = new DbContextOptionsBuilder<DbContext>();
        builder
            .UseSqlServer("my connection string") //"Server=.;Initial Catalog=TestDb;Integrated Security=True"
            .UseLoggerFactory(loggerFactory);

        var dbContext = new DbContext(builder.Options);

        ........

Here is a sample output from Visual Studio console:

Sample SQL statement output

Rosdi Kasim
  • 24,267
  • 23
  • 130
  • 154
  • 1
    DebugLoggerPrivider and ConsoleLoggerProvider seem to exist only in .NET Core: https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.logging.debug.debugloggerprovider – Gabriel Magana Jun 20 '19 at 14:09
  • 2
    What is in `new ConsoleLoggerSettings()`? – Rokit Sep 10 '21 at 17:35
10

SQL Management Studio => Tools => SQL Server profiler

File => New Trace...

Use the Template => Blank

Event selection => T-SQL

Lefthandside check for: SP.StmtComplete

Column filters can be used to select a specific ApplicationName or DatabaseName

Start that profile running then trigger the query.

Click here for Source information

andrew pate
  • 3,833
  • 36
  • 28
7

Use Logging with Entity Framework Core 3.x

Entity Framework Core emits SQL via the logging system. There are only a couple of small tricks. You must specify an ILoggerFactory and you must specify a filter. Here is an example from this article

Create the factory:

var loggerFactory = LoggerFactory.Create(builder =>
{
    builder
    .AddConsole((options) => { })
    .AddFilter((category, level) =>
        category == DbLoggerCategory.Database.Command.Name
        && level == LogLevel.Information);
});

Tell the DbContext to use the factory in the OnConfiguring method:

optionsBuilder.UseLoggerFactory(_loggerFactory);

From here, you can get a lot more sophisticated and hook into the Log method to extract details about the executed SQL. See the article for a full discussion.

public class EntityFrameworkSqlLogger : ILogger
{
    #region Fields
    Action<EntityFrameworkSqlLogMessage> _logMessage;
    #endregion
    #region Constructor
    public EntityFrameworkSqlLogger(Action<EntityFrameworkSqlLogMessage> logMessage)
    {
        _logMessage = logMessage;
    }
    #endregion
    #region Implementation
    public IDisposable BeginScope<TState>(TState state)
    {
        return default;
    }
    public bool IsEnabled(LogLevel logLevel)
    {
        return true;
    }
    public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
    {
        if (eventId.Id != 20101)
        {
            //Filter messages that aren't relevant.
            //There may be other types of messages that are relevant for other database platforms...
            return;
        }
        if (state is IReadOnlyList<KeyValuePair<string, object>> keyValuePairList)
        {
            var entityFrameworkSqlLogMessage = new EntityFrameworkSqlLogMessage
            (
                eventId,
                (string)keyValuePairList.FirstOrDefault(k => k.Key == "commandText").Value,
                (string)keyValuePairList.FirstOrDefault(k => k.Key == "parameters").Value,
                (CommandType)keyValuePairList.FirstOrDefault(k => k.Key == "commandType").Value,
                (int)keyValuePairList.FirstOrDefault(k => k.Key == "commandTimeout").Value,
                (string)keyValuePairList.FirstOrDefault(k => k.Key == "elapsed").Value
            );
            _logMessage(entityFrameworkSqlLogMessage);
        }
    }
    #endregion
}
Christian Findlay
  • 6,770
  • 5
  • 51
  • 103
6
IQueryable query = from x in appEntities
                   where x.id = 32
                   select x;
var queryString = query.ToString();

Will return the sql query. Working using datacontext of EntityFramework 6

Gianluca Conte
  • 480
  • 4
  • 8
  • 7
    I just tried this and it traces out the object: `Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[System.Linq.IGrouping`2[System.Int32,String]]` instead of the actual query. Am I missing something or did you forget to mention something? – loganjones16 Feb 27 '19 at 22:11
  • You can just: `string query = (from x in appEntities where x.id = 32 select x).ToString();` – Nur.B Sep 16 '22 at 07:52
6

Necromancing.
This page is the first search result when searching for a solution for any .NET Framework, so here as a public service, how it's done in EntityFrameworkCore (for .NET Core 1 & 2):

var someQuery = (
    from projects in _context.projects
    join issues in _context.issues on projects.Id equals issues.ProjectId into tmpMapp
    from issues in tmpMapp.DefaultIfEmpty()
    select issues
) //.ToList()
;

// string sql = someQuery.ToString();
// string sql = Microsoft.EntityFrameworkCore.IQueryableExtensions.ToSql(someQuery);
// string sql = Microsoft.EntityFrameworkCore.IQueryableExtensions1.ToSql(someQuery);
// using Microsoft.EntityFrameworkCore;
string sql = someQuery.ToSql();
System.Console.WriteLine(sql);

And then these extension methods (IQueryableExtensions1 for .NET Core 1.0, IQueryableExtensions for .NET Core 2.0) :

using System;
using System.Linq;
using System.Reflection;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.EntityFrameworkCore.Query.Internal;
using Microsoft.EntityFrameworkCore.Storage;
using Remotion.Linq.Parsing.Structure;


namespace Microsoft.EntityFrameworkCore
{

    // https://stackoverflow.com/questions/1412863/how-do-i-view-the-sql-generated-by-the-entity-framework
    // http://rion.io/2016/10/19/accessing-entity-framework-core-queries-behind-the-scenes-in-asp-net-core/

    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 PropertyInfo NodeTypeProviderField =
            QueryCompilerTypeInfo.DeclaredProperties.Single(x => x.Name == "NodeTypeProvider");

        private static readonly MethodInfo CreateQueryParserMethod =
            QueryCompilerTypeInfo.DeclaredMethods.First(x => x.Name == "CreateQueryParser");

        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
        {
            if (!(query is EntityQueryable<TEntity>) && !(query is InternalDbSet<TEntity>))
            {
                throw new ArgumentException("Invalid query");
            }

            var queryCompiler = (QueryCompiler) QueryCompilerField.GetValue(query.Provider);
            var nodeTypeProvider = (INodeTypeProvider) NodeTypeProviderField.GetValue(queryCompiler);
            var parser = (IQueryParser) CreateQueryParserMethod.Invoke(queryCompiler, new object[] {nodeTypeProvider});
            var queryModel = parser.GetParsedQuery(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;
        }
    }



    public class IQueryableExtensions1
    {
        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 PropertyInfo NodeTypeProviderField =
            QueryCompilerTypeInfo.DeclaredProperties.Single(x => x.Name == "NodeTypeProvider");

        private static readonly MethodInfo CreateQueryParserMethod =
            QueryCompilerTypeInfo.DeclaredMethods.First(x => x.Name == "CreateQueryParser");

        private static readonly FieldInfo DataBaseField =
            QueryCompilerTypeInfo.DeclaredFields.Single(x => x.Name == "_database");

        private static readonly FieldInfo QueryCompilationContextFactoryField = typeof(Database).GetTypeInfo()
            .DeclaredFields.Single(x => x.Name == "_queryCompilationContextFactory");


        public static string ToSql<TEntity>(IQueryable<TEntity> query) where TEntity : class
        {
            if (!(query is EntityQueryable<TEntity>) && !(query is InternalDbSet<TEntity>))
            {
                throw new ArgumentException("Invalid query");
            }

            var queryCompiler = (IQueryCompiler) QueryCompilerField.GetValue(query.Provider);

            var nodeTypeProvider = (INodeTypeProvider) NodeTypeProviderField.GetValue(queryCompiler);
            var parser =
                (IQueryParser) CreateQueryParserMethod.Invoke(queryCompiler, new object[] {nodeTypeProvider});
            var queryModel = parser.GetParsedQuery(query.Expression);
            var database = DataBaseField.GetValue(queryCompiler);
            var queryCompilationContextFactory =
                (IQueryCompilationContextFactory) QueryCompilationContextFactoryField.GetValue(database);
            var queryCompilationContext = queryCompilationContextFactory.Create(false);
            var modelVisitor = (RelationalQueryModelVisitor) queryCompilationContext.CreateQueryModelVisitor();
            modelVisitor.CreateQueryExecutor<TEntity>(queryModel);
            var sql = modelVisitor.Queries.First().ToString();

            return sql;
        }


    }


}
Stefan Steiger
  • 78,642
  • 66
  • 377
  • 442
  • I am using EF Core 2.0.1 and the above suggestion results in: System.InvalidCastException: 'Unable to cast object of type Microsoft.EntityFrameworkCore.Query.Internal.InMemoryQueryModelVisitor' to type ''Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor'` for the line: `var modelVisitor = (RelationalQueryModelVisitor) queryCompilationContext.CreateQueryModelVisitor();` – Chris Wolf Apr 18 '18 at 16:52
  • 2
    @ChrisWolf if you follow the original author's gist you can find somebody who [provided an updated version of that extension method](https://gist.github.com/rionmonster/2c59f449e67edf8cd6164e9fe66c545a#gistcomment-2372507). Worked for me. – Felix K. Oct 05 '18 at 20:24
5

Well, I am using Express profiler for that purpose at the moment, the drawback is that it only works for MS SQL Server. You can find this tool here: https://expressprofiler.codeplex.com/

VincentZHANG
  • 757
  • 1
  • 13
  • 31
5

While there are good answers here, none solved my problem completely (I wished to get the entire SQL statement, including Parameters, from the DbContext from any IQueryable. The following code does just that. It is a combination of code snippets from Google. I have only tested it with EF6+.

Just an aside, this task took me way longer than I thought it would. Abstraction in Entity Framework is a bit much, IMHO.

First the using. You will need an explicit reference to 'System.Data.Entity.dll'.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.SqlClient;
using System.Data.Common;
using System.Data.Entity.Core.Objects;
using System.Data.Entity;
using System.Data;
using System.Data.Entity.Infrastructure;
using System.Reflection;

The following class converts an IQueryable into a DataTable. Modify as your need may be:

public class EntityFrameworkCommand
{
    DbContext Context;

    string SQL;

    ObjectParameter[] Parameters;

    public EntityFrameworkCommand Initialize<T>(DbContext context, IQueryable<T> query)
    {
        Context = context;
        var dbQuery = query as DbQuery<T>;
        // get the IInternalQuery internal variable from the DbQuery object
        var iqProp = dbQuery.GetType().GetProperty("InternalQuery", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
        var iq = iqProp.GetValue(dbQuery, null);
        // get the ObjectQuery internal variable from the IInternalQuery object
        var oqProp = iq.GetType().GetProperty("ObjectQuery", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
        var objectQuery = oqProp.GetValue(iq, null) as ObjectQuery<T>;
        SQL = objectQuery.ToTraceString();
        Parameters = objectQuery.Parameters.ToArray();
        return this;
    }

    public DataTable GetData()
    {
        DataTable dt = new DataTable();
        var connection = Context.Database.Connection;
        var state = connection.State;
        if (!(state == ConnectionState.Open))
            connection.Open();
        using (var cmd = connection.CreateCommand())
        {
            cmd.CommandText = SQL;
            foreach (var p in Parameters)
            {
                var param = cmd.CreateParameter();
                param.Name = "@" + p.Name;
                param.Value = p.Value;
                cmd.Parameters.Add(param);
            }
            using (var da = DbProviderFactories.GetFactory(connection).CreateDataAdapter())
            {
                da.SelectCommand = cmd;
                da.Fill(dt);
            }
        }
        if (!(state == ConnectionState.Open))
            connection.Close();
        return dt;
    }
}

To use, simply call it as below:

var context = new MyContext();
var data = ....//Query, return type can be anonymous
    .AsQueryable();
var dt = new EntityFrameworkCommand()
    .Initialize(context, data)
    .GetData();
Jeremy Morren
  • 615
  • 9
  • 23
  • 1
    Great answer.Instead of `new SqlParameter`, you should use `DbProviderFactories.GetFactory(connection).CreateParameter()` so that it is compatible with other database providers. – FKDev Jan 12 '21 at 08:34
4

Starting from Entity Framework Core 5.0+ one can simply override the OnConfiguring method in the DbContext once for logging. This works also for Single() or Any() queries.

For logging to debug window:

public class ExampleDbContext : DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        // using System.Diagnostics;
        optionsBuilder.LogTo(message => Debug.WriteLine(message));
    }
}

For logging to console:

public class ExampleDbContext : DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.LogTo(Console.WriteLine);
    }
}

See here for more details including log levels and filtering: https://learn.microsoft.com/en-us/ef/core/logging-events-diagnostics/simple-logging

Baccata
  • 473
  • 1
  • 7
  • 15
  • After the .LogTo you can tell it to log SensitiveData, for dev, or it will hide parameterized values. Here is a filtered log example: EFCore 6 .LogTo(Console.Writeline, new [] {DbLoggerCategory.Database.Command.Name }, LogLevel.Information) .Enable SensitiveDataLogging(); – CANDIMAN Aug 14 '22 at 00:16
3

For me, using EF6 and Visual Studio 2015 I entered query in the immediate window and it gave me the generated SQL Statement

Jonas Stawski
  • 6,682
  • 6
  • 61
  • 106
2

In my case for EF 6+, instead of using this in the Immediate Window to find the query string:

var sql = ((System.Data.Entity.Core.Objects.ObjectQuery)query).ToTraceString();

I ended up having to use this to get the generated SQL command:

var sql = ((System.Data.Entity.Infrastructure.DbQuery<<>f__AnonymousType3<string,string,string,short,string>>)query).ToString();

Of course your anonymous type signature might be different.

HTH.

user8128167
  • 6,929
  • 6
  • 66
  • 79
2

I've just done this:

IQueryable<Product> query = EntitySet.Where(p => p.Id == id);
Debug.WriteLine(query);

And the result shown in the Output:

SELECT 
    [Extent1].[Id] AS [Id], 
    [Extent1].[Code] AS [Code], 
    [Extent1].[Name] AS [Name], 
    [Extent2].[Id] AS [Id1], 
    [Extent2].[FileName] AS [FileName], 
    FROM  [dbo].[Products] AS [Extent1]
    INNER JOIN [dbo].[PersistedFiles] AS [Extent2] ON [Extent1].[PersistedFileId] = [Extent2].[Id]
    WHERE [Extent1].[Id] = @p__linq__0
  • 1
    Yes, but i believe that Nobody wants to see the p__linq__i , but the real values – Tom Stickel Oct 02 '18 at 00:30
  • This way still works in EF 6 and it will be helpful if you only care about what the query structure look like. In my case the project I create the IQueryable object does not have reference to System.Data.Entity nor I want to add it just for debugging purpose. So this method worked just fine. – wctiger Nov 08 '18 at 22:05
2

Entity Framework 4 Solution

Most of the answers here were EF6-specific. Here's one for those of you still using EF4.

This method replaces the @p__linq__0/etc. parameters with their actual values, so you can just copy and paste the output into SSMS and run it or debug it.

    /// <summary>
    /// Temporary debug function that spits out the actual SQL query LINQ is generating (with parameters)
    /// </summary>
    /// <param name="q">IQueryable object</param>
    private string Debug_GetSQLFromIQueryable<T>(IQueryable<T> q)
    {
        System.Data.Objects.ObjectQuery oq = (System.Data.Objects.ObjectQuery)q;
        var result = oq.ToTraceString();
        List<string> paramNames = new List<string>();
        List<string> paramVals = new List<string>();
        foreach (var parameter in oq.Parameters)
        {
            paramNames.Add(parameter.Name);
            paramVals.Add(parameter.Value == null ? "NULL" : ("'" + parameter.Value.ToString() + "'"));
        }
        //replace params in reverse order, otherwise @p__linq__1 incorrectly replaces @p__linq__10 for instance
        for (var i = paramNames.Count - 1; i >= 0; i--)
        {
            result = result.Replace("@" + paramNames[i], paramVals[i]);
        }
        return result;
    }
jramm
  • 751
  • 1
  • 8
  • 26
1

If you want to have parameter values (not only @p_linq_0 but also their values) too, you can use IDbCommandInterceptor and add some logging to ReaderExecuted method.

Palec
  • 12,743
  • 8
  • 69
  • 138
michal.jakubeczy
  • 8,221
  • 1
  • 59
  • 63
1

For me

result.ToQueryString()

wasn't working because I was using .SingleAsync() or .ToListAsync()

So when I removed .SingleAsync() and separated it out into two statements, it worked

Example before

var result = await Context.Work.AsNoTracking().Where(x => x.WorkId == workId).SingleAsync();

Example after

var query  = Context.Work.AsNoTracking().Where(x => x.WorkId == workId);

Debug.WriteLine(query.ToQueryString()); // Separated into two pieces so I can see what the query is
    
var result = await query.SingleAsync();
TheJonz
  • 394
  • 2
  • 11