Невозможно получить полный текст SQL из запросов Entity Framework Core, содержащих Union

Я хочу сохранить sql, созданный запросами entity framework / LINQ для целей документации. Я использовал метод расширения IQueryable из этого сообщения в блоге, чтобы получить необработанный sql: http://rion.io/2016/10/19/accessing-entity-framework-core-queries-behind-the-scenes-in-asp-net-core/

Это отлично подходит для большинства моих запросов. Однако, когда я попытался получить sql из запроса, содержащего UNION, метод расширения вернул sql только для первой половины объединения, игнорируя вторую половину. Кто-нибудь знает, как получить sql до и после объединения?

Для воспроизводимости я использую

  • .NETCore v2.1.0
  • Entity Framework Core v2.1.3

Пример запроса EF / LINQ

        // Union query on DbContext with DbSet "Tables"
        var query = dbContext.Tables.Take(1).Union(dbContext.Tables.Take(2));

        // IQueryable Extension method
        var sql = query.ToSql();

        // Clean up SQL for easier reading
        sql = sql.Replace("\n", "").Replace("\r", "");

        // Value of sql (Missing second half of union)
        // SELECT TOP(1) [t].[Id], [t].[CreateDate], [t].[Description], [t].[DisplayName], [t].[Name], [t].[SourceId], [t].[Sql], [t].[Status]FROM [metadata].[Tables] AS [t]

Расширение 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;
    }
}
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
846
2

Ответы 2

Вместо этого используйте Linqpad и после получения результата выберите SQL, чтобы просмотреть получившийся sql. Обратите внимание, если вам нужны определенные библиотеки DLL из проекта, просто включите их в запрос.

Спасибо за Ваш ответ. Это может работать для получения SQL на специальной основе, но я хочу сохранить sql в базе данных и обновлять этот sql каждый раз при выполнении запроса. По сути, мой инструмент должен самодокументировать свой собственный sql для справки конечным пользователям.

Evan French 01.10.2018 16:03

Похоже, много работы с небольшой прибылью. Имейте в виду, что сгенерированный EF sql технически может изменяться с каждым выпуском. Если кому-то нужен такой документированный sql, почему бы не использовать / использовать хранимые процедуры для хранения бизнес-логики?

ΩmegaMan 01.10.2018 16:16

Я хочу позволить владельцам бизнеса увидеть, как рассчитываются их показатели, что добавит прозрачности в их процесс отчетности, который они считают невероятно ценным. Незначительные изменения по сравнению с более новыми версиями не имеют отношения к моему варианту использования. Расчет показателей может часто меняться, и такой подход гарантирует, что документация будет оставаться в актуальном состоянии.

Evan French 01.10.2018 16:26

Вы уверены, что получите полный SQL с методом расширения ToSql? Эта строка:

   var sql = modelVisitor.Queries.First().ToString();

Может ли Союз иметь два запроса?

Попробуйте сначала просмотреть запросы и, например, записать их в консоль.

foreach (var query in modelVisitor.Queries)
 Console.WriteLine(query);

Это вызовет toString () для каждого запроса. Вы видите весь запрос союза? Если это так, сделайте string.Join, чтобы объединить весь Sql.

Я тоже думал об этом, но modelVisitor.Queries содержит только одно значение. Однако у queryModel.ResultOperators есть два значения, соответствующие обеим половинам моего союза. Я подозреваю, что есть проблема с modelVisitor.CreateQueryExecutor<TEntity>(queryModel);, который, как я полагаю, заполняет modelVisitor.Queries только одним значением

Evan French 01.10.2018 16:10

Другие вопросы по теме