Невозможно получить полный текст SQL из запросов Entity Framework Core, содержащих Union - PullRequest
0 голосов
/ 28 сентября 2018

Я хочу сохранить sql, сгенерированный структурой сущности / запросами 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 Corev2.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;
    }
}

Ответы [ 2 ]

0 голосов
/ 29 сентября 2018

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

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

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

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

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

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

0 голосов
/ 28 сентября 2018

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

...