目次
概要
Entity Framework Core (EF Core) が裏側でどのようなSQLを発行しているかを可視化し、デバッグやパフォーマンス分析を行うための実装です。 DbContext の設定で LogTo メソッドを使用し、標準出力(コンソール)にリアルタイムでクエリ情報を流します。
仕様(入出力)
- 入力: 検索したいタスクの優先度(文字列)。
- 出力: 実行されたSQL文と、検索条件にヒットしたタスク一覧。
- 前提: .NET 6.0以上。
Microsoft.EntityFrameworkCore.Sqliteを使用。
基本の使い方
OnConfiguring メソッド内で LogTo を呼び出します。情報の氾濫を防ぐため、DbLoggerCategory でSQLコマンドのみにフィルタリングします。
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
options.UseSqlite("Data Source=mydb.db")
.LogTo(
Console.WriteLine, // 出力先
new[] { DbLoggerCategory.Database.Command.Name }, // SQL実行ログのみ
LogLevel.Information // 情報レベル
)
.EnableSensitiveDataLogging(); // パラメータ値も表示
}
コード全文
ここでは「タスク管理システム」を題材に、特定の優先度のタスクを検索した際に、どのような SELECT 文が発行されるかを確認します。
外部ライブラリとして Microsoft.EntityFrameworkCore.Sqlite が必要です。
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. データの準備(ログ出力付きContextを使用)
using (var context = new TaskDbContext())
{
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();
if (!context.Tasks.Any())
{
context.Tasks.AddRange(
new TaskItem { Title = "バグ修正", Priority = "High", DueDate = DateTime.Now.AddDays(1) },
new TaskItem { Title = "ドキュメント作成", Priority = "Low", DueDate = DateTime.Now.AddDays(5) },
new TaskItem { Title = "定例会議", Priority = "High", DueDate = DateTime.Now }
);
await context.SaveChangesAsync();
}
}
Console.WriteLine("\n=== SQLログの確認開始 ===\n");
// 2. 検索処理の実行
using (var context = new TaskDbContext())
{
var manager = new TaskManager(context);
// "High" のタスクを検索
// ここでコンソールに SELECT 文が表示されます
await manager.PrintTasksByPriorityAsync("High");
}
}
}
// 業務ロジッククラス
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[検索結果: 優先度 {priority}]");
foreach (var task in tasks)
{
Console.WriteLine($"- {task.Title} (期限: {task.DueDate:MM/dd})");
}
}
}
// エンティティ定義
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定義
public class TaskDbContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// SQLiteデータベース接続
optionsBuilder.UseSqlite("Data Source=tasks_debug.db");
// 【ログ出力設定】
// Console.WriteLine にログを流す
optionsBuilder.LogTo(
action: Console.WriteLine,
// フィルタ: SQLコマンド実行イベントのみを通す(これをしないと接続確立等のログで埋まる)
events: new[] { DbLoggerCategory.Database.Command.Name },
minimumLevel: LogLevel.Information
);
// 【機密データログ設定】
// SQLパラメータの値(WHERE Priority = ? の中身)を出力する設定
// ※本番環境では無効にすること
optionsBuilder.EnableSensitiveDataLogging();
}
}
コンソール出力例
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"
[検索結果: 優先度 High]
- 定例会議 (期限: 01/16)
- バグ修正 (期限: 01/17)
カスタムポイント
- 出力先の変更: コンソールアプリ以外の場合、
Console.WriteLineをSystem.Diagnostics.Debug.WriteLineに変更すると、IDEの出力ウィンドウで確認できます。 - 例外時のみ出力: 常にログを出すのではなく、エラー発生時のみ詳細を知りたい場合は、
DbCommandInterceptorを継承したクラスを作成し、CommandFailedメソッド内でのみログ出力を行う高度な方法もあります。 - クエリ文字列の取得: 実行せずにSQL文字列だけ欲しい場合、EF Core 5.0以降では以下のように書けます。C#
var query = context.Tasks.Where(t => t.Priority == "High"); string sql = query.ToQueryString(); // SQL文字列を取得
注意点
- 機密情報の取り扱い:
EnableSensitiveDataLoggingを有効にすると、ユーザー名やパスワードなどの個人情報がログにそのまま出力されます。開発環境(Development)以外では絶対に使用しないでください。 - パフォーマンス: コンソール出力は同期的なI/O処理であり、比較的高負荷です。本番環境で大量のアクセスがある場合、パフォーマンス低下の主因になります。
- フィルタリング:
events引数を省略すると、データベース接続のオープン/クローズ、トランザクション開始など、大量の内部イベントが出力され、肝心のSQLが見つけにくくなります。
応用
開発環境でのみ有効にする設定 (ASP.NET Core)
appsettings.json の設定値を使い、環境ごとにログレベルを切り替えるのが一般的です。コードを変更する必要がなくなります。
appsettings.Development.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
// SQLコマンドのログレベルだけを下げる
"Microsoft.EntityFrameworkCore.Database.Command": "Information"
}
}
}
まとめ
「データが取れない」「クエリが遅い」と感じたら、まずはこの設定で実際のSQLを確認してください。
LogTo メソッドを使えば、1行追加するだけで発行されるSQLを確認できます。
DbLoggerCategory.Database.Command.Name でフィルタリングすることで、SQL文だけを効率よく抽出できます。
