Deep Insider の Tutor コーナー
>>  Deep Insider は本サイトからスピンオフした姉妹サイトです。よろしく! 
書籍転載:ASP.NET MVC 5 実践プログラミング

書籍転載:ASP.NET MVC 5 実践プログラミング

LINQ:データをグループ化する - group句[C#]

2014年12月9日

特定のキー列でデータをグループ化するためのgroup句/GroupByメソッドについて解説する。書籍転載の25本目(基礎編「5-3-8」)。

  • このエントリーをはてなブックマークに追加

書籍転載について

 本コーナーは、秀和システム発行の書籍『ASP.NET MVC 5 実践プログラミング』の中から、特にBuild Insiderの読者に有用だと考えられる項目を編集部が選び、同社の許可を得て転載したものです。

 

 『ASP.NET MVC 5 実践プログラミング』の詳細や購入は秀和システムのサイト目次ページをご覧ください。

ご注意

 本記事は、書籍の内容を改変することなく、そのまま転載したものです。このため用字用語の統一ルールなどはBuild Insiderのそれとは一致しません。あらかじめご了承ください。

5-3-8 データをグループ化する - group句

 特定のキー列でデータをグループ化するには、group句/GroupByメソッドを利用します。たとえば以下は、Articlesテーブルの内容をCategory列でグループ化し、それぞれに属する記事を列挙する例です(メソッド構文での記法も併記します)。

C#
public ActionResult Group()
{
  // 記事情報をカテゴリー単位にグループ化
  var articles = from a in db.Articles
                 group a by a.Category;

  // メソッド構文
  // var articles = db.Articles.GroupBy(a => a.Category);

  return View(articles);
}
リスト5-48 Controllers/LinqController.cs
Razor
 1
 2
 3
1
 5
 6
 7
2
 9
10
11
12
@model IEnumerable<IGrouping<MvcModel.Models.CategoryEnum,MvcModel.Models.Article>>
... 中略 ...
<!-- グループを列挙 -->
@foreach (var group in Model) {
  <dt>@group.Key</dt>
  <dd>
  <!-- グループに属するオブジェクトを列挙 -->
  @foreach (var article in group) { 
    <p><a href="@article.Url">@article.Title</a></p>
  }
  </dd>
}
リスト5-49 Views/Linq/Group.cshtml
図5-19 カテゴリー単位に記事を列挙

図5-19 カテゴリー単位に記事を列挙

 group句による戻り値は、IEnumerable<IGrouping<K, S>>型です*35。よって、1では順番にグループを取得し、そのKeyプロパティでキー(ここではカテゴリー値)を取得します。グループ配下の要素(エンティティ)にアクセスするには、2のように取得したグループを更にループ処理します。

  • *35 Kはキー、Sはエンティティの型です。

 以下のようにすることで、Url/Title プロパティのみを含んだオブジェクトを返すこともできます。

C#
public ActionResult Group2()
{
  var articles = 
    from a in db.Articles
    group new ArticleLinkView { Url = a.Url, Title = a.Title }
    by a.Category;

  // メソッド構文
  //var articles = db.Articles.GroupBy(a => a.Category,
  //  a => new ArticleLinkView { Url = a.Url, Title = a.Title });

  return View(articles);
}
リスト5-50 Controllers/LinqController.cs *36
  • *36 対応するビューモデルArticleLinkView、ビュースクリプトGroup2.cshtmlは、配布サンプルを参照してください。
複数列でグループ化する

 複数列(複合キー)でグルーピングするならば、以下のようにグループ化キーをオブジェクトとして指定します。サンプルは、Category/Published列でグループ化した例です。

C#
public ActionResult MultiGroup()
{
  var articles = 
    from a in db.Articles
    group a by new ArticleGroup
    {
      Category = a.Category, Published = a.Published
    };

  // メソッド構文
  //var articles = db.Articles.
  //  GroupBy(a => new ArticleGroup
  //  {
  //    Category = a.Category, Published = a.Published
  //  });

  return View(articles);
}
リスト5-51 Controllers/LinqController.cs *37
図5-20 カテゴリー/公開日単位に記事を列挙
  • *37 対応するビューモデルArticleGroup、ビュースクリプトMultiGroup.cshtmlは、配布サンプルを参照してくださ い。

 その他、(たとえば)太字の部分をa.Published.Yearのようにすることで、公開「年」でグループ化したり、a.Title[0]でタイトルの先頭文字でグループ化したりすることもできます。はたまた、a.Viewcount == 0 ? 0 : a.Viewcount / 10000のような式を利用することで、0~10000、10001~20000...の単位でグループ化することも可能です。

グループ化した結果でフィルターする

 intoキーワードを利用することで、グルーピングされた結果に対して、追加でフィルターすることも可能です。いわゆるSQL-SELECT命令のHAVING句に相当するコードです。

C#
public ActionResult Having()
{
  var articles = 
    from a in db.Articles
    group a by a.Category into cgroup
    where cgroup.Average(a => a.Viewcount) > 10000
    select new ArticleHaving
    {
      Category = cgroup.Key,
      ViewAverage = cgroup.Average(a => a.Viewcount)
    };

  // メソッド構文
  //var articles = db.Articles.GroupBy(a => a.Category)
  //  .Where(group => group.Average(a => a.Viewcount) > 10000)
  //  .Select(group => new ArticleHaving
  //  {
  //     Category = group.Key,
  //     ViewAverage = group.Average(a => a.Viewcount)
  //  });

  return View(articles);
}
リスト5-52 Controllers/LinqController.cs *38
図5-21 ページビューの平均値が10000より大きいグループだけを表示

図5-21 ページビューの平均値が10000より大きいグループだけを表示
  • *38 対応するビューモデルArticleHaving、ビュースクリプトHaving.cshtmlは、配布サンプルを参照してください。

 intoキーワードでグループ化の結果を一時的に格納しておき、その結果でもってwhere/select句を呼び出しているわけです。メソッド構文では、以降のWhere/Selectメソッドには無条件にグループ化の結果が渡されますので、それと意識することなく絞り込みの式を表現できます。

 Averageメソッドは集計メソッドで、その他にも以下のようなものを利用できます。

メソッド概要
Average 平均値
Count 件数
LongCount 件数(Int64型)
Max 最大値
Min 最小値
Sum 合計値
表5-9 主な集計メソッド

 同じ要領で、グループキーでソートすることもできます。

C#
public ActionResult Having2()
{
  var articles = from a in db.Articles
                 group a by a.Category into cgroup
                 orderby cgroup.Key.ToString()
                 select cgroup;

  // メソッド構文
  //var articles = db.Articles
  //  .GroupBy(a => a.Category)
  //  .OrderBy(group => group.Key.ToString());

  return View(articles);
}
リスト5-53 Controllers/LinqController.cs *39
図5-22 グループ化キー(カテゴリー)でソート

図5-22 グループ化キー(カテゴリー)でソート
  • *39 対応するビュースクリプトHaving2.cshtmlは、配布サンプルを参照してください。

※以下では、本稿の前後を合わせて5回分(第23回~第27回)のみ表示しています。
 連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。

書籍転載:ASP.NET MVC 5 実践プログラミング
23. LINQ:特定範囲のデータだけを取得する - Skip/Takeメソッド[C#]

指定された件数だけデータを読み飛ばすためのSkipメソッドと、指定された件数のデータだけを取得するためのTakeメソッドについて解説。書籍転載の23本目(基礎編「5-3-6」)。

書籍転載:ASP.NET MVC 5 実践プログラミング
24. LINQ:先頭のデータを取得する - Firstメソッド[C#]

クエリ後の結果セットから先頭のデータを取得するためのFirstメソッドについて解説する。書籍転載の24本目(基礎編「5-3-7」)。

書籍転載:ASP.NET MVC 5 実践プログラミング
25. 【現在、表示中】≫ LINQ:データをグループ化する - group句[C#]

特定のキー列でデータをグループ化するためのgroup句/GroupByメソッドについて解説する。書籍転載の25本目(基礎編「5-3-8」)。

書籍転載:ASP.NET MVC 5 実践プログラミング
26. LINQ:エンティティ同士を結合する - join句[C#]

特定のキー列でエンティティ同士を結合し、複数のエンティティをまとめて取得するためのjoin句/Joinメソッドについて解説する。書籍転載の26本目(基礎編「5-3-9」)。

書籍転載:ASP.NET MVC 5 実践プログラミング
27. 開発者に人気のCSSフレームワーク「Bootstrap」入門

「レスポンシブデザインに対応したグリッドシステム」などの特長で、特に開発者に人気のCSSフレームワーク「Bootstrap」について解説する。書籍転載の27本目(応用編「8-2-5」)。転載は今回で終了。

サイトからのお知らせ

Twitterでつぶやこう!