LINQ to SQLで抽出と並び替え
※この投稿はMicrosoft Visual Studio 2008 Beta2で動作を確認しています。
LINQ to SQLではSQL Server上のデータベースに含まれるデータをプログラムから操作することができます。
まずは以下のような内容でPeopleテーブルを作成しました。
次にプロジェクトに新しい項目の追加からLINQ to SQLクラスを追加します。
新たに表示されるページ(LINQTEST.dbml)の左ペインにサーバエクスプローラからPeopleテーブルをドラッグ アンドドロップすると、Peopleクラスが自動的に生成されます。
このページを保存して、自動的に生成されたクラスを確定したうえで、メインのプログラムを記述します。
using System;
using System.Linq;
namespace LINQ4
{
class Program
{
static void Main(string[] args)
{
LINQTESTDataContext dtc = new LINQTESTDataContext();
dtc.Log = Console.Out;
var query = from p in dtc.People
where p.Gender == 1 && p.Age >= 20
orderby p.Age
select p;
foreach (var item in query)
{
Console.WriteLine("名前={0}, 年齢={1}", item.Name, item.Age);
}
Console.Read();
}
}
}
LINQ to SQLで重要になるのは、テーブルをドラッグ アンド ドロップすることで自動的に生成されるDataContextです。
ドラッグ アンド ドロップによりどのようなプログラムコードが自動生成されているかは、LINQ to SQL クラス名.designer.cs ファイルを見ることで確認できます。
このDataContext(上記ではLINQTESTDataContext)に含まれるテーブル(dtc.People)に対してLINQを記述していきます。
LINQ自体の記述はObjectやXMLを対象とした場合とほとんど大差はありません。
拡張メソッドを利用した記述も同じように利用できます。DataContextに含まれるテーブルが操作の対象となる点にだけ気をつけていれば十分です。
var query = dtc.People.Where(p => p.Gender == 1 && p.Age >= 20).OrderBy(p => p.Age);
実行結果は以下のようになります。
この実行結果にSQL文が含まれるのはプログラム中でDataContextのLogプロパティに標準出力(Console.Out)を設定しているためです。
LINQ to SQLのプログラムがパラメータを利用したSQLクエリに変換され、実行されていることがわかります。
このSQLクエリがどのタイミングで実行されるのか、ブレークポイントを指定してデバックを実行して確認してみましょう。
上記のように、LINQの記述の後のforeachにブレークポイントを設定した場合、この時点ではコンソール上にSQL文は表示されません。
F11キーを押して1ステップずつ確認していくと、2ステップ目の以下のタイミングでSQL文がコンソール上に表示されます。
このことにより、LINQの記述でquery変数に直接データが設定されるのではなく、query変数の内容にアクセスしようとしたタイミング(foreach内部)でSQL文が生成/発行され、データが取り出されることが確認できます。
LINQ to XMLで抽出と並び替え
※この投稿はMicrosoft Visual Studio 2008 Beta2で動作を確認しています。
LINQ to XMLということで、LINQはXML形式のデータを扱うこともできます。
たとえば次のようなプログラムで。
using System;
using System.Linq;
using System.Xml.Linq;
namespace LINQ3
{
class Program
{
static void Main(string[] args)
{
XElement People = XElement.Parse(
@"<People>
<Person>
<Name>オサダ トシヒロ</Name>
<Gender>1</Gender>
<Age>32</Age>
</Person>
<Person>
<Name>カネフジ タカエ</Name>
<Gender>2</Gender>
<Age>46</Age>
</Person>
<Person>
<Name>キョウゴク トシツグ</Name>
<Gender>1</Gender>
<Age>11</Age>
</Person>
<Person>
<Name>コウダ キミタカ</Name>
<Gender>1</Gender>
<Age>17</Age>
</Person>
<Person>
<Name>シモイズミ エイコ</Name>
<Gender>2</Gender>
<Age>13</Age>
</Person>
<Person>
<Name>センザイ シュウイチロウ</Name>
<Gender>1</Gender>
<Age>43</Age>
</Person>
<Person>
<Name>ソウリョウ ノリカズ</Name>
<Gender>1</Gender>
<Age>21</Age>
</Person>
<Person>
<Name>マツバネ タツコ</Name>
<Gender>2</Gender>
<Age>24</Age>
</Person>
<Person>
<Name>ミツジマ タカコ</Name>
<Gender>2</Gender>
<Age>32</Age>
</Person>
<Person>
<Name>ヤハタ トシチカ</Name>
<Gender>1</Gender>
<Age>28</Age>
</Person>
</People>");
var query = from p in People.Descendants("Person")
where int.Parse(p.Element("Gender").Value) == 1 && int.Parse(p.Element("Age").Value) >= 20
orderby int.Parse(p.Element("Age").Value)
select p;
foreach (var item in query)
{
Console.WriteLine("名前={0}, 年齢={1}", item.Element("Name").Value, item.Element("Age").Value);
}
Console.Read();
}
}
}
LINQでXMLを扱うためにはいくつか注意しないといけないところがあります。
- "using System.Xml.Linq; "という記述を追加しておきましょう。
- XMLデータはXElementクラスに格納します。
- LINQの対象となるのは、XElementからDescendantsメソッドで取り出したデータです。
- 各Elementの値(Value)は文字列なので、適切な型にキャストしましょう。
LINQプログラムの基本的な部分はObjectを対象としたときとXMLを対象としたときで変化はありません。
当然、次のように拡張メソッド形式での記述も利用できます。
var query = People.Descendants("Person")
.Where(p => int.Parse(p.Element("Gender").Value) == 1 && int.Parse(p.Element("Age").Value) >= 20)
.OrderBy(p => int.Parse(p.Element("Age").Value));
実行結果もまったく同じです。
#実行結果が同じになるようにプログラム組んでるんだから当然ですけどね。
LINQ to Objectで抽出と並び替え(配列編)
※この投稿はMicrosoft Visual Studio 2008 Beta2で動作を確認しています。
LINQ to ObjectはListだけを対象にしているわけではありません。
配列もその対象となります。 ということで、ソースコード。
using System;
using System.Linq;
namespace LINQ2
{
class Program
{
static void Main(string[] args)
{
var People = new[]{
new { Name="オサダ トシヒロ", Gender=1, Age=32},
new { Name="カネフジ タカエ", Gender=2, Age=46},
new { Name="キョウゴク トシツグ", Gender=1, Age=11},
new { Name="コウダ キミタカ", Gender=1, Age=17},
new { Name="シモイズミ エイコ", Gender=2, Age=13},
new { Name="センザイ シュウイチロウ", Gender=1, Age=43},
new { Name="ソウリョウ ノリカズ", Gender=1, Age=21},
new { Name="マツバネ タツコ", Gender=2, Age=24},
new { Name="ミツジマ タカコ", Gender=2, Age=32},
new { Name="ヤハタ トシチカ", Gender=1, Age=28}
};
var query = from p in People
where p.Gender == 1 && p.Age >= 20
orderby p.Age
select p;
foreach (var item in query)
{
Console.WriteLine("名前={0}, 年齢={1}", item.Name, item.Age);
}
Console.Read();
}
}
}
なんかデータ作ってるところがすっきりして見えるのは、気のせいではなく、匿名クラスを使っているからです。
まぁ、サンプルだから使える手法ですかね。
LINQの部分はデータがListのときとまったく同じです。
当然、拡張メソッドによる実装も同じく使えます。
var query = People.Where(p => p.Gender == 1 && p.Age >= 20).OrderBy(p => p.Age);
実行結果も同じになります。
LINQ to Objectで抽出と並び替え(List<T>編)
※この投稿はMicrosoft Visual Studio 2008 Beta2で動作を確認しています。
やっと最近LINQに触り始めて、今一番楽しいところなんで、自分がやってみたことをまとめていきたいと思います。
まぁ、まだまだこんなことができるんだぁ、と文法を追っているレベルなんで、たいしたことは書けないですが。
ということで、まずはListに格納されているオブジェクトを操作してみます。
何はともあれソースから。
using System;
using System.Collections.Generic;
using System.Linq;
namespace LINQ1
{
class Person
{
public string Name { get; set; }
public int Gender { get; set; }
public int Age { get; set; }
}
class Program
{
static void Main(string[] args)
{
List<Person> People = new List<Person>{
new Person{ Name="オサダ トシヒロ", Gender=1, Age=32},
new Person{ Name="カネフジ タカエ", Gender=2, Age=46},
new Person{ Name="キョウゴク トシツグ", Gender=1, Age=11},
new Person{ Name="コウダ キミタカ", Gender=1, Age=17},
new Person{ Name="シモイズミ エイコ", Gender=2, Age=13},
new Person{ Name="センザイ シュウイチロウ", Gender=1, Age=43},
new Person{ Name="ソウリョウ ノリカズ", Gender=1, Age=21},
new Person{ Name="マツバネ タツコ", Gender=2, Age=24},
new Person{ Name="ミツジマ タカコ", Gender=2, Age=32},
new Person{ Name="ヤハタ トシチカ", Gender=1, Age=28}
};
var query = from p in People
where p.Gender == 1 && p.Age >= 20
orderby p.Age
select p;
foreach (var item in query)
{
Console.WriteLine("名前={0}, 年齢={1}", item.Name, item.Age);
}
Console.Read();
}
}
}
上記のプログラムでListに格納しているのは名前、性別、年齢というデータを持つ
Personクラスのオブジェクトです。
このオブジェクトの集合の中から、成人(Age>=20)の男性(Gender=1)を取得し、
年齢の順に並べてみています。
結果は次のようになります。
このような結果を得るために、LINQが必ずしも必要なわけではありません。
たとえばList内のデータをひとつずつ取り出して条件に合致するデータだけを残し、
そのデータを並び替えるプログラムを書くことはそれほど難しくないはずです。
ただし、LINQを使うと下記のようにSQL文を書いたことがある人ならすぐに理解できる
簡潔な記述でデータの抽出と並び替えを一度に行うことができます。
var query = from p in People
where p.Gender == 1 && p.Age >= 20
orderby p.Age
select p;
ちなみに、上記のプログラムは以下のように書くこともできます。
var query = People.Where(p => p.Gender == 1 && p.Age >= 20).OrderBy(p => p.Age);
このWhere()やOrderBy()は拡張メソッドとして実装されています。
実はこの拡張メソッドによる実装がLINQの基礎であって、SQL文のような記述は、コンパイル時に
拡張メソッドを使った方法に置き換えられて実行される、と考えてよいと思います。