統合言語クエリ
第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 };