Entity Frameworkによって生成されたSQLを表示するにはどうすればよいですか?


624

エンティティフレームワークによって生成されたSQLを表示するにはどうすればよいですか?

(私の特定のケースでは、mysqlプロバイダーを使用しています-必要な場合)


1
この MSDNマガジンの記事では、Entity Framework 4
Arveの

2
リンクされた「重複する」質問はLINQ to SQLに関するものなので、実際には重複していません。
ジュルメル

2
デバッガーの下で実行すると、IntelliTraceは、結果なしではあるが、行われたSQLクエリを表示します。
ivan_pozdeev 2014年

開発中のSQLを確認したい場合は、LINQPadを使用できます。結果でLINQクエリを実行すると、実行されたSQLステートメントを示すSQLタブが表示されます。mySQLの場合、ドライバーをインストールする必要があります。使用可能なmySQLデータベースがありませんが、動作するはずです。
グリゴラン2015

回答:


472

次のことができます。

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が提供されます。


20
.Single()、. Count()、. Any()などで終わるクエリに対してSQLをそのまま使用することはありません。
springy76 2013

24
それは.Single()あなたのオブジェクトを実行した後、IQueryable私はもう推測しないからです。
Suhas 2013年

11
EF6では、リフレクションだけでそれを得ることができました。しかし、最初にに変換resultSystem.Data.Entity.Infrastructure.DbQuery<T>、次に内部プロパティをInternalQueryとして取得する必要があり、それを(System.Data.Entity.Internal.Linq.InternalQuery<T>)使用する必要がありますToTraceString()
itho

9
System.Data.Entityへの参照を追加します。System.Data.Objects.ObjectQueryは上記のDLLに存在します
Mahesh

54
EF6でできることresult.ToString()
Scott Chamberlain、

956

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/

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


107
この回答は、より多くの愛に値します(EF6 +を使用している場合)-すばらしいデバッグ追加、それをDBContextコンストラクター(this.Database.Log = ...)に追加するだけ
keithl8041

21
プロジェクトをデバッグモードで実行していることを確認し、[出力]ペインのコンボボックスで[デバッグ]が選択されているかどうかを確認し、デバッグがイミディエイトにリダイレクトされていないかどうかを確認します([ツール]> [オプション]> [デバッグ]> [すべての出力ウィンドウのテキストをイミディエイトにリダイレクト]ウィンドウ)
rkawano 2014年

5
これを取得した変数の値を生成されたSQLに直接含める方法はありますか?大きなものとのちょっとした痛み。
クリス

22
@Matt NibeckerこれはEF Coreでは機能しません。EF Coreの代替は何ですか?
ナム

9
警告:開発でのみ実行することを意図してこれを実装しました。テスト環境に展開すると、IISワーカープロセスでメモリリークが突然発生し始めました。メモリプロファイリングの後、明示的なGCでもエンティティコンテキストオブジェクトを収集していないことがわかりました(そう、それらはステートメントを使用していたのです)。この行を削除すると、すべて正常に戻りました。したがって、これは優れたツールですが、開発用のアプリにのみ組み込むようにしてください。
Brandon Barkley 2017

82

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>


12
精度、その下:<configuration> <entityFramework> <interceptors> ... </ interceptors> </ entityFramework> </ configuration>
Christophe P

80

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

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

12
ToString()p__linq__0最終値の代わりに、などの変数を含むクエリを提供します(例:の代わりに34563 p__linq__0
スポーツ

24

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

EF 4.1では次のことができます。

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

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

これにより、生成されたSQLが提供されます。


1
実際のところ、クエリが匿名型を返す場合にのみ機能すると思います。カスタムタイプを返す場合、ToString()出力はそのカスタムタイプの名前空間です。たとえば、上記のコードがのselect new CustomType { x = x.Name }場合、戻り値はCompany.Models.CustomType生成されたSQLではなく、次のようになります。
チャド・レヴィ

8
このテクニックはSystem.Data.Objects.ObjectQuery``1[MyProject.Models.Product]私に役立ちます。
Carl G

1
@CarlG System.Data.Objects.ObjectQueryはEF 4.1(DbContext)ではありません。DbContextを使用すると、System.Data.Entity.Infrastructure.DbQuery`1 [MyProject.Models.Product]となり、実際に "ToString()"の呼び出しでSQLを出力します
springy76

これにより、生成されたSQLが出力ウィンドウのどこに表示されますか?ドロップダウンからどのオプションですか?
JsonStatham 2018

17

私の答えは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メソッドのオーバーライドを回避します、ドキュメントでは推奨されていません:「テストがデータベース全体を対象としない限り、このアプローチはテストには向いていません。」

この複雑なケースでは以下を使用します。

  • IServiceCollectionStartupクラスConfigureServices(代わりにオーバーライドする方法OnConfiguring方法を、利益が間の緩い結合であるDbContextILoggerProvider、使用したいです)
  • の実装ILoggerProviderConsoleLoggerProvider上記の実装を使用する代わりに、利点は、ファイルへのログ方法を示す実装です(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;
        }
    } 
}

それで...それを行う初心者の方法はありませんか?
ファンデラクルス

1
@JuanDelaCruz私は私の答えを簡略化しました。シンプルな代替してみてください
赤エンドウ

16

2つの方法があります。

  1. 生成されるSQLを表示するには、単にを呼び出しますToTraceString()。これをウォッチウィンドウに追加し、ブレークポイントを設定して、任意のLINQクエリの任意の時点でクエリがどうなるかを確認できます。
  2. 選択したSQLサーバーにトレーサーをアタッチできます。これにより、最終的なクエリがすべての詳細で表示されます。MySQLの場合、クエリをトレースする最も簡単な方法は、単にクエリログをでテールすることtail -fです。MySQLのロギング機能について詳しくは、公式ドキュメントをご覧ください。SQL Serverの場合、最も簡単な方法は、付属のSQL Serverプロファイラーを使用することです。

27
何のToTraceString?
nos

Nickが返信を投稿した直後に指摘したObjectQuery。
ベンジャミンポラック

2
SQL Serverプロファイラは最初の4000文字をキャプチャしますが、EFクエリはそれよりはるかに長くなる可能性があります。

7

クエリを常に便利にするには、コードを変更せずにこれをDbContextに追加し、Visual Studioの出力ウィンドウで確認します。

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

@Matt Nibeckerの回答に似ていますが、これにより、クエリが必要になるたびに現在のコードに追加する必要がなくなります。


ベストアンサー!
AlexSC

7

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

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

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

イベントの選択=> T-SQL

左側のチェック:SP.StmtComplete

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

そのプロファイルの実行を開始し、クエリをトリガーします。

ソース情報については、ここをクリックしてください


1
ちょうどSQLサーバー申し訳ありませんthatsのではなく、MySQLの
アンドリューパテ


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

SQLクエリを返します。EntityFramework 6のdatacontextを使用した作業


4
私はこれを試したところ、オブジェクトがトレースされました:実際のクエリの代わりにMicrosoft.EntityFrameworkCore.Query.Internal.EntityQueryable1 [System.Linq.IGrouping 2[System.Int32,String]]。私は何かが足りないのですか、それとも何かを言及するのを忘れましたか?
loganjones16

5

私は統合テストをやって、私の使用して、Entity Frameworkのコア2.1で生成されたSQL文をデバッグするために、これを必要としていますDebugLoggerProviderConsoleLoggerProviderそうのように:

[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コンソールからの出力例を以下に示します。

SQLステートメントの出力例


1
DebugLoggerPrividerとConsoleLoggerProviderは、.NETのコア内に存在するように見える:docs.microsoft.com/en-us/dotnet/api/...
ガブリエルMagana

4

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

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
{

    // /programming/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;
        }


    }


}

私はEF Core 2.0.1を使用しており、上記の提案の結果は次のようになります。ライン: var modelVisitor = (RelationalQueryModelVisitor) queryCompilationContext.CreateQueryModelVisitor();
クリスウルフ

2
@ChrisWolf元の作者の要旨に従うと、その拡張メソッドの更新バージョン提供した人を見つけることができます。私のために働いた。
B12Toaster 2018年

2

私の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

私はこれをやったばかりです:

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

はい、しかし私は誰もp__linq__iを見たくないと信じていますが、実際の値
Tom Stickel

この方法はEF 6でも機能しますが、クエリ構造がどのように見えるかにのみ気を配ると役立ちます。私の場合、IQueryable <T>オブジェクトを作成するプロジェクトにはSystem.Data.Entityへの参照がなく、デバッグ目的でのみ追加する必要があります。したがって、この方法はうまくいきました。
wctiger 2018年

2

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



1

良い答えがここにありますが、どれも完全に私の問題を解決していない(私はSQL文全体、取得することを望んだのパラメータを含む DbContextからの任意のIQueryableからは、。これは、Googleからのコードスニペットの組み合わせでないことだけ。次のコード。 I EF6 +でのみテスト済みです。

余談ですが、この作業は思ったよりもずっと長くかかりました。Enhoity Frameworkでの抽象化は、少なからず、私見です。

まず使用。'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;

次のクラスは、IQueryableをDataTableに変換します。必要に応じて変更します。

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;
            cmd.Parameters.AddRange(Parameters.Select(p => new SqlParameter("@" + p.Name, p.Value)).ToArray());
            using (var da = DbProviderFactories.GetFactory(connection).CreateDataAdapter())
            {
                da.SelectCommand = cmd;
                da.Fill(dt);
            }
        }
        if (!(state == ConnectionState.Open))
            connection.Close();
        return dt;
    }
}

使用するには、次のように呼び出すだけです。

var context = new MyContext();
var data = ....//Query, return type can be anonymous
    .AsQueryable();
var dt = new EntityFrameworkCommand()
    .Initialize(context, data)
    .GetData();

0

Entity Framework 4ソリューション

ここでの回答のほとんどはEF6固有のものでした。これはまだEF4を使用している人のためのものです。

このメソッドは@p__linq__0/ etcを置き換えます。パラメータと実際の値を使用して、出力をコピーしてSSMSに貼り付け、実行またはデバッグすることができます。

    /// <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;
    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.