LINQ練習 #2 「LINQ to SQL 基本」

2009-02-25 19:37:48

どうも、悠希です。
Visual Studio 2008から追加された機能、LINQを使っていく為に色々とメモがてら書いていきます。
今回は「LINQ to SQL」を扱おうかと思います。

本題に入る前に前回の補足です。

コメントをいただいてLINQらしい方法を教示していただきましたのでそのコードを元に最後のコードを修正して書き出しておきます。
当日から1年の間の当年の日曜日を出力します。

C#
int nowYear = DateTime.Today.Year;

var alldays = from i in Enumerable.Range(0, 365) select DateTime.Today.AddDays(i);

var daylist = from d in alldays where d.DayOfWeek == DayOfWeek.Sunday && d.Year == nowYear select d;

foreach (var day in daylist) {

    Console.WriteLine(day.ToShortDateString());

}
Visual Basic
Dim nowYear As Integer = Today.Year

Dim alldays = From i In Enumerable.Range(0, 365) Select Today.AddDays(i)

Dim daylist = From d In alldays Where d.DayOfWeek = DayOfWeek.Sunday And d.Year = nowYear Select d

For Each row As Date In daylist

    Console.WriteLine(row.ToShortDateString)

Next

上記のように、allday変数に対してLINQで0~365の間でループを行い、Date/DateTime型のリストを生成しています。

コメントにあるようにわざわざallday変数に値を入れる事無くdaylist変数を構築する事も可能ですが、LINQ初心者がわかりやすい形に、という事で分割して記述しています。

ちなみに、分割しない形の場合は下記の通りとなります。

C#
int nowYear = DateTime.Today.Year;

var daylist = from d in (

                  from i in Enumerable.Range(0, 365)

                  select DateTime.Today.AddDays(i)

              )

              where d.DayOfWeek == DayOfWeek.Sunday

                 && d.Year == nowYear select d;

foreach (var day in daylist) {

    Console.WriteLine(day.ToShortDateString());

}
Visual Basic
Dim nowYear As Integer = Today.Year

Dim daylist = From d In ( _

                  From i In Enumerable.Range(0, 365) _

                  Select DateTime.Today.AddDays(i) _

              ) _

              Where d.DayOfWeek = DayOfWeek.Sunday _

              And d.Year = nowYear Select d

For Each row As Date In daylist

    Console.WriteLine(row.ToShortDateString)

Next

さて、ここからが本題です。

Visual Studio 2005まではSQL文を.NETから発行する場合には文字列にてSQL文を構築して発行する事が多いかと思われますが、LINQを使うと他のプロダクトに頼ることなく、O/Rマッピングのような方式でデータベースを扱う事が可能となります。

だたし、LINQ to SQLではINSERT/UPDATE/DELETEが貧弱であり、ちょっとした追加・更新・削除以外の場合には使いにくいです。

もちろん、追加・更新・削除の処理も問題なく行えるのですが、大量のデータを扱う場合には方式を考えなければ使い物にならない状態になりうるので注意してください。

とはいえ、参照系のプログラムを作成する場合にはとても使いやすいので目的によって使い分けるなどする事をお勧めします。

まずは準備を行います。

SQL Serverがインストールされている環境の場合はそのまま利用しても良いのですが、今回はSQL Serverがインストールされていない環境という前提で記述を行います。

Visual Studio 2008以降ではMicrosoft SQL Server Compactというローカルデータベース機能が追加されていますので、これを利用してLINQ to SQLを実装します。これはスクリプト言語等で使われることが多いSQLiteのようなデータベースです。

プロジェクトを右クリック→追加→新しい項目を選択し、表示されたウィンドウから「ローカルデータベース」を選択してsdfファイルを追加します。ここではSamples.sdfという名前で追加します。

するとプロジェクトにSamples.sdfというファイルが追加されています。

プロジェクトに追加したSamples.sdfをダブルクリックすると、サーバエクスプローラビューにSamples.sdfに対する接続が作成されますので、「テーブル」の位置で右クリック→テーブルの作成を指定して「テーブルの編集」ウィンドウを表示します。

ここで適当にテーブルレイアウトを作成しておきます。今回は下記のようなテーブルを作成しました。

列名 データ型 サイズ NULL許容 一意 主キー
ISBN nvarchar 13 いいえ はい はい
Name nvarchar 100 いいえ いいえ いいえ

作成されたテーブルレイアウトを右クリック→テーブルデータの表示でデータ編集画面が表示されるので、下記のようにデータを追加しました。

ISBN Name
4891006048 LINQテクノロジ入門~Microsoft Visual Studio 2008による新たなクエリ構築技法~
4877832009 すぐに使える実例で学ぶLINQ実践サンプル集―ASP.NET3.5対応

テーブルが作成できたら次にLINQ to SQL用のエンティティファイルを作成するのですが、ちょっと注意点があります。

SQL Server(Express等)を対象としてLINQ to SQLを行う場合にはエンティティファイルの作成がGUIの操作のみで可能なのですが、SQL Server Compactを使う場合にはテーブル定義の追加の場合に「選択されたオブジェクトにはサポート外のデータプロバイダが使用されています。」と表示されてしまうのでコマンドラインからエンティティファイルを作成する必要があります。(明確にいえばエンティティファイルを定義する為のXMLファイルです。)

sqlmetal.exeの位置は環境によって変わりますので適宜修正してください。
もし、sqlmetal.exeが見つからない場合にはWindows SDKが必要となるのでダウンロード/インストールしておきます。

コマンドライン
CD Samples.sdfのあるディレクトリ

"C:\program Files\Microsoft SDKs\Windows\v6.0A\bin\sqlmetal.exe" /dbml:SamplesContext.dbml /context:SampleContext Samples.sdf

上記コマンドを実行する事によってSamplesContext.dbmlが作成されるので、プロジェクトに追加しておきます。

これで準備が完了しましたので、実際にコードを書いていきます。

C#
using (SampleContext context = new SampleContext("Samples.sdf"))

{

    context.Log = Console.Out;

    var s1 = from d in context.Books

             where d.ISBN == "4891006048"

             select d;

    foreach (var row in s1)

    {

        Console.WriteLine("ISBN:{0}/Name:{1}", row.ISBN, row.Name);

    }

}
Visual Basic
Using context As SamplesContext = New SamplesContext("Samples.sdf")

    context.Log = Console.Out

    Dim s1 = From d In context.Books _

             Where d.ISBN = "4891006048" _

             Select d

    For Each row In s1

        Console.WriteLine("ISBN:{0}/Name:{1}", row.ISBN, row.Name)

    Next

End Using

Using句に関してはMSDNのリファレンスを参照してください。

まず、dbmlファイルにて定義したコンテキストクラスを生成しています。(1行目)。SamplesContextクラスをインスタンス化してcontext変数に設定しています。

SamplesContextのコンストラクタに渡している「Samples.sdf」という文字列は接続先のデータベースファイルを指定しており、SQL Server(Exress等)を利用している場合にはコネクションストリングを指定するか、dbmlファイルに設定されているコネクションストリングを使う(引数を指定しない)ようにしますが、SQL Server Compactではデータベースファイル名を指定する必要があります。

2行目の「context.Log = Console.Out」はコンソールに対して発行されたSQL文を表示する為に指定しています。LINQがどのようなSQL文を構築しているかがわかりやすくなりますので、ここでは設定しています。

3行目からがLINQでSQL式を構築し、データを表示している部分となります。

LINQ to Objectで記述した内容とほとんど同じ方法で書けている事がわかります。違いとしては抽出対象が「context.Books」になっているぐらいです。

これはcontextで接続されているデータベースからBooksテーブルのデータを抽出する事を指しており、SQL文で上記のLINQの内容を書くと下記のようになります。

SQL
SELECT

    d.ISBN

    , d.Name

FROM

    Books AS d

WHERE

    d.ISBN = '4891006048'

記述する順序が異なりますが、SQL文とLINQとの記述の違いはそんなに大きくないですね。しかしながら、文字列でSQL文を記述するのと異なり、インテリセンスが効いて書きやすくなっているかと思います。

また、型も判別してくれるので誤った値を入れる可能性が少なくなるのもいいですね。

上記は基本中の基本の内容で、もっと複雑なSQLを発行したりする事もLINQ to SQLは可能です。

次回以降では複数回に分けて徐々に複雑なLINQ to SQLを書いていこうと思っています。

次回の予定はLINQの式構築時のメソッド使用についてです。

※このエントリは ブロガーにより投稿されたものです。朝日インタラクティブ および ZDNet Japan編集部の見解・意向を示すものではありません。
  • 新着記事
  • 特集
  • ブログ