コンテンツにスキップ

統合言語クエリ

出典: フリー教科書『ウィキブックス(Wikibooks)』

第1章 LINQの基礎

[編集]

1.1 LINQとは

[編集]

統合言語クエリ(Language Integrated Query: LINQ)は、.NET Frameworkに組み込まれたデータクエリ機能です。データベースXML、メモリ上のコレクションなど、様々なデータソースに対して統一的な方法でクエリを記述することができます。

従来のプログラミングでは、データソースごとに異なる方法でデータ操作を行う必要がありました。たとえば、SQLデータベースにはSQL文を、XMLにはXPath式を使用するといった具合です。LINQの登場により、プログラマは単一の構文でこれらのデータソースを扱えるようになりました。

以下に簡単な例を示します:
// メモリ上のコレクションに対するLINQ
var numbers = new[] { 1, 2, 3, 4, 5 };
var evenNumbers = from n in numbers
                 where n % 2 == 0
                 select n;

// 同じクエリをメソッド構文で記述
var evenNumbers2 = numbers.Where(n => n % 2 == 0);

LINQの主な利点は、型安全性、IntelliSenseによるサポート、そしてデータソースに依存しない統一的なアプローチにあります。また、クエリの構文が宣言的であり、「何を」したいのかに焦点を当てて記述できることも大きな特徴です。

1.2 LINQの動作原理

[編集]

LINQの重要な特徴の一つが遅延評価(Lazy Evaluation)です。クエリを定義した時点ではデータは取得されず、実際にデータが必要になった時点で評価が行われます。

// クエリの定義(この時点では実行されない)
var query = from n in numbers
            where n > 3
            select n * 2;

// クエリの実行(この時点で評価が行われる)
foreach (var item in query)
{
    Console.WriteLine(item);
}

イミディエイト実行を行いたい場合は、ToList()やToArray()などのメソッドを使用します:

// 即座に評価が行われ、結果がリストに格納される
var results = query.ToList();

IEnumerable<T>とIQueryable<T>の違いも重要です。IEnumerable<T>はメモリ上のデータに対して操作を行う際に使用され、IQueryable<T>はデータベースなどの外部データソースに対して使用されます。

1.3 基本的なクエリ操作

[編集]

データソースの選択から始めて、フィルタリング、射影、並び替えといった基本的な操作を見ていきましょう。

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
    public string Category { get; set; }
}

// サンプルデータ
var products = new List<Product>
{
    new Product { Id = 1, Name = "ノートPC", Price = 80000, Category = "電化製品" },
    new Product { Id = 2, Name = "デスクトップPC", Price = 120000, Category = "電化製品" },
    new Product { Id = 3, Name = "キーボード", Price = 8000, Category = "周辺機器" }
};

// フィルタリング:特定の条件に合致するデータの取得
var expensiveProducts = from p in products
                       where p.Price > 100000
                       select p;

// 射影:必要なプロパティのみを選択
var productNames = from p in products
                  select p.Name;

// 並び替え:価格の昇順でソート
var sortedProducts = from p in products
                    orderby p.Price
                    select p;

これらの操作は、メソッド構文を使用して以下のように書くこともできます:

var expensiveProducts = products.Where(p => p.Price > 100000);
var productNames = products.Select(p => p.Name);
var sortedProducts = products.OrderBy(p => p.Price);

クエリ式とメソッド構文はどちらも同じ結果を生成しますが、状況に応じて読みやすい方を選択することができます。一般的に、単純な操作にはメソッド構文が、複雑な操作にはクエリ式が適しています。

第2章 データ操作

[編集]

2.1 集約操作

[編集]

データの集約操作は、コレクション全体から単一の値を導出する重要な機能です。LINQは様々な集約メソッドを提供しており、データ分析やレポート生成に活用できます。

最も基本的な集約操作として、Count、Sum、Average、Min、Maxがあります。

var products = new List<Product>
{
    new Product { Id = 1, Name = "ノートPC", Price = 80000, Category = "電化製品" },
    new Product { Id = 2, Name = "デスクトップPC", Price = 120000, Category = "電化製品" },
    new Product { Id = 3, Name = "キーボード", Price = 8000, Category = "周辺機器" },
    new Product { Id = 4, Name = "マウス", Price = 5000, Category = "周辺機器" }
};

decimal averagePrice = products.Average(p => p.Price);        // 平均価格
decimal totalPrice = products.Sum(p => p.Price);             // 総額
int productCount = products.Count();                         // 製品数
decimal maxPrice = products.Max(p => p.Price);              // 最高価格
decimal minPrice = products.Min(p => p.Price);              // 最低価格

より複雑な集約にはGroupByを使用します。GroupByはデータをカテゴリごとにグループ化し、各グループに対して集約操作を適用できます。

var categoryAnalysis = products.GroupBy(p => p.Category)
    .Select(g => new
    {
        Category = g.Key,
        AveragePrice = g.Average(p => p.Price),
        ProductCount = g.Count(),
        TotalRevenue = g.Sum(p => p.Price)
    });

foreach (var category in categoryAnalysis)
{
    Console.WriteLine($"カテゴリ: {category.Category}");
    Console.WriteLine($"平均価格: {category.AveragePrice:C}");
    Console.WriteLine($"製品数: {category.ProductCount}");
    Console.WriteLine($"総売上: {category.TotalRevenue:C}\n");
}

さらに柔軟な集約処理にはAggregateメソッドを使用します。Aggregateは任意の集約ロジックを実装できる強力なメソッドです。

// 製品名を「, 」で連結する例
string productList = products.Aggregate("製品リスト: ",
    (current, product) => current + product.Name + ", ",
    result => result.TrimEnd(',', ' '));

2.2 結合操作

[編集]

データベースの結合操作と同様に、LINQも複数のデータソースを結合する機能を提供します。

var categories = new List<Category>
{
    new Category { Id = 1, Name = "電化製品" },
    new Category { Id = 2, Name = "周辺機器" }
};

// 内部結合
var productDetails = from p in products
                    join c in categories
                    on p.Category equals c.Name
                    select new
                    {
                        ProductName = p.Name,
                        Category = c.Name,
                        Price = p.Price
                    };

// グループ結合
var categoryProducts = from c in categories
                      join p in products
                      on c.Name equals p.Category into productGroup
                      select new
                      {
                          CategoryName = c.Name,
                          Products = productGroup
                      };

第5章 デバッグとテスト

[編集]

5.1 デバッグ技法

[編集]

クエリの可視化

[編集]

パフォーマンス測定

[編集]

一般的な問題のトラブルシューティング

[編集]

5.2 単体テスト

[編集]

LINQクエリのテスト方法

[編集]

モックの使用

[編集]

テストパターン

[編集]

附録

[編集]

A. LINQメソッドリファレンス

[編集]

B. パフォーマンスチューニングガイド

[編集]

C. ベストプラクティス集

[編集]

D. サンプルコード集

[編集]