включить запрос linq в raw sql [duplicate]

Это не существует, но вы можете использовать JSON.parse(JSON.stringify(jobs))

504
задан Sr Julien 6 October 2016 в 14:55
поделиться

17 ответов

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

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

409
ответ дан Chris Moschini 17 August 2018 в 17:30
поделиться
  • 1
    Вы не получите SQL для запросов, заканчивающихся на .Single (), .Count (), .Any () и т. Д. Таким образом. – springy76 27 February 2013 в 14:31
  • 2
    Это потому, что после запуска .Single() ваш объект больше не будет IQueryable, я думаю. – Suhas 19 June 2013 в 08:39
  • 3
    с EF6 я мог получить его только с отражением. но сначала мне пришлось преобразовать result в System.Data.Entity.Infrastructure.DbQuery<T>, а затем получить внутреннее свойство InternalQuery как (System.Data.Entity.Internal.Linq.InternalQuery<T>), и только тогда используйте ToTraceString() – itsho 8 July 2014 в 12:20
  • 4
    добавить ссылку на System.Data.Entity, System.Data.Objects.ObjectQuery существует в приведенной выше dll – Mahesh 22 October 2014 в 08:05
  • 5
    В EF6 вы можете просто сделать result.ToString() – Scott Chamberlain 2 September 2015 в 18:42

Мой ответ адресован ядру EF. Я ссылаюсь на эту проблему github , а документы на настройке 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                
    #endregion
}

Complex

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

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

  • IServiceCollection в методе Startup класса 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 В файле появятся основные запросы.)

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;
        }
    } 
}
4
ответ дан Barry MSIH 17 August 2018 в 17:30
поделиться
  • 1
    Итак ... у новичков нет способа сделать это? – Juan De la Cruz 18 February 2018 в 01:07
  • 2
    @JuanDelaCruz Я упростил свой ответ; попробуйте простую альтернативу – The Red Pea 18 February 2018 в 01:27

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

  1. Чтобы просмотреть SQL, который будет сгенерирован, просто вызовите ToTraceString(). Вы можете добавить его в окно просмотра и установить точку останова, чтобы узнать, какой запрос будет в любой заданной точке для любого запроса LINQ.
  2. Вы можете прикрепить трассировщик к вашему SQL-серверу по выбору, который покажет вы последний запрос во всех деталях. В случае с MySQL самый простой способ отслеживания запросов - просто закрыть журнал запросов с помощью tail -f. Вы можете узнать больше о средствах регистрации MySQL в официальной документации . Для SQL Server самым простым способом является использование включенного профилировщика SQL Server.
14
ответ дан Benjamin Pollack 17 August 2018 в 17:30
поделиться
  • 1
    Что такое ToTraceString? – nos 11 September 2009 в 20:48
  • 2
    ObjectQuery, как заметил Ник сразу после того, как я опубликовал свой ответ. – Benjamin Pollack 11 September 2009 в 21:55
  • 3
    SQL Server Profiler захватывает первые 4000 символов, но запросы EF могут быть намного длиннее. – John Robertson 27 February 2014 в 22:57

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

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

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

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

14
ответ дан Capriols 17 August 2018 в 17:30
поделиться
  • 1
    Фактически, я считаю, что это работает только тогда, когда запрос возвращает анонимный тип. Если он возвращает пользовательский тип, выход ToString() является пространством имен этого настраиваемого типа. Например, если приведенный выше код был select new CustomType { x = x.Name }, возвращаемое значение было бы чем-то вроде Company.Models.CustomType вместо сгенерированного SQL. – Chad Levy 15 September 2011 в 10:57
  • 2
    Этот метод дает мне System.Data.Objects.ObjectQuery``1[MyProject.Models.Product]. – Carl G 14 November 2012 в 19:42
  • 3
    @CarlG System.Data.Objects.ObjectQuery не является EF 4.1 (DbContext). Используя DbContext, это будет System.Data.Entity.Infrastructure.DbQuery`1 [MyProject.Models.Product], который действительно выводит его SQL при вызове ToString () & quot; – springy76 27 February 2013 в 14:37

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

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

И результат, показанный в 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
ответ дан Daniel Camargo 17 August 2018 в 17:30
поделиться

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

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

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

4
ответ дан Gerrie Pretorius 17 August 2018 в 17:30
поделиться
IQueryable query = from x in appEntities
                   where x.id = 32
                   select x;
var queryString = query.ToString();

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

4
ответ дан Gianluca Conte 17 August 2018 в 17:30
поделиться

Начиная с 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>
68
ответ дан isepise 17 August 2018 в 17:30
поделиться

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

2
ответ дан Jonas Stawski 17 August 2018 в 17:30
поделиться

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

var result = from i in myContext.appEntities
             select new Model
             {
                 field = i.stuff,
             };
var sql = result.ToString();
71
ответ дан Kirk Woll 17 August 2018 в 17:30
поделиться
  • 1
    ToString() предоставит вам запрос с переменными в нем, например p__linq__0, вместо окончательных значений (например: 34563 вместо p__linq__0) – sports 14 February 2015 в 23:15

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

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

13
ответ дан NullReference 17 August 2018 в 17:30
поделиться

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

1
ответ дан Palec 17 August 2018 в 17:30
поделиться

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

782
ответ дан PussInBoots 17 August 2018 в 17:30
поделиться
  • 1
    Этот ответ заслуживает большей любви (если вы используете EF6 +) - отличное дополнение к отладке, просто добавьте его в конструктор DBContext (this.Database.Log = ...) – keithl8041 7 February 2014 в 14:54
  • 2
    Убедитесь, что вы запускаете проект в режиме DEBUG MODE, проверьте, есть ли элемент «Отладка». выбрал в поле со списком на панели «Вывод», а также проверить, не отлаживается ли ваш отладочный запрос на «Немедленный» («Инструменты» и «Параметры» и «Отладка»). Перенаправить все текст окна вывода в окно «Немедленное окно») – rkawano 21 May 2014 в 18:41
  • 3
    есть ли способ заставить это включать значения переменных непосредственно в сгенерированный sql? Немного боль с большими. – Chris 28 June 2014 в 08:02
  • 4
    @Matt Nibecker Это не работает в EF Core. Какая альтернатива для EF Core? – nam 16 September 2016 в 04:13
  • 5
    – Brandon Barkley 16 August 2017 в 17:35

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


    }


}
1
ответ дан Stefan Steiger 17 August 2018 в 17:30
поделиться
  • 1
    Я использую EF Core 2.0.1, а приведенные выше результаты предложения: System.InvalidCastException: «Невозможно наложить объект типа Microsoft.EntityFrameworkCore.Query.Internal.InMemoryQueryModelVisitor», чтобы набрать «Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor'` для строка: var modelVisitor = (RelationalQueryModelVisitor) queryCompilationContext.CreateQueryModelVisitor(); – Chris Wolf 18 April 2018 в 16:52
  • 2
    – B12Toaster 5 October 2018 в 20:24

В моем случае для 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();

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

HTH.

2
ответ дан user8128167 17 August 2018 в 17:30
поделиться

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

4
ответ дан VincentZHANG 17 August 2018 в 17:30
поделиться
1
ответ дан Rosdi Kasim 29 October 2018 в 17:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: