Подтвердить что ты не робот

Как просмотреть SQL, созданный платформой Entity Framework?

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

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

4b9b3361

Ответ 1

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

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, который был сгенерирован.

Ответ 2

Для тех, кто использует 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/

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

Ответ 3

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

var result = from i in myContext.appEntities
             select new Model
             {
                 field = i.stuff,
             };
var sql = result.ToString();

Ответ 4

Начиная с 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>

Ответ 5

Существует два способа:

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

Ответ 6

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

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

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

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

Ответ 7

Применимо для 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();
   }
}

Дополнительная информация здесь: Запись и перехват операций с базой данных

Ответ 8

Хорошо, я использую для этой цели экспресс-профайлер, недостатком является то, что он работает только для MS SQL Server. Вы можете найти этот инструмент здесь: https://expressprofiler.codeplex.com/

Ответ 9

IQueryable query = from x in appEntities
                   where x.id = 32
                   select x;
var queryString = query.ToString();

Вернет запрос sql. Работа с использованием datacontext для EntityFramework 6

Ответ 10

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

Простой

Отмените метод 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
            //.UseSqlServer("...");
    #endregion
}

Комплекс

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

В этом сложном случае используется:

  • Метод IServiceCollection in Startup class ConfigureServices (вместо того, чтобы переопределять метод OnConfiguring, преимущество - ослабление связи между DbContext и ILoggerProvider, которые вы хотите использовать).
  • Реализация ILoggerProvider (вместо использования реализации ConsoleLoggerProvider, показанной выше; преимущество - наша реализация показывает, как мы будем регистрироваться в File (я не вижу поставщик регистрации файлов, поставляемый с 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;
        }
    } 
}

Ответ 11

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

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

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

Ответ 12

В моем случае для EF 6+ вместо использования этого в окне Immediate для поиска строки запроса:

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

Мне пришлось использовать это, чтобы получить сгенерированную команду SQL:

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

Конечно, ваша подпись анонимного типа может отличаться.

НТН.

Ответ 13

Я только что сделал это:

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

И результат, показанный в Вывод:

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

Ответ 14

Для меня, используя EF6 и Visual Studio 2015, я ввел query в непосредственное окно и дал мне сгенерированное выражение SQL

Ответ 15

Если вы хотите иметь значения параметров (не только @p_linq_0, но и их значения), вы можете использовать IDbCommandInterceptor и добавьте несколько протоколов в метод ReaderExecuted.

Ответ 16

Necromancing.

Эта страница является первым результатом поиска при поиске решения для любой платформы .NET Framework, поэтому здесь, в качестве публичной службы, как это делается в EntityFramework Core (для .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);

И затем эти методы расширения (IQueryableExtensions1 для .NET Core 1.0, IQueryableExtensions для .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/info/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;
        }


    }


}