entity framework - मैं इकाई फ्रेमवर्क द्वारा जेनरेट किए गए एसक्यूएल को कैसे देखूं?




entity-framework ado.net (11)

Necromancing।
यह पृष्ठ किसी भी .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 कोर 1.0 के लिए IQueryableExtensions1, .NET कोर 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
{

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


    }


}

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

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


आप ईएफ 4.1 में निम्नलिखित कर सकते हैं:

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

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

इससे आपको जेनरेट किया गया एसक्यूएल मिलेगा।


ईएफ 6+ के लिए मेरे मामले में, क्वेरी स्ट्रिंग को खोजने के लिए तत्काल विंडो में इसका उपयोग करने के बजाय:

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

उत्पन्न जेनरेट एसक्यूएल कमांड प्राप्त करने के लिए इसका उपयोग करने के लिए समाप्त हो गया:

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

बेशक आपका अनाम प्रकार हस्ताक्षर अलग हो सकता है।

HTH।


ईएफ 6.0 और उसके बाद के लिए लागू: आप में से उन लोगों के लिए जो लॉगिंग कार्यक्षमता के बारे में अधिक जानना चाहते हैं और पहले से दिए गए कुछ उत्तरों को जोड़ना चाहते हैं।

ईएफ से डेटाबेस में भेजे गए किसी भी कमांड को अब लॉग किया जा सकता है। 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();
   }
}

यहां अधिक जानकारी: डेटाबेस संचालन लॉगिंग और इंटरसेप्टिंग


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

निम्न पंक्ति जोड़ने से विजुअल स्टूडियो आउटपुट पैनल में जेनरेट किए गए एसक्यूएल (अतिरिक्त निष्पादन से संबंधित विवरण के साथ) थूक जाएगा:

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

इस निफ्टी ब्लॉग श्रृंखला में ईएफ 6 में लॉगिंग के बारे में अधिक जानकारी: http://blog.oneunicorn.com/2013/05/08/ef6-sql-logging-part-1-simple-logging/

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


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

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

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


दो तरीके हैं:

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

मेरा जवाब ईएफ कोर पते। मैं इस DbContext मुद्दे का संदर्भ देता हूं, और DbContext को कॉन्फ़िगर करने पर दस्तावेज़:

सरल

एक OnConfiguring का उपयोग करने के लिए यहां दिखाए गए अनुसार आपके DbContext क्लास ( YourCustomDbContext ) की OnConfiguring विधि को ओवरराइड करें; आपके प्रश्न कंसोल पर लॉग इन होना चाहिए:

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
            //.UseSqlServer("...");
    #endregion
}

जटिल

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

यह कॉम्प्लेक्स केस उपयोग करता है:

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

इस कदर:

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 जो आपके लॉग को उस फ़ाइल में जोड़ता है जिसे आप कॉन्फ़िगर कर सकते हैं; आपके ईएफ कोर प्रश्न फ़ाइल में दिखाई देंगे।)

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

मैंने अभी यह किया है:

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

यदि आप डीबीकॉन्टेक्स्ट का उपयोग कर रहे हैं, तो आप SQL प्राप्त करने के लिए निम्न कार्य कर सकते हैं:

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

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

एसक्यूएल क्वेरी वापस कर देगा। EntityFramework 6 के डेटाकॉन्टेक्स्ट का उपयोग कर काम करना






ado.net