web-dev-qa-db-ja.com

Entity Frameworkによって生成されたSQLを表示する方法

エンティティフレームワークによって生成されたSQLを表示する方法

(私の特定のケースでは、私はmysqlプロバイダーを使用しています - それが問題であれば)

540
nos

次のことができます。

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を与えるでしょう。

433
Nick Berardi

Entity Framework 6以降を使用している場合、(私が行ったように)Visual Studioで出力SQLを表示したい場合は、新しいロギング/インターセプト機能を使用する必要があります。

次の行を追加すると、Visual Studioの出力パネルに、生成されたSQLが(追加の実行関連の詳細とともに)吐出されます。

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/

注意:プロジェクトをデバッグモードで実行していることを確認してください。

855
Matt Nibecker

EF6.1以降では、インターセプターを使用してデータベースロガーを登録できます。章「インターセプタ」および「データベース操作のファイルへのログ記録」を参照してください ここ

<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>
74
isepise

DbContextを使用している場合は、次のようにしてSQLを取得できます。

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

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

ここにもっと情報があります: データベース操作のログ記録と傍受

21
NullReference

EF 4.1では、次のことが可能です。

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

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

それはあなたに生成されたSQLを与えるでしょう。

17
Capriols

2つの方法があります。

  1. 生成されるSQLを表示するには、単にToTraceString()を呼び出します。あなたのウォッチウィンドウにそれを追加して、どんなLINQクエリのためにどんなクエリがどんな時点でもあるかを見るためにブレークポイントを設定することができます。
  2. あなたが選択したあなたのSQLサーバーにトレーサーを付けることができます。 MySQLの場合、クエリを追跡する最も簡単な方法は、単にクエリログをtail -fで調整することです。 MySQLのロギング機能の詳細については、 公式ドキュメント を参照してください。 SQL Serverの場合、最も簡単な方法は、付属のSQL Serverプロファイラを使用することです。
16

私の答えはEF core に対応しています。私はこの github issue 、および configure DbContext に関するドキュメントを参照します。

単純

ConsoleLoggerProviderを使用するには、OnConfiguringクラスのDbContextメソッド(YourCustomDbContextここに表示 をオーバーライドします。あなたの質問はコンソールにログするべきです:

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
}

複素数

この複雑なケースでは、ドキュメントでは推奨されていない DbContextOnConfiguringメソッド をオーバーライドすることは避けています。

この複雑なケースでは、

  • IServiceCollectionクラスのStartupメソッドConfigureServicesメソッド(OnConfiguringメソッドをオーバーライドするのではなく、利点はDbContextと使用するILoggerProviderの間の疎結合です)
  • ILoggerProviderの実装(上記のConsoleLoggerProvider実装を使用する代わりに、私たちの実装はどのようにFileにログを記録するかを示しています( EF Coreに同梱されているFile Logging Provider ))

このような:

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(およびそのログを設定可能なFileに追加するMyLoggerの実装です。EFCoreクエリはファイルに表示されます)。

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
The Red Pea

コードを変更せずにクエリを常に便利にするには、これをDbContextに追加して、ビジュアルスタジオの出力ウィンドウで確認します。

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

@Matt Nibeckerの回答に似ていますが、これを使用すると、クエリが必要になるたびに現在のコードに追加する必要はありません。

6

さて、私は現時点でその目的のためにExpressプロファイラーを使用しています、欠点はそれがMS SQL Serverにしか機能しないということです。あなたはここでこのツールを見つけることができます: https://expressprofiler.codeplex.com/ /

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

SQLクエリを返します。 EntityFramework 6のデータコンテキストを使った作業

4
Gianluca Conte

私は統合テストを行っていて、Entity Framework Core 2.1で生成されたSQL文をデバッグするためにこれを必要としていたので、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

4
Rosdi Kasim

私にとっては、EF6とVisual Studio 2015を使用して、イミディエイトウィンドウにqueryと入力すると、生成されたSQLステートメントが表示されます。

2
Jonas Stawski

私はちょうどこれをやった:

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
2
Daniel Camargo

私のEF 6+の場合は、イミディエイトウィンドウでこれを使用してクエリ文字列を見つけるのではなく、

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

ネクロマンシング.
このページは、任意の.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);

そして、これらの拡張メソッド(.NET Core 1.0の場合はIQueryableExtensions1、.NET Core 2.0の場合はIQueryableExtensions 1):

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

パラメータ値(@p_linq_0だけでなくそれらの値も)も必要な場合は、 IDbCommandInterceptor を使用してReaderExecutedメソッドにログを追加します。

1
jabko87

SQL Management Studio =>ツール=> SQL Serverプロファイラ

ファイル=>新しいトレース...

テンプレートを使用=>空白

イベント選択=> T-SQL

左手側のチェック:SP.StmtComplete

列フィルタを使用して、特定のApplicationNameまたはDatabaseNameを選択できます。

そのプロファイルの実行を開始してから、照会を起動します。

ここをクリックしてソース情報

1
andrew pate