Bagaimana cara melihat SQL yang dihasilkan oleh Entity Framework?

624

Bagaimana cara melihat SQL yang dihasilkan oleh kerangka kerja entitas?

(Dalam kasus khusus saya, saya menggunakan penyedia mysql - jika itu penting)

tidak
sumber
1
Artikel ini dari Majalah MSDN menjelaskan beberapa opsi pembuatan profil untuk Entity Framework 4
Arve
2
Pertanyaan "duplikat" yang ditautkan adalah untuk LINQ ke SQL, jadi sebenarnya bukan duplikat.
jrummell
2
Saat berjalan di bawah debugger, IntelliTrace menampilkan kueri SQL yang dibuat, meskipun tanpa hasil.
ivan_pozdeev
Jika Anda tertarik melihat SQL sesaat pengembangan, Anda dapat menggunakan LINQPad . Saat Anda menjalankan kueri LINQ dalam hasil akan ada tab SQL yang menunjukkan pernyataan SQL yang dieksekusi. Untuk mySQL Anda harus menginstal driver. Saya tidak memiliki database mySQL yang tersedia, tetapi harus berfungsi.
gligoran

Jawaban:

472

Anda dapat melakukan hal berikut:

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

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

atau di EF6:

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

Itu akan memberi Anda SQL yang dihasilkan.

Nick Berardi
sumber
20
Anda tidak akan mendapatkan SQL untuk kueri yang diakhiri dengan .Single (), .Count (), .Any (), dll. Dengan cara itu.
springy76
24
Itu karena setelah menjalankan .Single()objek Anda tidak lagi IQueryablesaya kira.
Suhas
11
dengan EF6, saya bisa mendapatkannya hanya dengan refleksi. tetapi pertama-tama, saya harus mengonversi resultke System.Data.Entity.Infrastructure.DbQuery<T>, kemudian mendapatkan properti internal InternalQuerysebagai (System.Data.Entity.Internal.Linq.InternalQuery<T>), dan hanya pada saat itu, gunakanToTraceString()
itsho
9
tambahkan referensi ke System.Data.Entity, System.Data.Objects.ObjectQuery ada di dll di atas
Mahesh
54
Di EF6, Anda bisa melakukannyaresult.ToString()
Scott Chamberlain
956

Bagi mereka yang menggunakan Entity Framework 6 dan lebih tinggi, jika Anda ingin melihat output SQL dalam Visual Studio (seperti yang saya lakukan), Anda harus menggunakan fungsi logging / intersepsi yang baru.

Menambahkan baris berikut akan memuntahkan SQL yang dihasilkan (bersama dengan detail terkait eksekusi tambahan) di panel output Visual Studio:

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

Informasi lebih lanjut tentang masuk dalam EF6 dalam seri blog yang bagus ini: http://blog.oneunicorn.com/2013/05/08/ef6-sql-logging-part-1-simple-logging/

Catatan: Pastikan Anda menjalankan proyek Anda dalam mode DEBUG.

Matt Nibecker
sumber
107
Jawaban ini layak mendapatkan lebih banyak cinta (jika Anda menggunakan EF6 +) - tambahan debug yang hebat, cukup tambahkan di konstruktor DBContext (this.Database.Log = ...)
keithl8041
21
Pastikan Anda menjalankan proyek Anda dalam MODE DEBUG, periksa apakah item "Debug" telah dipilih di combobox panel Output dan juga periksa apakah debug Anda tidak mengarahkan ke Segera (Alat> Pilihan> Debugging> Mengarahkan semua teks Jendela Output ke Segera. Jendela)
rkawano
5
apakah ada cara untuk mendapatkan ini untuk memasukkan nilai variabel langsung dalam sql yang dihasilkan? Sedikit sakit dengan yang lebih besar.
Chris
22
@Matt Nibecker Ini tidak berfungsi di EF Core. Apa alternatif untuk EF Core?
nam
9
PERINGATAN: Saya menerapkan ini dengan tujuan hanya berjalan dalam pengembangan. Ketika kami ditempatkan di lingkungan pengujian kami, kami mulai dengan tiba-tiba melihat kebocoran memori dalam Proses Pekerja IIS. Setelah profil memori, kami menyadari bahkan GC eksplisit tidak lagi mengumpulkan objek konteks entitas (ya, mereka menggunakan pernyataan). Menghapus garis ini mengembalikan semua ke normal. Jadi, meskipun ini adalah alat yang hebat, pastikan Anda hanya memasukkannya ke dalam aplikasi untuk pengembangan.
Brandon Barkley
82

Dimulai dengan EF6.1 Anda dapat menggunakan Interceptors untuk mendaftarkan logger basis data. Lihat bab "Pencegat" dan "Operasi Database Pencatatan" ke File di sini

<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>
isepise
sumber
1
Posting blog pada subjek blog.oneunicorn.com/2014/02/09/...
Tim Abell
12
Precision, Ada di bawah: <configuration> <entityFramework> <interceptors> ... </interceptors> </entityFramework> </configuration>
Christophe P
80

Jika Anda menggunakan DbContext, Anda dapat melakukan hal berikut untuk mendapatkan SQL:

var result = from i in myContext.appEntities
             select new Model
             {
                 field = i.stuff,
             };
var sql = result.ToString();
Doug Clutter
sumber
12
ToString()akan memberi Anda kueri dengan variabel di dalamnya, seperti p__linq__0, alih-alih nilai akhir (misal: 34563 alih-alih p__linq__0)
sports
24

Berlaku untuk EF 6.0 ke atas: Bagi Anda yang ingin tahu lebih banyak tentang fungsionalitas pencatatan dan menambahkan ke beberapa jawaban yang sudah diberikan.

Perintah apa pun yang dikirim dari EF ke database sekarang dapat dicatat. Untuk melihat pertanyaan yang dihasilkan dari EF 6.x, gunakanDBContext.Database.Log property

Apa yang Mendapat Log

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

Contoh:

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

Keluaran:

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

Untuk masuk ke file eksternal:

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

Info lebih lanjut di sini: Logging dan Mencegah Operasi Database

NullReference
sumber
21

Anda dapat melakukan hal berikut di EF 4.1:

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

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

Itu akan memberi Anda SQL yang dihasilkan.

Capriols
sumber
1
Sebenarnya, saya percaya ini hanya berfungsi ketika kueri mengembalikan jenis anonim. Jika mengembalikan tipe kustom, ToString()output adalah namespace dari tipe kustom itu. Sebagai contoh, jika kode di atas adalah select new CustomType { x = x.Name }, nilai yang dikembalikan akan menjadi seperti Company.Models.CustomTypebukannya SQL yang dihasilkan.
Chad Levy
8
Teknik ini menghasilkan System.Data.Objects.ObjectQuery``1[MyProject.Models.Product]bagi saya.
Carl G
1
@CarlG System.Data.Objects.ObjectQuery bukan EF 4.1 (DbContext). Menggunakan DbContext itu akan menjadi System.Data.Entity.Infrastructure.DbQuery`1 [MyProject.Models.Product] yang memang menampilkan SQL pada panggilan ke "ToString ()"
springy76
Ini akan memberi Anda SQL yang dihasilkan, di mana, di jendela output? opsi mana dari dropdown?
JsonStatham
17

Jawaban saya membahas inti EF . Saya merujuk masalah github ini , dan dokumen tentang konfigurasiDbContext :

Sederhana

Ganti OnConfiguringmetode DbContextkelas Anda ( YourCustomDbContext) seperti yang ditunjukkan di sini untuk menggunakan ConsoleLoggerProvider; pertanyaan Anda harus masuk ke konsol:

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
}

Kompleks

Kasus Kompleks ini menghindari override yang DbContext OnConfiguringmetode. , yang tidak disarankan dalam dokumen: "Pendekatan ini tidak cocok untuk pengujian, kecuali jika tes menargetkan basis data lengkap."

Kasing Kompleks ini menggunakan:

  • Metode IServiceCollectionin Startupclass ConfigureServices(alih-alih mengganti OnConfiguringmetode; manfaatnya adalah kopling yang lebih longgar antara DbContextdan yang ILoggerProvideringin Anda gunakan)
  • Implementasi ILoggerProvider(alih-alih menggunakan ConsoleLoggerProviderimplementasi yang ditunjukkan di atas; manfaat adalah implementasi kami yang menunjukkan bagaimana kami akan masuk ke File (Saya tidak melihat Penyedia Logging File dikirimkan bersama EF Core ))

Seperti ini:

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

Inilah implementasi dari a MyLoggerProvider(dan MyLoggeryang menambahkan log-nya ke File yang dapat Anda konfigurasikan; kueri EF Core Anda akan muncul dalam file.)

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;
        }
    } 
}
Kacang Merah
sumber
Jadi ... tidak ada cara pemula untuk melakukannya?
Juan De la Cruz
1
@JuanDelaCruz Saya menyederhanakan jawaban saya; coba alternatif sederhana
The Red Pea
16

Ada dua cara:

  1. Untuk melihat SQL yang akan dihasilkan, cukup panggil ToTraceString(). Anda bisa menambahkannya ke jendela arloji Anda dan mengatur titik istirahat untuk melihat seperti apa kueri pada titik tertentu untuk setiap kueri LINQ.
  2. Anda dapat melampirkan pelacak ke server SQL pilihan Anda, yang akan menunjukkan kepada Anda permintaan terakhir dalam semua detail berdarahnya. Dalam kasus MySQL, cara termudah untuk melacak kueri adalah dengan mengeklik log kueri tail -f. Anda dapat mempelajari lebih lanjut tentang fasilitas logging MySQL di dokumentasi resmi . Untuk SQL Server, cara termudah adalah dengan menggunakan profiler SQL Server yang disertakan.
Benjamin Pollack
sumber
27
ToTraceString tentang apa?
nos
ObjectQuery, seperti yang dicatat Nick tepat setelah saya memposting respons saya.
Benjamin Pollack
2
SQL Server Profiler menangkap 4000 karakter pertama, tetapi kueri EF bisa lebih lama dari itu.
7

Agar kueri selalu praktis, tanpa mengubah kode, tambahkan ini ke DbContext Anda dan periksa di jendela output di visual studio.

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

Mirip dengan @Matt Nibecker, tetapi dengan ini Anda tidak perlu menambahkannya dalam kode Anda saat ini, setiap kali Anda membutuhkan kueri.

Gerrie Pretorius
sumber
Jawaban terbaik!
AlexSC
7

SQL Management Studio => Tools => SQL Server profiler

File => Jejak Baru ...

Gunakan Template => Kosong

Pilihan acara => T-SQL

Lefthandside memeriksa: SP.StmtComplete

Filter kolom dapat digunakan untuk memilih ApplicationName atau DatabaseName tertentu

Mulai menjalankan profil itu kemudian memicu permintaan.

Klik di sini untuk informasi Sumber

andrew pate
sumber
1
maaf itu hanya untuk SQL server, bukan MySQL
andrew pate
5

Yah, saya menggunakan profiler Express untuk tujuan itu saat ini, kekurangannya adalah itu hanya bekerja untuk MS SQL Server. Anda dapat menemukan alat ini di sini: https://expressprofiler.codeplex.com/

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

Akan mengembalikan kueri sql. Bekerja menggunakan datacontext dari EntityFramework 6

Gianluca Conte
sumber
4
Saya baru saja mencoba ini dan melacak objek: Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable1 [System.Linq.IGrouping 2[System.Int32,String]]bukan permintaan yang sebenarnya. Apakah saya kehilangan sesuatu atau Anda lupa menyebutkan sesuatu?
loganjones16
5

Saya sedang melakukan tes integrasi, dan perlu ini untuk men-debug pernyataan SQL yang dihasilkan di Entity Framework Core 2.1, jadi saya menggunakan DebugLoggerProvideratau ConsoleLoggerProviderseperti itu:

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

        ........

Berikut ini contoh keluaran dari konsol Visual Studio:

Contoh output pernyataan SQL

Rosdi Kasim
sumber
1
DebugLoggerPrivider dan ConsoleLoggerProvider tampaknya hanya ada di .NET Core: docs.microsoft.com/en-us/dotnet/api/…
Gabriel Magana
4

Necromancing.
Halaman ini adalah hasil pencarian pertama ketika mencari solusi untuk .NET Framework, jadi di sini sebagai layanan publik, bagaimana hal itu dilakukan dalam EntityFramework Core (untuk .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);

Dan kemudian metode ekstensi ini (IQueryableExtensions1 untuk .NET Core 1.0, IQueryableExtensions untuk .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
{

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


    }


}
Stefan Steiger
sumber
Saya menggunakan EF Core 2.0.1 dan saran di atas menghasilkan: System.InvalidCastException: 'Tidak dapat membuang objek bertipe Microsoft.EntityFrameworkCore.Query.Internal.InMemoryQueryModelVisitor' untuk mengetikkan '' Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor` for ' baris: var modelVisitor = (RelationalQueryModelVisitor) queryCompilationContext.CreateQueryModelVisitor();
Chris Wolf
2
@ ChrisWolf jika Anda mengikuti intisari penulis asli, Anda dapat menemukan seseorang yang menyediakan versi terbaru dari metode ekstensi itu . Bekerja untukku.
B12Toaster
2

Dalam kasus saya untuk EF 6+, alih-alih menggunakan ini di Jendela Segera untuk menemukan string kueri:

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

Saya akhirnya harus menggunakan ini untuk mendapatkan perintah SQL yang dihasilkan:

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

Tentu saja tanda tangan jenis anonim Anda mungkin berbeda.

HTH.

pengguna8128167
sumber
2

Saya baru saja melakukan ini:

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

Dan hasilnya ditunjukkan pada 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
Daniel Camargo
sumber
Ya, tetapi saya percaya bahwa tidak ada yang ingin melihat p__linq__i, tetapi nilai sebenarnya
Tom Stickel
Cara ini masih berfungsi di EF 6 dan akan sangat membantu jika Anda hanya peduli seperti apa struktur kueri itu. Dalam kasus saya, proyek yang saya buat objek <T> IQueryable tidak memiliki referensi ke System.Data.Entity atau saya ingin menambahkannya hanya untuk tujuan debugging. Jadi metode ini bekerja dengan baik.
wctiger
2

Bagi saya, menggunakan EF6 dan Visual Studio 2015 saya masuk querydi jendela langsung dan itu memberi saya Pernyataan SQL yang dihasilkan

Jonas Stawski
sumber
1

Jika Anda ingin memiliki nilai parameter (tidak hanya @p_linq_0tetapi juga nilainya), Anda dapat menggunakan IDbCommandInterceptordan menambahkan beberapa logging ke ReaderExecutedmetode.

michal.jakubeczy
sumber
1

Walaupun ada jawaban yang baik di sini, tidak ada yang menyelesaikan masalah saya sepenuhnya (saya ingin mendapatkan seluruh pernyataan SQL, termasuk Parameter , dari DbContext dari IQueryable. Kode berikut tidak hanya itu. Ini adalah kombinasi dari potongan kode dari Google. Saya hanya mengujinya dengan EF6 + .

Di samping itu, tugas ini membawa saya jauh lebih lama daripada yang saya kira. Abstraksi dalam Entity Framework sedikit banyak, IMHO.

Pertama menggunakan. Anda akan memerlukan referensi eksplisit ke '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;

Kelas berikut mengubah IQueryable menjadi DataTable. Ubah sesuai kebutuhan Anda mungkin:

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

Untuk menggunakannya, cukup sebut sebagai berikut:

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

Solusi Entity Framework 4

Sebagian besar jawaban di sini adalah khusus EF6. Ini satu untuk Anda yang masih menggunakan EF4.

Metode ini menggantikan @p__linq__0/ etc. parameter dengan nilai aktualnya, jadi Anda bisa menyalin dan menempelkan output ke SSMS dan menjalankannya atau men-debug-nya.

    /// <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;
    }
jramm
sumber