একটি সত্তা ফ্রেমওয়ার্ক কোর আইকিউয়েরেবল <T> থেকে এসকিউএল কোড পান


92

আমি সত্তা ফ্রেমওয়ার্ক কোর ব্যবহার করছি এবং আমার দেখতে হবে কোন এসকিউএল কোড উত্পন্ন হচ্ছে। সত্তা ফ্রেমওয়ার্কের পূর্ববর্তী সংস্করণগুলিতে আমি নিম্নলিখিতগুলি ব্যবহার করতে পারি:

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

যেখানে ক্যোয়ারি একটি আইকোয়ারিযোগ্য অবজেক্ট ... তবে টুট্রেস স্ট্রিং ইএফ কোরটিতে উপলভ্য নয়।

আমি কীভাবে ইএফ কোর-তে অনুরূপ কিছু করতে পারি?



আপনি এটি চেষ্টা করতে পারেন: rion.io/2016/10/19/…
মাইকব্রিজ

উত্তর:


82

ইএফ কোর 5 / নেট 5

query.ToQueryString()EF কোর 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;
        }
    }

EF কোর 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;
        }

রোসিওলি থেকে গিস্টটি দেখুন

EF কোর 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);

ইএফ নেট কোর টিমও ইস্যুটি ট্র্যাক করেছে এবং পরবর্তী প্রকাশের জন্য নির্ধারিত হয়েছে।


4
আপনি কিভাবে এই একটি সঙ্গে কাজ করার লিখতে হবে একটি উদাহরণ দিতে পারেন IQueryableএবং না IQueryable<T>?
বাইরনেডো

আমি মনে করি আপনি সবসময় একটি আছে IQueryable<T>widgetউপরে উদাহরণ দেখুন । আপনার কি এমন একটি উদাহরণ রয়েছে যা কেবলমাত্র আইকোয়ারিযোগ্য?
থম কিসেওয়েটার

আমি ব্যবহার করছি github.com/StefH/System.Linq.Dynamic.Core , যা একটি আপনি দেয় IQueryableমাত্র
byrnedo

আপনার কাঠামোর মধ্যে আপনার প্রশ্নগুলি এনটিটি টাইপের <T> উপর ভিত্তি করে। টো এসকিএল-এর একটি এনটিটাইপ দরকার কারণ এটি স্কিল স্টেটমেন্ট তৈরি করতে ক্ষেত্র এবং সারণীর নাম জানতে হবে। এই তথ্য ছাড়া এটি করা যাবে না।
থম কিসেওয়েটার

4
var রিলেশনালকমন্ডড ক্যাশে = এনিউরেটর P প্রাইভেট ("_ রিলেশনালকম্যান্ডসিচে"); নাল
ফেরায়

81

এই উত্তরটি EF কোর 2.1 এর জন্য। EF কোর 3.0 এবং 3.1 এর জন্য @ থম কিয়েস্বেটারের উত্তর দেখুন

EF কোর 5 এর জন্য বিল্ট-ইন পদ্ধতি ToQueryString()ব্যবহার করা হবেIQueryable<>

যেহেতু ইএফ 7 এর নাম সত্তা ফ্রেমওয়ার্ক কোর নামকরণ করা হয়েছে আমি আপনাকে EF কোরের বিকল্পগুলির সংক্ষিপ্তসার করব।

এসকিউএল বিবৃতি লগ করার জন্য 3 টি পদ্ধতি রয়েছে IQueryable<>:

  • অন্তর্নির্মিত বা কাস্টম লগিং ব্যবহার করে । এই টিউটোরিয়ালটিতে উল্লিখিত হিসাবে আপনার পছন্দের লগার বা অন্তর্নির্মিত লগার ইন। নেট কোর ব্যবহার করে এক্সিকিউটিভ ক্যোয়ারি লগইন করা ।
  • একটি প্রোফাইলার ব্যবহার করে । এক্সিকিউটিভ কোয়েরি নিরীক্ষণের জন্য মিনিপ্রফিলারের মতো এসকিউএল প্রোফাইলার ব্যবহার করা ।
  • ব্যবহার ক্রেজি প্রতিফলন কোড । একই বেসিক ধারণাটি সম্পাদন করতে আপনি কিছু পুরানো পদ্ধতির অনুরূপ কিছু কাস্টম প্রতিবিম্ব কোড প্রয়োগ করতে পারেন।

এখানে পাগলের প্রতিবিম্ব কোড (এক্সটেনশন পদ্ধতি):

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 / রিওমনসটার / 2c59f449e67edf8cd6164e9fe66c545a


4
মন্তব্য করার জন্য আপনাকে ধন্যবাদ। আমি কোডটি আপডেট করেছি যাতে এখন এটি 2.1 এর সাথে কাজ করা উচিত।
নিকলে কোস্তভ

4
@ স্টেফেন ম্যানগোল্ড এটি ডিবাগিংয়ের উদ্দেশ্যে করা :) এটি দ্রুত হওয়ার উদ্দেশ্যে নয়।
নিকোলে কোস্তভ

4
@ রিকার্ডোপ্রেস: না, তারা রেওন.ও.আই.ও. / /201 / ১১ / ১৯ / ১৯ কে উল্লেখ করেছে , যা আপনার পোস্টকে জমা দেয়।
মার্টিজন পিটারস

4
অ্যালেক্সেই আমি ব্যবহার শুরু করেছি optionsBuilder.UseLoggerFactory(LoggerFactory); public static readonly LoggerFactory LoggerFactory = new LoggerFactory(new[] { new ConsoleLoggerProvider((_, __) => true, true) });কারণ এটি আরও বেশি সুন্দর স্কয়ার তৈরি করে, তবে দুর্ভাগ্যক্রমে অনেক স্প্যামও তৈরি হয়।
জোয়েল্টি

4
নেট কোর along.০ এর সাথে ইএফ কোর ৩.০ এখন জিএ-তে প্রকাশিত হয়েছে এবং পদ্ধতিটির ক্ষেত্রে এটি ব্রেকিং রয়েছে: টো এসকিএল। 3.0 এর জন্য কীভাবে এটি পুনরায় প্রতিস্থাপন করবেন কোনও ধারণা? আরও তথ্য: github.com/aspnet/EntityFrameworkCore/issues/18029
বরিশডজ

40

যে কারও জন্য কেবল এক-বিভ্রান্তিকর EF কোর ক্যোয়ারী বা এই জাতীয় কোডটি পরিবর্তন করতে চান না এবং তাদের কোড পরিবর্তন করতে চান না তা নির্ণয়ের চেষ্টা করছেন, কয়েকটি বিকল্প রয়েছে:

এসকিউএল সার্ভার ম্যানেজমেন্ট স্টুডিও (এসএসএমএস) এসকিউএল প্রোফাইলার ব্যবহার করুন

যদি আপনি এসকিউএল সার্ভার ম্যানেজমেন্ট স্টুডিও (এসএসএমএস) ইনস্টল করে থাকেন তবে আপনি এসএসএমএসের সরঞ্জাম মেনু থেকে এসকিউএল প্রোফাইলার সরিয়ে নিতে পারেন:

এসকিউএল সার্ভার ম্যানেজমেন্ট স্টুডিওতে (এসএসএমএস) সরঞ্জাম মেনুতে এসকিউএল প্রোফাইলার বিকল্প

এবং এসকিউএল প্রোফাইলার এ এটি খোলার পরে একটি নতুন ট্রেস চলমান শুরু করুন।

এরপরে আপনি EF এর থেকে আগত এসকিউএল অনুরোধটি দেখতে সক্ষম হবেন, তারা সাধারণত বেশ ভালভাবে গঠিত এবং পড়তে সহজ easy

ভিজ্যুয়াল স্টুডিওতে আউটপুট উইন্ডোটি পরীক্ষা করুন

আমার ভিএস2019 এর অনুলিপিতে, EF2.2 ব্যবহার করে আমি ওয়েব সার্ভার থেকে আউটপুট দেখানোর জন্য আউটপুট উইন্ডোটি পরিবর্তন করতে পারি (আউটপুট ফলকের শীর্ষে "আউটপুট দেখান" কম্বোতে আপনার অ্যাপ্লিকেশন এবং ওয়েব সার্ভারের নাম নির্বাচন করুন) এবং বহির্গামী এসকিউএলও সেখানে প্রদর্শিত হবে। আমি আমার কোডটি যাচাই করেছি এবং যতদূর আমি দেখতে পাচ্ছি যে এটি সক্ষম করার জন্য আমি কোনও কাজ করিনি, সুতরাং আমার মনে হয় এটি অবশ্যই ডিফল্টরূপে এটি করা উচিত:

এখানে চিত্র বর্ণনা লিখুন

আপনি যদি প্রশ্নগুলির মধ্যে এসকিউএল সার্ভারে প্রেরিত পরামিতিগুলি দেখতে চান তবে আপনি ডিবিসিঙ্কটেক্সটটি EnableSensitiveDataLoggingপদ্ধতির সাথে সেট আপ করার সময় এটি স্যুইচ করতে পারেন eg

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

@ টিচ - লিল 3 পি মন্তব্যগুলিতে উল্লেখ করেছে যে প্রজেক্টের প্রোপার্টি পৃষ্ঠাগুলির ডিবেগ ট্যাবে এসকিউএল ডিবাগিং চালু করার জন্য তাদের একটি সুইচও ব্যবহার করা দরকার (যা "sqlDebugging": trueলঞ্চসেটিংস.জেসনে সেট করে)। আমি চেক করেছি এবং আমার কোনও প্রকল্পের জন্য এটি চালু হয়নি, তবে উপরেরটি যদি আপনার জন্য কাজ না করে তবে এটির জন্যও পরীক্ষামূলক হওয়া উপযুক্ত।


4
আজুর স্কিল
এমিল

@ ব্যাটম্যাচি আমি আরও একটি পদ্ধতি যুক্ত করেছি যা
আজুরের

আমি ইএফ কোর থেকে আউটপুট পাব, তবে এটি আমাকে @__ p_0 ইত্যাদির জন্য ব্যবহার করে এমন ভেরিয়েবলগুলি দেখায় না
ডালেকিডি

@ ড্যালিকেডি যদি মেমরি আমাকে সঠিকভাবে সেবাদাত দেয় তবে এটি একটি সুরক্ষা সমস্যা - আমি মনে করি এমভিসি ডিফল্টরূপে প্যারামিটারগুলি গোপন করে কারণ তারা সংবেদনশীল ডেটা অন্তর্ভুক্ত করতে পারে। আমি মনে করি এমভিসির জন্য একটি ডিবাগিং বিকল্পের ফলে প্যারামিটারগুলি প্রদর্শিত হবে, তবে কোনটি মনে করতে পারছি না। আমার কোডটি সন্ধান করছি app.UseDeveloperExceptionPage()স্টার্টআপ.কনফিগুরে এবং services.AddServerSideBlazor() .AddCircuitOptions(options => { options.DetailedErrors = true; });স্টার্টআপ.কনফিগার সার্ভিসগুলিতে। এর মধ্যে একটি প্যারামিটার দেখায় পেতে পারে।
tomRedox

4
এই লিঙ্কটি আমাকে সহায়তা করেছে -> thecodebuzz.com/adding-logging-in-entity-framework-core
ইউরি কার্ডোসো

3

@ নিকোলে-কোস্টভ উত্তরের ভিত্তিতে আমার নেওয়া take

পার্থক্যটি হ'ল আমি হার্ড কোডিংয়ের পরিবর্তে প্যারামিটারগুলি সহ এসকিউএল কমান্ডটি পাই যা ইএফ কোর কীভাবে ডাটাবেসে কমান্ড প্রেরণ করে তার সাথে সামঞ্জস্য হয়। এছাড়াও, আপনি যদি ডাটাবেসটিতে কমান্ডটি সম্পাদনা করতে এবং প্রেরণ করতে চান তবে পরামিতিগুলি ব্যবহার করা আরও ভাল অনুশীলন।

    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

এই উত্তরটি যুক্ত করা হচ্ছে কারণ এখানে সমস্ত পরামর্শ নতুন ইএফ কোর রিলিজ (যেমন, এখানে সমস্ত উত্তর ইএফ কোর ২.২ এ বিভক্ত হয়েছে) এর সাথে বিভক্ত হয়েছে। এখানে প্রথম কোডটিতে আমার জন্য কাজ করা কোডটি এবং এটি মনে হচ্ছে। নেট কোর সংস্করণ অজ্ঞেয়বাদী (এখনও অবধি): https://blogs.msdn.microsoft.com/dbrowne/2017/09/22/simple-logging- জন্য -মাংসক /


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

এই পোস্ট থেকে

আপনি লোগার বাস্তবায়ন করতে চাইলে আপনি আরও তথ্য পেতে পারেন:

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 কোর 3.1 এর জন্য, আমার কাছে নিম্নলিখিতগুলি রয়েছে ( হললো থেকে কিছু গিটহাব মন্তব্যের ভিত্তিতে ) @ থম কিয়েসওয়েটার এট আল এর মন্তব্যে উপরের লিঙ্ক করা হয়েছে ।

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

এবং তারপরে এই এক্সটেনশন পদ্ধতিগুলি (। নেট কোর ১.০ এর জন্য আইকিউয়েরেবল এক্সটেনশনস ১,। নেট কোর ২.০ এর জন্য আইকিউয়েরেবল এক্সটেনশনগুলি):

    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 কোর 2.1.1 সহ, এটি আর কাজ করে না। প্রাইভেট স্ট্যাটিক রিডোনলি প্রোপার্টিআইনফো নোডটাইপপ্রাইভাইডারফিল্ড = কোয়েরি কমপাইলার টাইপআইএনফো D ডিক্লেয়ারডপ্রোপার্টি.সিংল (x => x.Name == "নোডটাইপপ্রভাইডার") এ ত্রুটি;
স্টিফ হেইনারথ

@ স্টেফ হেইনরথ: আমি আমার উত্তর পরিষ্কারভাবে বলেছি বলে মনে করি। নেট কোর 1.0 এবং 2.0 এবং, 2.1 বা 2.2 নয় 2. অন্যরা ইতিমধ্যে 2.2, 3.0 এবং 3.1 এর জন্য কোড দিয়েছে। আমি এই উত্তরটি লেখার সময় .NET কোর 2.1 প্রকাশ করা হয়নি। এটি নেট কোর 2.0 এবং 1.0 এর জন্য পুরোপুরি বৈধ
স্টিফান স্টিগার

0

EF কোর 3 এবং তদূর্ধেরের জন্য, EFCore.BulkExferences এর একটি ToParametriisedSQL পদ্ধতি রয়েছে। আমার একমাত্র গ্রিপ এটি মাইক্রোসফট.ডাটা.এসএকএলসিপ্লায়েন্ট হিসাবে প্যারামিটারগুলি ফিরিয়ে দেয়, তাই মাঝে মাঝে আমাকে সেগুলি System.Data.SqlClient এ রূপান্তর করতে হয় যদি তা আমার সংযোগের ধরণ হয়।

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

EFCore.BulkExtensions.IQueryableExtensions.ToParametrizedSql
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.