एक एंटिटी फ्रेमवर्क कोर IQueryable <T> से SQL कोड प्राप्त करें


103

मैं एंटिटी फ्रेमवर्क कोर का उपयोग कर रहा हूं और मुझे यह देखने की आवश्यकता है कि कौन सा एसक्यूएल कोड उत्पन्न हो रहा है। इकाई ढांचे के पिछले संस्करणों में मैं निम्नलिखित का उपयोग कर सकता है:

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

जहाँ क्वेरी एक IQueryable ऑब्जेक्ट है ... लेकिन ToTraceString EF Core में उपलब्ध नहीं है।

मैं ईएफ कोर में कुछ समान कैसे कर सकता हूं?



आप यह कोशिश कर सकते हैं: rion.io/2016/10/19/…
माइकब्रिज

जवाबों:


108

ईएफ कोर 5 / नेट 5

query.ToQueryString()

ईएफ कोर 5.0 में देखें डॉक्यूमेंटेशन टूवेरस्ट्रिंग () और नया क्या है

var query = _context.Widgets.Where(w => w.IsReal && w.Id == 42);  
var sql = query.ToQueryString();

पुराने नेट कोर फ्रेमवर्क के लिए एक एक्सटेंशन का उपयोग किया जा सकता है।

कोर 2.1.2


using System.Linq;
using System.Reflection;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.EntityFrameworkCore.Query.Internal;
using Microsoft.EntityFrameworkCore.Query.Expressions;
using Microsoft.EntityFrameworkCore.Query.Sql;
using static Microsoft.EntityFrameworkCore.DbLoggerCategory;

    public static class QueryableExtensions
    {
        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 FieldInfo QueryModelGeneratorField = typeof(QueryCompiler).GetTypeInfo().DeclaredFields.First(x => x.Name == "_queryModelGenerator");
        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)
        {
            var queryCompiler = (QueryCompiler) QueryCompilerField.GetValue(query.Provider);
            var queryModelGenerator = (QueryModelGenerator)QueryModelGeneratorField.GetValue(queryCompiler);
            var queryModel = queryModelGenerator.ParseQuery(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;
        }
    }

ईएफ कोर 3.0

        public static string ToSql<TEntity>(this IQueryable<TEntity> query)
        {
            var enumerator = query.Provider.Execute<IEnumerable<TEntity>>(query.Expression).GetEnumerator();
            var enumeratorType = enumerator.GetType();
            var selectFieldInfo = enumeratorType.GetField("_selectExpression", BindingFlags.NonPublic | BindingFlags.Instance) ?? throw new InvalidOperationException($"cannot find field _selectExpression on type {enumeratorType.Name}");
            var sqlGeneratorFieldInfo = enumeratorType.GetField("_querySqlGeneratorFactory", BindingFlags.NonPublic | BindingFlags.Instance) ?? throw new InvalidOperationException($"cannot find field _querySqlGeneratorFactory on type {enumeratorType.Name}");
            var selectExpression = selectFieldInfo.GetValue(enumerator) as SelectExpression ?? throw new InvalidOperationException($"could not get SelectExpression");
            var factory = sqlGeneratorFieldInfo.GetValue(enumerator) as IQuerySqlGeneratorFactory ?? throw new InvalidOperationException($"could not get IQuerySqlGeneratorFactory");
            var sqlGenerator = factory.Create();
            var command = sqlGenerator.GetCommand(selectExpression);
            var sql = command.CommandText;
            return sql;
        }

रोजी से देखिए

ईएफ कोर 3.1

using System.Linq;
using System.Reflection;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.Query.SqlExpressions;
using Microsoft.EntityFrameworkCore.Query;

public static string ToSql<TEntity>(this IQueryable<TEntity> query) where TEntity : class
{
    var enumerator = query.Provider.Execute<IEnumerable<TEntity>>(query.Expression).GetEnumerator();
    var relationalCommandCache = enumerator.Private("_relationalCommandCache");
    var selectExpression = relationalCommandCache.Private<SelectExpression>("_selectExpression");
    var factory = relationalCommandCache.Private<IQuerySqlGeneratorFactory>("_querySqlGeneratorFactory");

    var sqlGenerator = factory.Create();
    var command = sqlGenerator.GetCommand(selectExpression);

    string sql = command.CommandText;
    return sql;
}

private static object Private(this object obj, string privateField) => obj?.GetType().GetField(privateField, BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(obj);
private static T Private<T>(this object obj, string privateField) => (T)obj?.GetType().GetField(privateField, BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(obj);

इस मुद्दे को EF नेट कोर टीम द्वारा भी ट्रैक किया जाता है और अगली रिलीज़ के लिए निर्धारित किया जाता है।


1
आप कैसे यह एक साथ काम करने के लिए लिखा जाना चाहिए का एक उदाहरण दे सकता है IQueryableऔर एक नहीं IQueryable<T>?
बवेरो

मुझे लगता है कि तुम हमेशा एक है IQueryable<T>। ऊपर का widgetउदाहरण देखें । क्या आपके पास एक उदाहरण है जिसमें केवल एक IQueryable है।
थोमास केवेटेर

मैं का उपयोग कर रहे github.com/StefH/System.Linq.Dynamic.Core है, जो एक तुम देता है IQueryableबस
byrnedo

1
var relationalCommandCache = enumerator.Private ("_ relationalCommandCache"); रिटर्न नूर
खुर्रम अली

1
के लिए EF Core 2.1, ये केवल वही हैं जिनकी usingमुझे ज़रूरत थी (अस्पष्ट संदर्भों की समस्या को रोकने के लिए)। using System.Linq; using System.Reflection; using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.Query.Internal; using Microsoft.EntityFrameworkCore.Storage;
ऐश के

82

यह उत्तर EF Core 2.1 के लिए है। EF Core 3.0 और 3.1 के लिए @Thom Kiesewetter का उत्तर देखें

ईएफ कोर 5 के लिए वहाँ पर निर्मित विधि का ToQueryString()उपयोग किया जाएगाIQueryable<>

चूँकि EF 7 का नाम बदलकर Entity Framework Core रखा गया है इसलिए मैं आपको EF Core के विकल्पों को संक्षेप में प्रस्तुत करूँगा।

SQL कथन लॉग करने के लिए 3 दृष्टिकोण हैं IQueryable<>:

  • बिल्ट-इन या कस्टम लॉगिंग का उपयोग करनाइस ट्यूटोरियल में बताए अनुसार अपनी पसंद के लॉगर या बिल्ट-इन लॉगर को .NET कोर में इस्तेमाल करके एक्जिक्यूटिंग क्वेरी को लॉग करना ।
  • एक Profiler का उपयोग करना । निष्पादित क्वेरी पर नजर रखने के लिए मिनीप्रोफाइलर की तरह एक एसक्यूएल प्रॉसेसर का उपयोग करना ।
  • क्रेजी रिफ्लेक्शन कोड का उपयोग करना । आप उसी मूल अवधारणा को करने के लिए पुराने दृष्टिकोण के समान कुछ कस्टम प्रतिबिंब कोड को लागू कर सकते हैं।

यहाँ पागल प्रतिबिंब कोड (विस्तार विधि) है:

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 FieldInfo QueryModelGeneratorField = QueryCompilerTypeInfo.DeclaredFields.First(x => x.Name == "_queryModelGenerator");

    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
    {
        var queryCompiler = (QueryCompiler)QueryCompilerField.GetValue(query.Provider);
        var modelGenerator = (QueryModelGenerator)QueryModelGeneratorField.GetValue(queryCompiler);
        var queryModel = modelGenerator.ParseQuery(query.Expression);
        var database = (IDatabase)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;
    }
}

इस विस्तार विधि को अपने कोड में जोड़ने के बाद, आप इस विधि का उपयोग इस प्रकार कर सकते हैं:

// Build a query using Entity Framework
var query = _context.Widgets.Where(w => w.IsReal && w.Id == 42);  
// Get the generated SQL
var sql = query.ToSql();  

रेफरल: http://rion.io/2016/10/19/accessing-entity-framework-core-queries-behind-the-scenes-in-asp-net-core/ और https://gist.github.com / rionmonster / 2c59f449e67edf8cd6164e9fe66c545a


1
टिप्पणियों के लिए धन्यवाद। मैंने कोड अपडेट किया है इसलिए इसे 2.1 के साथ काम करना चाहिए।
निकोले कोस्तोव

1
@SteffenMangold यह डिबगिंग के उद्देश्यों के लिए है :) यह तेज़ होने का इरादा नहीं है।
निकोले कोस्तोव

1
@RicardoPeres: नहीं, वे rion.io/2016/10/19/… का संदर्भ देते हैं , जो आपकी पोस्ट को क्रेडिट करता है।
मार्टिन पीटर्स

1
@ अलेक्सई मैंने उपयोग करना शुरू कर दिया optionsBuilder.UseLoggerFactory(LoggerFactory); public static readonly LoggerFactory LoggerFactory = new LoggerFactory(new[] { new ConsoleLoggerProvider((_, __) => true, true) });क्योंकि यह और भी सुंदर एसक्यूएल बनाता है, लेकिन दुर्भाग्य से बहुत अधिक स्पैम भी है।
जोएलटी

2
ईएफ़ कोर 3.0 के साथ .Net कोर 3.0 अब जीए में जारी किया गया है, और इसमें विधि के बारे में परिवर्तन हैं: ToSql। किसी भी विचार कैसे 3.0 के लिए इसे फिर से लागू करने के लिए? अधिक जानकारी: github.com/aspnet/EntityFrameworkCore/issues/18029
borisdj

41

किसी के लिए बस एक बार की गलत ईएफ कोर क्वेरी या इस तरह से निदान करने की कोशिश कर रहा है और अपने कोड को बदलना नहीं चाहता, कुछ विकल्प हैं:

SQL सर्वर प्रबंधन स्टूडियो (SSMS) SQL प्रोफाइलर का उपयोग करें

यदि आपने SQL सर्वर प्रबंधन स्टूडियो (SSMS) स्थापित किया है, तो आप SSMS में टूल मेनू से SQL Profiler को आग लगा सकते हैं :

SQL सर्वर प्रबंधन स्टूडियो (SSMS) में उपकरण मेनू में SQL Profiler विकल्प

और फिर खुलते ही SQL Profiler में एक नया ट्रेस शुरू करें।

फिर आप EF से आने वाले SQL अनुरोध को देख पाएंगे, वे आम तौर पर बहुत अच्छी तरह से बनते हैं और पढ़ने में आसान होते हैं।

Visual Studio में आउटपुट विंडो की जाँच करें

VS2019 की मेरी प्रति में, EF2.2 का उपयोग करके मैं वेब सर्वर से आउटपुट दिखाने के लिए आउटपुट विंडो को बदल सकता हूं (आउटपुट फलक के शीर्ष पर "कॉम्बो से" शो आउटपुट "में अपने ऐप और वेब सर्वर का नाम चुनें) और निवर्तमान SQL को भी इसमें दिखाया गया है। मैंने अपना कोड जाँच लिया है और जहाँ तक मैं देख सकता हूँ मैंने इसे सक्षम करने के लिए कुछ नहीं किया है, इसलिए मुझे लगता है कि इसे डिफ़ॉल्ट रूप से करना होगा:

यहां छवि विवरण दर्ज करें

यदि आप क्वेरी में SQL सर्वर पर भेजे गए पैरामीटर देखना चाहते हैं, तो आप उस EnableSensitiveDataLoggingविधि के साथ DBContext सेट करते समय स्विच कर सकते हैं , जैसे।

services.AddDbContext<FusionContext>(options => options
    .UseSqlServer(connectionString))
    //.EnableDetailedErrors()
    .EnableSensitiveDataLogging()

@Tich - Lil3p ने टिप्पणी में कहा है कि उन्हें प्रोजेक्ट के प्रॉपर्टीज पेज के डिबग टैब में SQL डीबगिंग चालू करने के लिए एक स्विच का उपयोग करने की आवश्यकता है (जो "sqlDebugging": trueलॉन्चसेट्स.जसन में सेट है)। मैंने जाँच की और मुझे अपनी किसी भी परियोजना के लिए स्विच नहीं मिला, लेकिन अगर ऊपर वाला आपके लिए काम नहीं कर रहा है, तो वह भी प्रयोग करने लायक हो सकता है।


3
Azure Sql
Emil

@batmaci मैंने एक और तरीका जोड़ा है जो Azure के लिए काम कर सकता है
tomRedox

मुझे EF Core से आउटपुट मिलता है, लेकिन यह मुझे @__ p_0, इत्यादि के लिए उपयोग किए जाने वाले चर नहीं दिखाता है
DaleyKD

@DaleyKD अगर मेमोरी मुझे सही सेवा देता है तो यह एक सुरक्षा मुद्दा है - मुझे लगता है कि एमवीसी डिफ़ॉल्ट रूप से मापदंडों को छुपाता है क्योंकि वे संवेदनशील डेटा शामिल कर सकते हैं। मुझे लगता है कि एमवीसी के लिए डिबगिंग विकल्पों में से एक पैरामीटर दिखाया जाएगा, लेकिन मुझे याद नहीं है कि कौन सा है। मेरे पास अपने कोड को देखते app.UseDeveloperExceptionPage()हुए Startup.Configure और services.AddServerSideBlazor() .AddCircuitOptions(options => { options.DetailedErrors = true; });Startup.ConfigureServices में हैं। उन मापदंडों में से एक दिखावा हो सकता है।
टॉमराडॉक्स

1
इस लिंक ने मेरी मदद की -> thecodebuzz.com/adding-logging-in-entity-framework-core
यूरी कार्डसो

3

मेरा निकोल-कोस्तोव जवाब पर आधारित है।

अंतर यह है कि मुझे हार्ड कमांड के बजाय निकाले गए मापदंडों के साथ एसक्यूएल कमांड मिलता है जो ईएफ कोर डेटाबेस को कमांड भेजने के तरीके के अनुरूप अधिक है। इसके अलावा, यदि आप डेटाबेस को कमांड को संपादित और भेजना चाहते हैं, तो मापदंडों का उपयोग करना बेहतर अभ्यास है।

    private static class IQueryableUtils 
    {
        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 FieldInfo QueryModelGeneratorField = QueryCompilerTypeInfo.DeclaredFields.First(x => x.Name == "_queryModelGenerator");
        private static readonly FieldInfo queryContextFactoryField = QueryCompilerTypeInfo.DeclaredFields.First(x => x.Name == "_queryContextFactory");
        private static readonly FieldInfo loggerField = QueryCompilerTypeInfo.DeclaredFields.First(x => x.Name == "_logger");
        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 sql, IReadOnlyDictionary<string, object> parameters) ToSql<TEntity>(IQueryable<TEntity> query) where TEntity : class
        {
            var queryCompiler = (QueryCompiler)QueryCompilerField.GetValue(query.Provider);
            var queryContextFactory = (IQueryContextFactory)queryContextFactoryField.GetValue(queryCompiler);
            var logger = (Microsoft.EntityFrameworkCore.Diagnostics.IDiagnosticsLogger<DbLoggerCategory.Query>)loggerField.GetValue(queryCompiler);
            var queryContext = queryContextFactory.Create();
            var modelGenerator = (QueryModelGenerator)QueryModelGeneratorField.GetValue(queryCompiler);
            var newQueryExpression = modelGenerator.ExtractParameters(logger, query.Expression, queryContext);
            var queryModel = modelGenerator.ParseQuery(newQueryExpression);
            var database = (IDatabase)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 command = modelVisitor.Queries.First().CreateDefaultQuerySqlGenerator()
                .GenerateSql(queryContext.ParameterValues);

            return (command.CommandText, queryContext.ParameterValues);
        }
    }


2

इस उत्तर को जोड़ना क्योंकि यहां सभी सुझाव नए ईएफ कोर रिलीज के साथ टूट गए हैं (यानी, यहां सभी उत्तर ईएफ कोर 2.2 पर टूट गए हैं)। यहाँ कोड है कि पहली कोशिश पर मेरे लिए काम किया है, और लगता है .NET कोर संस्करण अज्ञेय (अब तक): https://blogs.msdn.microsoft.com/dbrowne/2017/09/22/simple-log-for -ef कोर /


2

इकाई फ्रेमवर्क कोर 3.x

आप इसे लॉगिंग के माध्यम से प्राप्त कर सकते हैं।

फैक्टरी बनाएँ:

var loggerFactory = LoggerFactory.Create(builder =>
{
    builder
    .AddConsole((options) => { })
    .AddFilter((category, level) =>
        category == DbLoggerCategory.Database.Command.Name
        && level == LogLevel.Information);
});

बताएं कि DbContextकिस कारखाने का उपयोग करना है:

optionsBuilder.UseLoggerFactory(_loggerFactory);

से इस पोस्ट

आप अधिक जानकारी प्राप्त कर सकते हैं यदि आप ILogger को लागू करना चाहते हैं:

public class EntityFrameworkSqlLogger : ILogger
{
    #region Fields
    Action<EntityFrameworkSqlLogMessage> _logMessage;
    #endregion
    #region Constructor
    public EntityFrameworkSqlLogger(Action<EntityFrameworkSqlLogMessage> logMessage)
    {
        _logMessage = logMessage;
    }
    #endregion
    #region Implementation
    public IDisposable BeginScope<TState>(TState state)
    {
        return default;
    }
    public bool IsEnabled(LogLevel logLevel)
    {
        return true;
    }
    public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
    {
        if (eventId.Id != 20101)
        {
            //Filter messages that aren't relevant.
            //There may be other types of messages that are relevant for other database platforms...
            return;
        }
        if (state is IReadOnlyList<KeyValuePair<string, object>> keyValuePairList)
        {
            var entityFrameworkSqlLogMessage = new EntityFrameworkSqlLogMessage
            (
                eventId,
                (string)keyValuePairList.FirstOrDefault(k => k.Key == "commandText").Value,
                (string)keyValuePairList.FirstOrDefault(k => k.Key == "parameters").Value,
                (CommandType)keyValuePairList.FirstOrDefault(k => k.Key == "commandType").Value,
                (int)keyValuePairList.FirstOrDefault(k => k.Key == "commandTimeout").Value,
                (string)keyValuePairList.FirstOrDefault(k => k.Key == "elapsed").Value
            );
            _logMessage(entityFrameworkSqlLogMessage);
        }
    }
    #endregion
}

1

चर के साथ EF Core 3.1 के लिए, मेरे पास निम्नलिखित है ( हैलो से कुछ GitHub टिप्पणियों के आधार पर ) जो @ Thom Kesewetter et al से टिप्पणी में ऊपर लिंक किया गया था ।

/// <summary>
/// SQL Extension methods to get the SQL and check correctness
/// Class can be removed with EF Core 5 (https://github.com/dotnet/efcore/issues/6482#issuecomment-587605366) (although maybe variable substitution might still be necessary if we want them inline)
/// </summary>
public static class SqlExtensions
{
    private static object Private(this object obj, string privateField) => obj?.GetType().GetField(privateField, BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(obj);
    private static T Private<T>(this object obj, string privateField) => (T)obj?.GetType().GetField(privateField, BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(obj);

    /// <summary>
    /// Gets a SQL statement from an IQueryable
    /// </summary>
    /// <param name="query">The query to get the SQL statement for</param>
    /// <returns>Formatted SQL statement as a string</returns>
    public static string ToQueryString<TEntity>(this IQueryable<TEntity> query) where TEntity : class
    {
        using var enumerator = query.Provider.Execute<IEnumerable<TEntity>>(query.Expression).GetEnumerator();
        var relationalCommandCache = enumerator.Private("_relationalCommandCache");
        var selectExpression = relationalCommandCache.Private<SelectExpression>("_selectExpression");
        var factory = relationalCommandCache.Private<IQuerySqlGeneratorFactory>("_querySqlGeneratorFactory");
        var relationalQueryContext = enumerator.Private<RelationalQueryContext>("_relationalQueryContext");

        var sqlGenerator = factory.Create();
        var command = sqlGenerator.GetCommand(selectExpression);
        var parametersDict = relationalQueryContext.ParameterValues;

        return SubstituteVariables(command.CommandText, parametersDict);
    }

    private static string SubstituteVariables(string commandText, IReadOnlyDictionary<string, object> parametersDictionary)
    {
        var sql = commandText;
        foreach (var (key, value) in parametersDictionary)
        {
            var placeHolder = "@" + key;
            var actualValue = GetActualValue(value);
            sql = sql.Replace(placeHolder, actualValue);
        }

        return sql;
    }

    private static string GetActualValue(object value)
    {
        var type = value.GetType();

        if (type.IsNumeric())
            return value.ToString();

        if (type == typeof(DateTime) || type == typeof(DateTimeOffset))
        {
            switch (type.Name)
            {
                case nameof(DateTime):
                    return $"'{(DateTime)value:u}'";

                case nameof(DateTimeOffset):
                    return $"'{(DateTimeOffset)value:u}'";
            }
        }

        return $"'{value}'";
    }

    private static bool IsNullable(this Type type)
    {
        return
            type != null &&
            type.IsGenericType &&
            type.GetGenericTypeDefinition() == typeof(Nullable<>);
    }

    private static bool IsNumeric(this Type type)
    {
        if (IsNullable(type))
            type = Nullable.GetUnderlyingType(type);

        if (type == null || type.IsEnum)
            return false;

        return Type.GetTypeCode(type) switch
        {
            TypeCode.Byte => true,
            TypeCode.Decimal => true,
            TypeCode.Double => true,
            TypeCode.Int16 => true,
            TypeCode.Int32 => true,
            TypeCode.Int64 => true,
            TypeCode.SByte => true,
            TypeCode.Single => true,
            TypeCode.UInt16 => true,
            TypeCode.UInt32 => true,
            TypeCode.UInt64 => true,
            _ => false
        };
    }
}

यह शायद सभी प्रकारों को स्थानापन्न नहीं करता है लेकिन अधिकांश कवर किए जाते हैं। बेझिझक विस्तार करें।


0

एक सार्वजनिक सेवा के रूप में:

    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 .NET .NET 1.0 के लिए, I.NETableExtensions .NET .NET कोर 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.1.1 के साथ, यह अब काम नहीं करता है। निजी स्थैतिक रूप से आसानी से पता लगाने में त्रुटि
स्टेफ हेयानाथ

@Stef Heyenrath: मुझे लगता है कि मेरा उत्तर स्पष्ट रूप से .NET कोर 1.0 और 2.0 बताता है और 2.1 या 2.2 नहीं। अन्य ने पहले से ही 2.2, 3.0 और 3.1 के लिए कोड दिया है। .NET कोर 2.1 उस समय जारी नहीं किया गया था जब मैंने यह उत्तर लिखा था। यह .NET कोर 2.0 और 1.0 के लिए पूरी तरह से मान्य है
स्टीफन स्टीगर

0

EF Core 3 और इसके बाद के संस्करण के लिए, EFCore.BulkExtensions में एक ToParametrizedSql विधि है। मेरा एकमात्र सार यह है कि यह Microsoft.Data.SqlClient के रूप में मापदंडों को लौटाता है, इसलिए कभी-कभी मुझे उन्हें System.Data.SqlClient में बदलना होगा यदि वह मेरा कनेक्शन प्रकार है।

https://github.com/borisdj/EFCore.BulkExtensions

EFCore.BulkExtensions.IQueryableExtensions.ToParametrizedSql
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.