如何在EF Core中显示底层SQL查询?

129

在这个.NET Core 2.0发布!视频的倒数3:15,Diego Vega演示了Entity Framework Core 2.0中的新功能。其中一部分是在控制台应用程序中显示底层SQL的数据转储。

输入图像描述文字

我看到Stack Overflow上有很多答案建议使用SQL Profiler来查看底层查询。但现在我很好奇:你怎么能做到Diego Vega所做的事情,并在应用程序中直接显示查询呢?

针对.NET 6+的更新:在开发中,默认启用了EF日志记录。请参阅此GitHub问题

更新:Diego将"Microsoft.EntityFrameworkCore.Database.Command":"Information"添加到appsettings.Development.json。有关详细信息,请参见如何在EF Core中显示底层SQL查询?


2
显然他正在使用EF Core Logging,很可能是使用过滤器if (eventId.Id == Microsoft.EntityFrameworkCore.Diagnostics.RelationalEventId.CommandExecuted.Id) - Ivan Stoev
4
只需在 appsettings.Development.json 中添加 "Microsoft.EntityFrameworkCore.Database.Command": "Information" 即可。 - RickAndMSFT
12个回答

170

.NET 6及以上版本更新:在开发环境中,默认已启用EF日志记录。

只需将"Microsoft.EntityFrameworkCore.Database.Command": "Information" 添加到appsettings.Development.json文件中,因此仅在dev模式下记录。通常您不希望记录生产应用程序中的每个查询。

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=MyDB-2;Trusted_Connection=True;MultipleActiveResultSets=true"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
     ,"Microsoft.EntityFrameworkCore.Database.Command": "Information"
    }
  },
  "AllowedHosts": "*"
}

SQL的输出将显示在命令窗口或VS输出窗口中。

在此输入图像描述

请参阅官方文档中的Entity Framework Core的SQL日志记录。在旧版本中,这是一个错误,因为默认情况下它没有记录,参见这个GitHub问题


2
对我来说最好的答案。非常感谢。 - Uwe Keim
2
终于!为了解决这个问题我已经搜索了很久。到目前为止,这是最简单的解决方案。 - AGB
2
这只是EF Core 5吗? - xr280xr
1
优秀的答案。 - zeeqzaq
3
这里需要注意的是,使用VS 2022时,增加的日志记录量会导致调试时性能严重下降。除非你正在调试加载旋转器,否则建议仅在必要时启用它。 - joakimriedel
显示剩余15条评论

105

嗨,您可以像下面这样做来在输出窗口中显示Entity Framework Core生成的SQL代码。 在您的 DbContext 类中:

public static readonly Microsoft.Extensions.Logging.LoggerFactory _myLoggerFactory = 
    new LoggerFactory(new[] { 
        new Microsoft.Extensions.Logging.Debug.DebugLoggerProvider() 
    });

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.UseLoggerFactory(_myLoggerFactory);
}

当调试器附加时,调试记录器会将消息写入调试输出窗口。

您需要执行以下操作:

  • 使用Microsoft.Extensions.Logging;
  • 安装nuget包:Microsoft.Extensions.Logging.Debug

3
如果您正在使用 Database First (Scaffold-DbContext),并且您的 DbContext 可能会被重新生成,这将直接覆盖您对 OnConfiguring 所做的任何更改,那该怎么办呢? - xr280xr
1
就是这么简单。其他所有的解决方案都是不必要地复杂。谢谢。 - PepeDeLew
1
更简单的方法,见下面我的回答:只需将 "Microsoft.EntityFrameworkCore.Database.Command": "Information" 添加到 appsettings.Development.json 中,这样它只会在开发模式下记录日志。 - RickAndMSFT
有没有使用Serilog的想法? - sinsedrix
1
谢谢,它在 asp net core 2.2 中完美运行。 - Árthur

42

我使用 EF Core 3.x,这个方法适用于我的情况:

services.AddDbContext<LibraryContext>(options => options
    .UseLoggerFactory(LoggerFactory.Create(builder => builder.AddConsole()))
    .UseSqlServer(Configuration.GetConnectionString("LibraryDemoSql")));

信用:https://dev59.com/QFQJ5IYBdhLWcg3wdFh4#59663606


2
你在哪里可以看到SQL查询语句?我在输出窗口中没有看到它。 - Muflix
2
嗨@Muflix,这取决于你在哪里运行它。我的应用程序是Web API应用程序,我在Rider的IIS Express配置中运行它,SQL日志显示在“运行”窗口中。 - maximus
@maximus,感谢您的确认!这让我意识到我需要将我的Project->Properties->Debug->Launch设置更改为Project,而不是IIS Express。现在我已经打开了那个“控制台”窗口来查看查询。 - computercarguy
更简单的方法,请看下面我的回答:只需将“Microsoft.EntityFrameworkCore.Database.Command”:“Information”添加到appsettings.Development.json中,这样它只会在开发模式下记录。 - RickAndMSFT
3
这可能会引入内存泄漏。请参见此处的相关问题(https://dev59.com/jLzpa4cB1Zd3GeqPI1Vz#68183414)。 - Tulshi Das

41

EF Core >= 5

简单日志记录

Entity Framework Core (EF Core) 的简单日志记录可用于在开发和调试应用程序时轻松获取日志。这种形式的日志记录需要最少的配置,不需要额外的 NuGet 包。

LogTo Console

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder.LogTo(Console.WriteLine);

将日志输出到调试窗口

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder.LogTo(message => Debug.WriteLine(message));

记录到文件

private readonly StreamWriter _logStream = new StreamWriter("mylog.txt", append: true);

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder.LogTo(_logStream.WriteLine);

public override void Dispose()
{
    base.Dispose();
    _logStream.Dispose();
}

public override async ValueTask DisposeAsync()
{
    await base.DisposeAsync();
    await _logStream.DisposeAsync();
}

21

https://learn.microsoft.com/en-us/ef/core/miscellaneous/logging

DbContext的OnConfiguring方法中,您可以设置日志记录器,控制台日志是预定义类型,只需使用这个NuGet。请注意,对于日志记录器实例,使用工厂模式是最佳实践。
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .UseLoggerFactory(MyLoggerFactory) // Warning: Do not create a new ILoggerFactory instance each time
        .UseSqlServer(
            @"Server=(localdb)\mssqllocaldb;Database=EFLogging;Trusted_Connection=True;ConnectRetryCount=0");

1
更简单的方法,请看下面我的回答:只需将“Microsoft.EntityFrameworkCore.Database.Command”:“Information”添加到appsettings.Development.json中,这样它只会在开发模式下记录。 - RickAndMSFT

13
如果您只是寻找底层的 SQL,则dani herrera 的答案非常好。
但是,从 EF Core 5 开始(我不确定之前的版本),有一个称为 Debug View 的功能,我相信您会喜欢它。虽然这并不完全符合问题的要求,但这个调试视图包含了很多有用的信息,您不能忽略它们。
以下是几种获取到该功能的方法:
  1. 在上下文中放置断点,并按以下方式查找 Debug View。

ef core context model debug view

我已经展示了短视图,现在轮到你尝试长视图。在这里,您可以找到关于上下文持有的对象的有用信息。

  1. 如果您有一个 IQueryable 对象,请尝试以下方法。这也应该很有用。请注意,在此处查询尚未发送到数据库。因此,在这里,您将获得 EF Core 即将发送到数据库的查询。

ef core IQueryable Debug View

还要注意,您可以在 IQueryable 对象上调用 ToQueryString() 方法以获取相同的查询!

queryable.ToQueryString()
  1. 最后但并非最不重要的,尝试在上下文中的更改跟踪器对象上使用调试视图。

Ef Core上更改跟踪器的调试视图

该图显示了在调用保存更改方法之前的状态。观察在调用保存更改方法之后发生的情况(按F10,然后再次观察)。


1
看起来很棒。很高兴学习它! - dani herrera

11

在 .Net Core 3 中,可以使用 AddDebug 写入输出调试窗口。

要将日志写入 Visual Studio 输出窗口,请使用相应的方法。

services.AddDbContext<LibraryContext>(options => options
            .UseLoggerFactory(LoggerFactory.Create(builder => builder.AddDebug()))
            .UseSqlServer(Configuration.GetConnectionString("key")));

输出窗口是“调试”。当作为控制台应用程序运行时,控制台是控制台窗口。 - N-ate

11

我相信被接受的答案是可行的,但我想知道如何使用依赖注入来做到这一点...

private readonly ILoggerFactory loggerFactory;  

public MyDataContext(DbContextOptions<MyDataContext> options, ILoggerFactory loggerFactory)
        : base(options)
{
    this.loggerFactory = loggerFactory;
}

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)  
{
    // Allow null if you are using an IDesignTimeDbContextFactory
    if (loggerFactory != null)
    { 
        if (Debugger.IsAttached)
        {
            // Probably shouldn't log sql statements in production
            optionsBuilder.UseLoggerFactory(this.loggerFactory); 
        }
    }
} 

10

如果您使用的是EF Core 5,您的查询将具有一个Query属性和一个ToQueryString()方法,可以调用该方法来检索查询字符串。请注意,这些属性/方法仅适用于查询,而不是结果 - 通常没有中间查询变量,因为它们会立即运行,因此最容易将形成并运行的查询分成两个步骤以进行调试:

//before
return db.Person.Where(p => p.Name == "John").ToList();

//after; q has Query/ToQueryString()
var q = db.Person.Where(p => p.Name == "John");
return q.ToList();

在此输入图片描述

图片来自Eamon Keene的博客,该博客还详细介绍了如何设置日志记录。


1
简单而强大的解决方案。它也适用于 .net 6。 - Denny Jacob
它起作用了...但是,EF通过ChangeTracker创建了各种查询,你永远无法访问实际的查询字符串。最好只要打开SQL日志记录即可。 - Auspex

5

如果你正在基于ASP.NET Core MVC框架编写API或应用服务,你可以像这样在Startup.cs类中启用SQL日志记录:

public void ConfigureServices(IServiceCollection services)
{
    ...

    Action<DbContextOptionsBuilder> dbOptionsContextBuilder = builder => 
        {
        builder.UseSqlServer(Configuration.DbConnection)  // Configuration.DbConnection is the db connection string
               .UseLoggerFactory(ConsoleLoggerFactory);   // Logs out SQL
        };

    services.AddDbContext<YourDatabaseContext>(dbOptionsContextBuilder);


    ...
}

此处引用了之前定义的ConsoleLoggerFactory,类似以下代码:

private static readonly LoggerFactory ConsoleLoggerFactory = new LoggerFactory(new[] { new ConsoleLoggerProvider((_, __) => true, true) });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接