Как посмотреть SQL, сгенерированный Entity Framework? - PullRequest
547 голосов
/ 11 сентября 2009

Как просмотреть SQL, сгенерированный структурой сущностей?

(В моем конкретном случае я использую провайдер mysql - если это имеет значение)

Ответы [ 18 ]

865 голосов
/ 24 декабря 2013

Для тех, кто использует Entity Framework 6 и выше, если вы хотите просмотреть выходной SQL в Visual Studio (как я сделал), вы должны использовать новую функцию ведения журнала / перехвата.

Добавление следующей строки приведет к тому, что сгенерированный SQL (вместе с дополнительными подробностями, связанными с выполнением) выпадет на панели вывода Visual Studio:

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

Больше информации о входе в EF6 в этой замечательной серии блогов: http://blog.oneunicorn.com/2013/05/08/ef6-sql-logging-part-1-simple-logging/

Примечание. Убедитесь, что проект запущен в режиме отладки.

436 голосов
/ 11 сентября 2009

Вы можете сделать следующее:

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

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

или в EF6:

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

Это даст вам сгенерированный SQL.

76 голосов
/ 11 октября 2012

Если вы используете DbContext, вы можете сделать следующее, чтобы получить SQL:

var result = from i in myContext.appEntities
             select new Model
             {
                 field = i.stuff,
             };
var sql = result.ToString();
75 голосов
/ 07 июля 2014

Начиная с EF6.1, вы можете использовать Interceptors для регистрации регистратора базы данных. См. Главы "Перехватчики" и "Ведение журнала операций базы данных" в файле здесь

<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>
21 голосов
/ 16 августа 2016

Применимо для EF 6.0 и выше: Для тех из вас, кто хочет узнать больше о функциональных возможностях ведения журнала и добавить некоторые ответы, которые уже даны.

Любая команда, отправленная из EF в базу данных, теперь может быть зарегистрирована. Чтобы просмотреть сгенерированные запросы из EF 6.x, используйте DBContext.Database.Log property

Что регистрируется

 - 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.

Пример:

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(); 
}

Выход:

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

Для входа во внешний файл:

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();
   }
}

Подробнее здесь: Ведение журнала и перехват операций с базой данных

17 голосов
/ 01 сентября 2011

В EF 4.1 вы можете выполнять следующие действия:

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

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

Это даст вам сгенерированный SQL.

16 голосов
/ 11 сентября 2009

Есть два способа:

  1. Чтобы просмотреть SQL, который будет сгенерирован, просто позвоните ToTraceString(). Вы можете добавить его в окно просмотра и установить точку останова, чтобы увидеть, каким будет запрос в любой заданной точке для любого запроса LINQ.
  2. Вы можете прикрепить трассировщик к вашему выбранному SQL-серверу, который покажет вам окончательный запрос во всех его подробностях. В случае с MySQL самый простой способ отследить запросы - просто привязать журнал запросов к tail -f. Вы можете узнать больше о средствах ведения журнала MySQL в официальной документации . Для SQL Server самый простой способ - использовать включенный профилировщик SQL Server.
11 голосов
/ 01 июня 2017

Мой адрес ответа EF core . Я упоминаю эту проблему github и документы по , конфигурирующие DbContext:

Simple

Переопределите метод OnConfiguring вашего DbContext класса (YourCustomDbContext) , как показано здесь , чтобы использовать ConsoleLoggerProvider; Ваши запросы должны войти в консоль:

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

В этом сложном случае избегается переопределение метода DbContext OnConfiguring. , который не рекомендуется в документах: «Этот подход не подходит для тестирования, если тесты не нацелены на полную базу данных».

Этот сложный случай использует:

  • Метод IServiceCollection в Startup класс ConfigureServices (вместо переопределения метода OnConfiguring; преимуществом является более слабая связь между DbContext и ILoggerProvider, которые вы хотите использовать)
  • Реализация ILoggerProvider (вместо того, чтобы использовать реализацию ConsoleLoggerProvider, показанную выше; преимущество заключается в том, что наша реализация показывает, как мы ведем журнал в файл (я не вижу провайдера регистрации файлов, поставляемого с EF Core ))

Вот так:

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));
        ...
    }
}

Вот реализация MyLoggerProvider (и его MyLogger, который добавляет свои журналы в файл, который вы можете настроить; ваши запросы EF Core появятся в файле.)

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;
        }
    } 
}
6 голосов
/ 21 января 2017

Чтобы запрос всегда был под рукой, без изменения кода добавьте это в свой DbContext и проверьте его в окне вывода в Visual Studio.

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

Аналогично ответу @Matt Nibecker, но при этом вам не нужно добавлять его в текущий код каждый раз, когда вам нужен запрос.

4 голосов
/ 07 октября 2018

Я делаю интеграционный тест, и он мне нужен для отладки сгенерированного оператора SQL в Entity Framework Core 2.1, поэтому я использую DebugLoggerProvider или ConsoleLoggerProvider, например:

[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);

        ........

Вот пример вывода с консоли Visual Studio:

Sample SQL statement output

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...