[C#] How to Log SQL Executed by EF Core to the Console

目次

Overview

This implementation allows you to visualize the SQL commands that Entity Framework Core (EF Core) executes in the background. This is useful for debugging and performance analysis. By using the LogTo method in the DbContext configuration, you can see query information in real-time within the standard output (console).

Specifications (Input/Output)

  • Input: Priority level of tasks to search (string).
  • Output: The executed SQL statement and a list of tasks that match the search criteria.
  • Prerequisites: .NET 6.0 or higher. Uses Microsoft.EntityFrameworkCore.Sqlite.

Basic Usage

Call LogTo inside the OnConfiguring method. To avoid too much information, use DbLoggerCategory to filter for only SQL commands.

protected override void OnConfiguring(DbContextOptionsBuilder options)
{
    options.UseSqlite("Data Source=mydb.db")
        .LogTo(
            Console.WriteLine, // Output destination
            new[] { DbLoggerCategory.Database.Command.Name }, // Only SQL execution logs
            LogLevel.Information // Log level
        )
        .EnableSensitiveDataLogging(); // Show parameter values
}

Full Code Example

In this example, we use a “Task Management System” to see what SELECT statement is issued when searching for tasks with a specific priority. You will need the Microsoft.EntityFrameworkCore.Sqlite package.

dotnet add package Microsoft.EntityFrameworkCore.Sqlite
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

public class Program
{
    public static async Task Main()
    {
        // 1. Prepare data (using Context with logging enabled)
        using (var context = new TaskDbContext())
        {
            await context.Database.EnsureDeletedAsync();
            await context.Database.EnsureCreatedAsync();

            if (!context.Tasks.Any())
            {
                context.Tasks.AddRange(
                    new TaskItem { Title = "Bug Fix", Priority = "High", DueDate = DateTime.Now.AddDays(1) },
                    new TaskItem { Title = "Create Docs", Priority = "Low", DueDate = DateTime.Now.AddDays(5) },
                    new TaskItem { Title = "Weekly Meeting", Priority = "High", DueDate = DateTime.Now }
                );
                await context.SaveChangesAsync();
            }
        }

        Console.WriteLine("\n=== Starting SQL Log Verification ===\n");

        // 2. Execute search
        using (var context = new TaskDbContext())
        {
            var manager = new TaskManager(context);
            // Search for "High" priority tasks
            // The SELECT statement will appear in the console here
            await manager.PrintTasksByPriorityAsync("High");
        }
    }
}

// Business Logic Class
public class TaskManager
{
    private readonly TaskDbContext _context;

    public TaskManager(TaskDbContext context)
    {
        _context = context;
    }

    public async Task PrintTasksByPriorityAsync(string priority)
    {
        var tasks = await _context.Tasks
            .Where(t => t.Priority == priority)
            .OrderBy(t => t.DueDate)
            .ToListAsync();

        Console.WriteLine($"\n[Search Result: Priority {priority}]");
        foreach (var task in tasks)
        {
            Console.WriteLine($"- {task.Title} (Due: {task.DueDate:MM/dd})");
        }
    }
}

// Entity Definition
public class TaskItem
{
    public int Id { get; set; }
    public string Title { get; set; } = string.Empty;
    public string Priority { get; set; } = string.Empty; // High, Medium, Low
    public DateTime DueDate { get; set; }
}

// DbContext Definition
public class TaskDbContext : DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        // SQLite database connection
        optionsBuilder.UseSqlite("Data Source=tasks_debug.db");

        // [Logging Configuration]
        // Send logs to Console.WriteLine
        optionsBuilder.LogTo(
            action: Console.WriteLine,
            // Filter: Only pass SQL command execution events
            // This prevents the log from being filled with connection status, etc.
            events: new[] { DbLoggerCategory.Database.Command.Name },
            minimumLevel: LogLevel.Information
        );

        // [Sensitive Data Logging]
        // Setting to output SQL parameter values (e.g., the content of WHERE Priority = ?)
        // *Disable this in production environments*
        optionsBuilder.EnableSensitiveDataLogging();
    }
}

Example Console Output

info: 1/16/2026 10:00:00.000 ... (Microsoft.EntityFrameworkCore.Database.Command)
      Executed DbCommand (2ms) [Parameters=[@__priority_0='High' (Size = 4)], CommandType='Text', CommandTimeout='30']
      SELECT "t"."Id", "t"."DueDate", "t"."Priority", "t"."Title"
      FROM "Tasks" AS "t"
      WHERE "t"."Priority" = @__priority_0
      ORDER BY "t"."DueDate"

[Search Result: Priority High]
- Weekly Meeting (Due: 01/16)
- Bug Fix (Due: 01/17)

Customization Points

  • Change Output Destination: In non-console applications, change Console.WriteLine to System.Diagnostics.Debug.WriteLine to view logs in the IDE’s output window.
  • Log Only on Exceptions: If you want logs only when an error occurs, you can use a more advanced method by inheriting from DbCommandInterceptor and logging within the CommandFailed method.
  • Get Query String: If you want the SQL string without executing it, you can use the following in EF Core 5.0 or later:C#var query = context.Tasks.Where(t => t.Priority == "High"); string sql = query.ToQueryString(); // Get the SQL string

Important Notes

  • Handling Sensitive Information: Enabling EnableSensitiveDataLogging will output personal data like usernames or passwords to the log. Never use this outside of development environments.
  • Performance: Console output is a synchronous I/O process and can be quite heavy. In a production environment with high traffic, it can become a major cause of performance degradation.
  • Filtering: If you omit the events argument, a large number of internal events (opening/closing connections, starting transactions, etc.) will be output, making it difficult to find the actual SQL statements.

Advanced Application

Enabling Only in Development (ASP.NET Core)

It is common to use configuration values in appsettings.json to switch log levels for each environment. This avoids having to change the code.

appsettings.Development.json

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      // Lower the log level only for SQL commands
      "Microsoft.EntityFrameworkCore.Database.Command": "Information"
    }
  }
}

Conclusion

Filtering with DbLoggerCategory.Database.Command.Name allows you to efficiently extract only the SQL statements.

If you feel that “data isn’t being retrieved” or “the query is slow,” check the actual SQL using this setting first.

By using the LogTo method, you can verify the issued SQL by adding just one line.

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次