bucket-sort logo bucket-sort

プログラミングとインフラエンジニアリングの覚え書き

  • Posts
  • About
  • Contact
  1. Home
  2. All Posts
  3. [C#] EF Core の便利な問い合わせ機能を使う

[C#] EF Core の便利な問い合わせ機能を使う

Aug 2, 2026 C# , .NET , Entity Framework Core bucket-sort

前回は、EF Core の更新と削除を見ました。

今回は、実務で役立つ問い合わせ系の機能をまとめます。
グローバルフィルター、生 SQL、投影、データベース生成値、関数呼び出し、バッチ処理です。

グローバルフィルター

論理削除を導入すると、通常の検索では削除済みデータを除外したくなります。

public sealed class Car
{
    public int Id { get; set; }
    public string Make { get; set; } = "";
    public string Color { get; set; } = "";
    public string PetName { get; set; } = "";
    public bool IsDeleted { get; set; }
}

毎回 Where(car => !car.IsDeleted) を書くのは面倒です。
そこで、モデル設定でフィルターを定義します。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Car>()
        .HasQueryFilter(car => !car.IsDeleted);
}

これで、通常の context.Cars への問い合わせでは、削除済みデータが自動的に除外されます。

List<Car> cars = await context.Cars.ToListAsync();

必要に応じてフィルターを無視できます。

List<Car> allCars = await context.Cars
    .IgnoreQueryFilters()
    .ToListAsync();

グローバルフィルターは便利ですが、暗黙的に条件が追加されるため、管理画面や集計処理では意識しておく必要があります。

生 SQL と LINQ を組み合わせる

EF Core では、生 SQL を入口にして LINQ を続けることができます。

List<Car> cars = await context.Cars
    .FromSqlRaw("""
        SELECT Id, Make, Color, PetName, IsDeleted
        FROM Inventory
        WHERE Make = {0}
        """, "Honda")
    .Where(car => car.Color == "Blue")
    .ToListAsync();

FromSqlRaw() ではパラメーターを使い、値を直接文字列結合しないようにします。

より安全で読みやすい補間版もあります。

string make = "Honda";

List<Car> cars = await context.Cars
    .FromSqlInterpolated($"""
        SELECT Id, Make, Color, PetName, IsDeleted
        FROM Inventory
        WHERE Make = {make}
        """)
    .ToListAsync();

補間文字列で書いていますが、値は SQL パラメーターとして扱われます。

生 SQL を使う場面

生 SQL は、次のような場面で役立ちます。

  • 複雑な SQL を直接書きたい
  • データベース固有機能を使いたい
  • 既存の SQL を活用したい
  • パフォーマンス確認済みのクエリを使いたい
  • ストアドプロシージャを呼びたい

ただし、EF Core の変更追跡やモデルとの整合性を意識する必要があります。
結果列がエンティティの形と合わない場合は、DTO やキーなし型を検討します。

DTO へ投影する

画面や API では、エンティティ全体ではなく必要な項目だけ返したいことが多いです。

public sealed class CarSummary
{
    public int Id { get; init; }
    public string DisplayName { get; init; } = "";
    public int OrderCount { get; init; }
}
List<CarSummary> summaries = await context.Cars
    .AsNoTracking()
    .Select(car => new CarSummary
    {
        Id = car.Id,
        DisplayName = car.Color + " " + car.Make + " (" + car.PetName + ")",
        OrderCount = car.Orders.Count
    })
    .ToListAsync();

投影を使うと、必要な列と集計だけを取得できます。
エンティティをそのまま外へ返すより、API の契約も安定します。

データベース生成値

主キーの自動採番、作成日時、更新日時など、データベース側で生成される値があります。

public sealed class Car
{
    public int Id { get; set; }
    public string Make { get; set; } = "";
    public string Color { get; set; } = "";
    public string PetName { get; set; } = "";
    public DateTime CreatedAt { get; set; }
}

設定例です。

modelBuilder.Entity<Car>()
    .Property(car => car.CreatedAt)
    .HasDefaultValueSql("SYSUTCDATETIME()");

追加時に CreatedAt を設定しなくても、データベース側で値が入ります。

Car car = new Car
{
    Make = "Honda",
    Color = "Blue",
    PetName = "Vega"
};

context.Cars.Add(car);
await context.SaveChangesAsync();

Console.WriteLine(car.CreatedAt);

保存後、生成された値がエンティティへ反映されます。

データベース関数をマッピングする

データベース関数を C# メソッドとして表現できます。

public static class DbFunctions
{
    public static int PetNameLength(string value)
        => throw new NotSupportedException();
}

設定例です。

modelBuilder
    .HasDbFunction(typeof(DbFunctions).GetMethod(nameof(DbFunctions.PetNameLength))!)
    .HasName("LEN");

問い合わせで使います。

List<Car> cars = await context.Cars
    .Where(car => DbFunctions.PetNameLength(car.PetName) > 3)
    .ToListAsync();

このメソッドは C# 側で実行するためのものではなく、SQL へ変換するための記述です。
メソッド本体で例外を投げているのは、クライアント側で直接実行される想定ではないためです。

EF.Functions を使う

EF Core には、データベース関数を呼び出すための入口があります。

List<Car> cars = await context.Cars
    .Where(car => EF.Functions.Like(car.PetName, "%a%"))
    .ToListAsync();

Like は SQL の LIKE に変換されます。
文字列検索を SQL 側で表現したい場合に便利です。

データベースごとに使える関数は異なります。
プロバイダー固有の拡張もあるため、対象DBの機能を意識して使いましょう。

ステートメントのまとめ実行

EF Core は、複数の変更を SaveChanges() でまとめて送ります。

context.Cars.Add(new Car { Make = "Honda", Color = "Blue", PetName = "A" });
context.Cars.Add(new Car { Make = "Ford", Color = "Red", PetName = "B" });
context.Cars.Add(new Car { Make = "Toyota", Color = "Black", PetName = "C" });

await context.SaveChangesAsync();

1 件ごとに SaveChanges() を呼ぶより、まとめて呼ぶ方が効率的です。

避けたい例です。

foreach (Car car in cars)
{
    context.Cars.Add(car);
    await context.SaveChangesAsync();
}

推奨例です。

context.Cars.AddRange(cars);
await context.SaveChangesAsync();

大量データでは専用の一括投入手段も検討しますが、通常の追加なら SaveChanges() の回数を減らすだけでも効果があります。

まとめ

EF Core には、実務で役立つ便利な機能が多くあります。

グローバルフィルターは論理削除やテナント分離に有効です。
生 SQL は複雑な問い合わせやデータベース固有機能に使えます。
投影は画面や API に必要な形だけ取得するために重要です。

次回は、同時実行制御、接続回復、値変換、シャドウプロパティ、履歴テーブルなど、より設計寄りの機能を見ていきます。

C# .NET Entity Framework Core クエリフィルター FromSql 投影 EF.Functions
← [C#] EF Core で更新と削除を扱う [C#] EF Core の実務向け機能を理解する →

Related Posts

  • [C#] EF Core でデータベースの準備と初期データを扱う Aug 8, 2026
  • [C#] EF Core とリポジトリでデータ操作を整理する Aug 7, 2026
  • [C#] DbContext の設定と保存処理を拡張する Aug 6, 2026
  • [C#] EF Core のエンティティと表示用モデルを設計する Aug 5, 2026

Table of Contents

  • グローバルフィルター
  • 生 SQL と LINQ を組み合わせる
  • 生 SQL を使う場面
  • DTO へ投影する
  • データベース生成値
  • データベース関数をマッピングする
  • EF.Functions を使う
  • ステートメントのまとめ実行
  • まとめ

Recent Posts

  • [C#] EF Core でデータベースの準備と初期データを扱う Aug 8, 2026
  • [C#] EF Core とリポジトリでデータ操作を整理する Aug 7, 2026
  • [C#] DbContext の設定と保存処理を拡張する Aug 6, 2026
  • [C#] EF Core のエンティティと表示用モデルを設計する Aug 5, 2026
  • [C#] EF Core を中心にデータアクセス層を分ける Aug 4, 2026

Categories

  • C#150
  • .NET149
  • AWS27
  • Laravel16
  • Entity Framework Core15
  • Linux15
  • MySQL9
  • Apache8
  • PHP8
  • Data Access6
  • DynamoDB6
  • セキュリティ6
  • Nginx5
  • WordPress4
  • インフラ4
  • Hugo3
  • .NET Framework1
  • Aurora1
  • Diagnostics1
  • Filament1

Tags

  • C#
  • .NET
  • AWS
  • Laravel
  • コレクション
  • PHP
  • Entity Framework Core
  • セキュリティ
  • MySQL
  • Linux
  • パフォーマンス
  • Apache
  • LINQ
  • System.Collections.Generic
  • デリゲート
  • リフレクション
  • ADO.NET
  • Code Snippet
  • DynamoDB
  • NoSQL
  • PHP-FPM
  • RDS
  • System.Collections
  • Windows
  • メタデータ
  • メモリ管理
  • CIL
  • DoS
  • Nginx
  • SQL Server
  • WordPress
  • ラムダ式
  • 監視
  • 設計
  • Amazon Linux 2023
  • Delegate
  • Docker
  • IDisposable
  • Ipset
  • Iptables
  • LINQ to Objects
  • OPCache
  • Pointer
  • Reflection
  • System.Collections.Specialized
  • Unsafe
  • Webサーバー
  • アセンブリ
  • インターフェース
  • オブジェクト指向
Powered by Hugo & Explore Theme.