मैं इकाई फ्रेमवर्क द्वारा उत्पन्न एसक्यूएल को कैसे देख सकता हूं?


624

मैं इकाई ढांचे द्वारा उत्पन्न एसक्यूएल को कैसे देख सकता हूं?

(मेरे विशेष मामले में मैं mysql प्रदाता का उपयोग कर रहा हूं - अगर यह मायने रखता है)


1
इस MSDN पत्रिका से artice इकाई की रूपरेखा के लिए कुछ रूपरेखा विकल्पों का वर्णन 4
Arve

2
लिंक्ड "डुप्लिकेट" प्रश्न LINQ से SQL के लिए है, इसलिए यह वास्तव में डुप्लिकेट नहीं है।
jrummell

2
डीबगर के तहत चलने पर, IntelliTrace SQL क्वेरी से बने, उनके परिणामों के बिना दिखाता है।
ivan_pozdeev

यदि आप विकास के दौरान सिर्फ SQL देखने में रुचि रखते हैं, तो आप LINQPad का उपयोग कर सकते हैं । जब आप परिणामों में एक LINQ क्वेरी चलाते हैं तो एक SQL टैब होगा जो निष्पादित SQL स्टेटमेंट दिखाता है। MySQL के लिए आपको एक ड्राइवर इंस्टॉल करना होगा। मेरे पास mySQL डेटाबेस उपलब्ध नहीं है, लेकिन यह काम करना चाहिए।
ग्लोगेरन

जवाबों:


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
आपको एससीएल (), .Count (), .Any (), आदि के साथ समाप्त होने वाले प्रश्नों के लिए एसक्यूएल नहीं मिलेगा।
बसंत 76६

24
ऐसा इसलिए है क्योंकि .Single()आपके ऑब्जेक्ट को चलाने के बाद कोई और IQueryableअनुमान नहीं है।
सुहास

11
EF6 के साथ, मैं इसे केवल प्रतिबिंब के साथ प्राप्त कर सकता हूं। लेकिन पहले, मुझे परिवर्तित resultकरना था System.Data.Entity.Infrastructure.DbQuery<T>, फिर आंतरिक संपत्ति के InternalQueryरूप में प्राप्त करना था (System.Data.Entity.Internal.Linq.InternalQuery<T>), और उसके बाद ही, इसका उपयोग करेंToTraceString()
जूल

9
System.Data.Entity, System.Data.Objects.ObjectQuery के संदर्भ में उपरोक्त dll में मौजूद हैं
महेश

54
EF6 में आप बस कर सकते हैंresult.ToString()
स्कॉट चैंबरलेन

955

Entity Framework 6 और उससे अधिक का उपयोग करने वालों के लिए, यदि आप Visual Studio में आउटपुट SQL देखना चाहते हैं (जैसे मैंने किया) तो आपको नए लॉगिंग / अवरोधन की कार्यक्षमता का उपयोग करना होगा।

निम्न पंक्ति को जोड़ने से उत्पन्न 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-log/

नोट: सुनिश्चित करें कि आप अपने प्रोजेक्ट को DEBUG मोड में चला रहे हैं।


107
यह उत्तर अधिक प्रेम के योग्य है (यदि आप EF6 + का उपयोग कर रहे हैं) - महान डिबग इसके अलावा, बस इसे DBContext कंस्ट्रक्टर (this.Database.Log = ...) पर जोड़ें
keithl8041

21
सुनिश्चित करें कि आप अपने प्रोजेक्ट को DEBUG MODE में चला रहे हैं, जांचें कि क्या आइटम "डीबग" ने आउटपुट फलक के कॉम्बोक्स पर चुना है और यह भी जांचें कि क्या आपका डीबग तत्काल (उपकरण)> विकल्प> डिबगिंग पर रीडायरेक्ट नहीं कर रहा है - सभी आउटपुट विंडो पाठ को तत्काल भेजें खिड़की)
rakawano

5
वहाँ उत्पन्न चक्र के भीतर चर मूल्यों को सीधे शामिल करने के लिए इसे प्राप्त करने का एक तरीका है? बड़े लोगों के साथ एक दर्द का सा।
क्रिस

22
@ मैट निबेकर यह ईएफ कोर में काम नहीं करता है। ईएफ कोर के लिए विकल्प क्या है?
nam

9
चेतावनी: मैंने इसे केवल विकास में चलाने के इरादे से लागू किया है। जब हमने अपने परीक्षण वातावरण में तैनात किया, तो हमने IIS कार्यकर्ता प्रक्रिया में अचानक मेमोरी लीक देखना शुरू कर दिया। मेमोरी प्रोफाइलिंग के बाद, हमें एहसास हुआ कि GC भी इकाई संदर्भ वस्तुओं को अब एकत्र नहीं कर रहा है (हाँ, वे बयानों का उपयोग करने में थे)। इस लाइन को हटाने से सभी सामान्य हो गए। इसलिए, जब यह एक महान उपकरण है, तो सुनिश्चित करें कि आप इसे केवल विकास के लिए अपने ऐप में बनाते हैं।
ब्रैंडन बार्कले

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>

1
विषय पर ब्लॉग पोस्ट blog.oneunicorn.com/2014/02/09/…
टिम एबेल

12
परिशुद्धता, यह निम्न है: <कॉन्फ़िगरेशन> <एंटिफ्रेमवर्क> <इंटरसेप्टर्स> ... </ इंटरसेप्टर्स> </ एंट्रीफ्रैमवर्क> </ कॉन्फ़िगरेशन>
क्रिस्टोफ़ पी

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]मेरे लिए उत्पादन करती है।
कार्ल जी

1
@CarlG System.Data.Objects.ObjectQuery EF 4.1 (DbContext) नहीं है। DbContext का उपयोग करना यह System.Data.Entity.Infrastructure.DbQuery`1 [MyProject.Models.Product] होगा जो वास्तव में "ToString ()" के लिए एक कॉल पर SQL को आउटपुट करता है
Springy76 12:27

यह आपको आउटपुट विंडो में, जहाँ, उत्पन्न किया गया SQL देगा? ड्रॉपडाउन से कौन सा विकल्प?
JsonStatham

17

मेरा उत्तर ईएफ कोर को संबोधित करता है । मैं इस 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
}

जटिल

यह जटिल मामला विधि को ओवरराइड करने से बचता है DbContext OnConfiguring, जो डॉक्स में हतोत्साहित किया जाता है: "यह दृष्टिकोण खुद को परीक्षण के लिए उधार नहीं देता है, जब तक कि परीक्षण पूर्ण डेटाबेस को लक्षित न करें।"

यह जटिल मामला उपयोग करता है:

  • IServiceCollectionमें Startupवर्ग ConfigureServicesविधि अधिभावी के बजाय ( OnConfiguringविधि; लाभ के बीच एक हारने युग्मन है DbContextऔरILoggerProvider आप उपयोग करना चाहते हैं)
  • का कार्यान्वयन ILoggerProvider( ConsoleLoggerProviderऊपर दिखाए गए कार्यान्वयन का उपयोग करने के बजाय ; लाभ हमारे कार्यान्वयन से पता चलता है कि हम फ़ाइल में कैसे प्रवेश करेंगे (मैं ईएफ कोर के साथ भेज दिया गया फ़ाइल लॉगिंग प्रदाता नहीं देखता )

ऐशे ही:

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

इसके दो तरीके हैं:

  1. उत्पन्न होने वाले SQL को देखने के लिए, बस कॉल करें ToTraceString()। आप इसे अपनी घड़ी की खिड़की में जोड़ सकते हैं और यह देखने के लिए एक ब्रेकप्वाइंट सेट कर सकते हैं कि किसी भी LINQ क्वेरी के लिए किसी भी बिंदु पर क्वेरी क्या होगी।
  2. आप अपनी पसंद के एसक्यूएल सर्वर में एक अनुरेखक संलग्न कर सकते हैं, जो आपको इसके सभी गोर विस्तार में अंतिम क्वेरी दिखाएगा। MySQL के मामले में, प्रश्नों का पता लगाने का सबसे आसान तरीका केवल क्वेरी लॉग को पूंछना है tail -f। आप आधिकारिक दस्तावेज में MySQL की लॉगिंग सुविधाओं के बारे में अधिक जान सकते हैं । SQL सर्वर के लिए, सबसे आसान तरीका शामिल SQL सर्वर प्रोफाइलर का उपयोग करना है।

27
ToTraceString क्या है?
नाक

जब मैंने अपनी प्रतिक्रिया पोस्ट की, तो नीट के रूप में ObjectQuery ने सही उल्लेख किया।
बेंजामिन पोलाक

2
SQL Server Profiler पहले 4000 वर्णों को कैप्चर करता है, लेकिन EF क्वेरी इससे बहुत अधिक लंबी हो सकती है।

7

क्वेरी को हमेशा काम में लेने के लिए, कोड को बदले बिना इसे अपने DbContext में जोड़ें और इसे दृश्य स्टूडियो में आउटपुट विंडो पर जांचें।

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

@Matt Nibecker के उत्तर के समान, लेकिन इसके साथ आपको इसे अपने वर्तमान कोड में जोड़ने की आवश्यकता नहीं है, हर बार आपको क्वेरी की आवश्यकता होती है।


सबसे अच्छा जवाब!
एलेक्सएससी

7

SQL प्रबंधन स्टूडियो => उपकरण => SQL सर्वर प्रोफाइलर

फ़ाइल => नया ट्रेस ...

टेम्पलेट => रिक्त का उपयोग करें

घटना चयन => टी-एसक्यूएल

इसके लिए बायाँ साइड चेक: SP.StmtComplete

किसी विशिष्ट ApplicationName या DatabaseName का चयन करने के लिए कॉलम फ़िल्टर का उपयोग किया जा सकता है

उस प्रोफ़ाइल को चालू करें फिर क्वेरी को ट्रिगर करें।

सोर्स की जानकारी के लिए यहां क्लिक करें


1
क्षमा करें, सिर्फ SQL सर्वर के लिए, MySQL नहीं
andrew pate

5

खैर, मैं इस समय उस प्रयोजन के लिए एक्सप्रेस प्रोफाइलर का उपयोग कर रहा हूं, दोष यह है कि यह केवल एमएस एसक्यूएल सर्वर के लिए काम करता है। आप इस उपकरण को यहां पा सकते हैं: https://expressprofiler.codeplex.com/


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

Sql क्वेरी वापस करेगा। EntityFramework 6 के डेटासोनेट का उपयोग करके काम करना


4
मैंने सिर्फ यह कोशिश की और यह वस्तु का पता लगाता है: Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable1 [System.Linq.IGrouping 2[System.Int32,String]]वास्तविक क्वेरी के बजाय। क्या मुझे कुछ याद आ रहा है या आप कुछ उल्लेख करना भूल गए हैं?
loganjones16

5

मैं इंटीग्रेशन टेस्ट कर रहा हूं, और जरूरत है कि मैं एंटिटी फ्रेमवर्क कोर 2.1 में उत्पन्न एसक्यूएल स्टेटमेंट को डिबग करूं, इसलिए मैं इसका उपयोग करता हूं 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 कंसोल से एक नमूना आउटपुट है:

नमूना SQL कथन आउटपुट


1
DebugLoggerPrivider और ConsoleLoggerProvider केवल .NET Core में मौजूद हैं: docs.microsoft.com/en-us/dotnet/api/…
Gabriel Magana

4

Necromancing।
यह पृष्ठ किसी भी .NET फ्रेमवर्क के लिए समाधान खोजते समय पहला खोज परिणाम है, इसलिए यहां एक सार्वजनिक सेवा के रूप में, यह EntityFramework Core (.NET कोर 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);

और फिर ये एक्सटेंशन मेथड (I.NETableExtensions1 for .NET Core 1.0, IQueryableExtensions for .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;
        }


    }


}

मैं EF Core 2.0.1 और उपर्युक्त सुझाव के परिणामों का उपयोग कर रहा हूं: System.InvalidCastException: 'Microsoft के प्रकार ऑब्जेक्ट को लाने में असमर्थ। लाइन: var modelVisitor = (RelationalQueryModelVisitor) queryCompilationContext.CreateQueryModelVisitor();
क्रिस वुल्फ

2
यदि आप मूल लेखक के जिस्ट का अनुसरण करते हैं तो @ChrisWolf आप किसी ऐसे व्यक्ति को पा सकते हैं जिसने उस एक्सटेंशन विधि का अपडेटेड संस्करण प्रदान किया है । मेरे लिए काम किया।
20:12 बजे B12Toaster

2

ईएफ 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 नहीं देखना चाहता, लेकिन असली मूल्य
टॉम

यह तरीका अभी भी EF 6 में काम करता है और यह तभी उपयोगी होगा जब आप केवल इस बात की परवाह करेंगे कि क्वेरी संरचना कैसी दिखती है। मेरे मामले में मैं जिस परियोजना को IQueryable <T> ऑब्जेक्ट बनाता हूं, उसमें System.Data.Entity का संदर्भ नहीं है और न ही मैं इसे केवल डिबगिंग उद्देश्य के लिए जोड़ना चाहता हूं। तो इस विधि ने ठीक काम किया।
22

2

मेरे लिए, EF6 और विज़ुअल स्टूडियो 2015 का उपयोग करके मैंने queryतत्काल विंडो में प्रवेश किया और इसने मुझे उत्पन्न एसक्यूएल स्टेटमेंट दिया


1

यदि आप पैरामीटर मान (न केवल @p_linq_0बल्कि उनके मान भी) चाहते हैं, तो आप IDbCommandInterceptorकुछ लॉगिंग ReaderExecutedविधि का उपयोग और जोड़ सकते हैं ।


1

जबकि वहाँ अच्छा जवाब यहाँ हैं, कोई भी मेरी समस्या पूरी तरह से (मैं पूरे SQL विवरण, प्राप्त करने के लिए कामना की हल पैरामीटर सहित किसी भी IQueryable से, DbContext से। निम्नलिखित कोड करता है सिर्फ इतना है कि। यह गूगल से कोड के टुकड़े का एक संयोजन है। मैं केवल EF6 + के साथ इसका परीक्षण किया है

बस एक तरफ, इस कार्य ने मुझे जितना सोचा था उससे अधिक समय लगा। इकाई फ्रेमवर्क में अमूर्त एक बहुत अधिक है, IMHO।

पहला प्रयोग। आपको '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 को डेटाटेबल में परिवर्तित करता है। अपनी आवश्यकता के अनुसार संशोधित करें:

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

इकाई फ्रेमवर्क 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;
    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.