ScottGu's blog translated by Chica @ Wankuma

LINQ to SQL (パート 2 - データモデルクラスの定義)

  

パート 1 では、"LINQ to SQLとは何か"について論議し、いくつかの可能なデータシナリオに関する基本的な概略を紹介しました。

投稿の最初で、以下にあるようなLINQ to SQLを使用している共通のデータシナリオの実行方法を表したコードサンプルを提供しました。

  • データベースの検索方法
  • データベースの行の更新方法
  • データベースへの複数行の挿入方法と関連付けの方法
  • データベースの行の削除方法
  • ストアドプロシジャーの呼びだし方法
  • サーバーサイドページングでのデータの取得方法

以下のようなLINQ to SQLクラスモデルを使用したそれらのデータシナリオを全て実行しました。

この2回目のブログでは、上記のLINQ to SQLデータモデルの作成方法についてより詳細に入り込んでいこうと思います。

LINQ to SQL、LINQ to SQLデザイナ、またこのブログでカバーしている全ての機能は .NET 3.5 および Visual Studio "Orcas"リリースの1部として出荷されることになっています。

Visual Studio "Orcas" ベータ 1 または Visual Web Developer Express "Orcas" ベータ1のいずれかをダウンロードして頂ければ、以下のステップを全てお試しいただくことができます。両方ともインストールしてVS2005とサイドバイサイドで使用することができます。

新しいLINQ to SQL データモデルの作成

Visual Studioの"新しい項目を追加"オプションから"LINQ to SQL"項目を選択して、LINQ to SQLデータモデルをASP.NET、クラスライブラリ、Windowsクライアントプロジェクトに追加することができます。

"LINQ to SQL"項目を選択すると、LINQ to SQLデザイナが立ち上がるので、リレーショナルデータベースを表すクラスをモデル化することができるようになります。また、強く型付けられた"DataContext"クラスも作成されます。作成されたクラスはデータベース内でモデル化を行った各テーブルを表すプロパティと、モデル化を行った各ストアドプロシジャーに対するのメソッドを持っています。パート1 で述べましたが、DataContextクラスはデータベースからエンティティを検索する際またそこへ変更を適用する際のメインのコンジットです。

以下は空のLINQ to SQLのORMデザイナ サーフェイスのスクリーンショットで、新しいLINQ to SQLデータモデルを作成する時に現れる画面です。

 

エンティティクラス

LINQ to SQLにより、データベースとのマッピング(双方向)を行うクラスをモデル化することが可能です。これらのクラスは通常"エンティティクラス"として参照され、そのインスタンスは"エンティティ"と呼ばれます。エンティティクラスはデータベース内のテーブルにマップされ、エンティティクラスのプロパティは通常テーブルのカラムにマップされます。そしてエンティティクラスの各インスタンスは、データベースのテーブルの行を表します。

LINQ to SQLと一緒に定義されたエンティティクラスは特別のベースクラスから派生する必要がないので、全てのオブジェクトから継承させることができます。LINQ to SQLデザイナを使用して作成された全てのクラスは"partialクラス"として定義されます。-つまり、コードの中に追加のプロパティ、メソッド、イベントなどを落とし込むことができます。

VS 2005で提供されているDataSet/TableAdapterの機能とは違って、LINQ to SQLデザイナを使用する場合は、データモデルの作成に使用するSQLクエリを特定してレイヤへアクセスする必要はありません。

それよりも、データベースとのマッピング(双方向)およびそれらの関連付け方法をエンティティクラスで定義することに集中します。それによりLINQ to SQL OR/M の実装がランタイムでデータのエンティティを取り扱う時に適切なSQL実行のロジックを作成してくれます。強く型付けされた方法でどのようにデータモデルのクエリを行うかを表現するためにLINQクエリシンタックスを使うことができます。

データベースからエンティティクラスを作成

すでにデータベーススキーマの定義があった場合、そこから簡単にLINQ to SQLエンティティクラスを作成することができます。

一番簡単な方法は、Visual Studioのサーバーエクスプローラでデータベースを開いて、モデル化したいテーブルとビューを選択し、LINQ to SQLデザイナ サーフェイスにドラッグアンドドロップしてください。

 

上記の2つのテーブル(Categories およびProducts)と1つビュー(Invoices)を"Northwind"データベースからLINQ to SQLデザイナインターフェイスへ追加した場合、自動的にデータベーススキーマに基づいて以下の3つのエンティティクラスが作成されます。

 

上記で定義したデータモデルクラスを使えば、このLINQ to SQLシリーズの パート 1 で述べたコードサンプル(ストアドプロシジャーを除く)を全て起動させることができます。これらの検索、挿入、更新、削除、サーバーサイドページングシナリオを行うために、他にコードおよび構成を追加する必要はありません。

名前付けと複数化

LINQ to SQLデザイナを使用した時に気づくことの1つですが、自動的にデータベーススキーマに基づいてエンティティクラスを作成する際に様々なテーブルやカラムの名前を"複数化"することがあります。例えば、上記の例で"Products"テーブルは"Product"クラスで、"Categories"テーブルは"Category"クラスになっています。このクラスの名前付けにより.NETの名前付け方法とモデルに整合性がとれるようになるので、私自身は通常デザイナが私にとって非常に便利に(特にモデルに多くのテーブルを追加したとき)それらを修正してくれていると思っています。

デザイナが生成するクラスおよびプロパティの名前が気に入らない場合は、オーバーライドして好みの名前に変更して頂くことも可能です。方法として、デザイナでエンティティおよびプロパティの名前をインラインで編集、またプロジェクトグリッドで修正、のどちらでも行うことができます。

 

エンティティ、プロパティ、関連の名前をデータベーススキーマと異なるものできるということは、多くの場面で非常に便利だと思われることになると思います。特に、

1) バックエンドのデータベースのテーブルおよびカラムのスキーマの名前を変更した時。エンティティモデルがバックエンドスキーマと異なる名前を持つことができれば、マッピングルールを更新するだけにしてアプリケーションや新しいテーブルおよびカラム名を使用した検索コードを更新しないことも可能だからです。

2) データベーススキーマの名前がそれほど"きれいな"名前ではない場合。例えば、エンティティクラス上のプロパティ名に対して"au_lname"や"au_fnameなどを使用しないで、エンティティクラス上では "LastName"や"FirstName"のような名前にして(データベースのカラム名を変更することなく)それに対して開発を行うことができます。

リレーションシップ アソシエーション(関係・関連)

LINQ to SQLデザイナ上にサーバーエクスプローラからオブジェクトをドラッグすると、Visual Studioはそのオブジェクトのプライマリーキーおよび外部キーの関係を調べて、それらに基づいて自動的に作成される異なるエンティティクラス間のデフォルトの"リレーションシップ アソシエーション(関係・関連)"を作成します。例えば、LINQ to SQLデザイナ上にNorthwindからProductsとCategoriesの両方を追加した時、2つの間の1対複数の関係が見て取れると思います。(これはデザイナの矢印が表示します。)

上記の関係は、Productエンティティクラスが"Category"プロパティを持っていて、それを開発者は与えられたProduct対するCategory エンティティにアクセスするために使用することができます。またCategoryクラスは"Products"コレクションを持っていて、それにより開発者はそのCategory内の全ての製品を取得することができます。

もしデザイナのモデル化のされ方や関連の名前付けが好みではない場合、オーバーライドすることができます。デザイナの関連矢印をクリックするだけでプロパティにアクセスできるので、そのプロパティグリッドを通じて名前の変更、削除、修正を行うことができます。

遅延ローディング

LINQ to SQLにより、開発者は最初のアクセスでエンティティ上のどのプロパティを最初に取ってくるのか、また遅延ロードするのかを特定することができます。デザイナ上でエンティティのプロパティまたは関連を選択してエイティティプロパティに対してデフォルトのプレフェッチ・遅延ロードをカスタマイズすることができ、プロパティグリッド内で"Delay Loaded"プロパティをtrueまたはfalseに設定することができます。

いつこれをしたいという簡単なサンプルに、上記でモデル化した"Category"エンティティクラスを使ってみてください。"Northwind"内のカテゴリテーブルには"Picture"カラムがあり、各カテゴリには(おそらく大きい)バイナリ画像が入っています。データベースからバイナリ画像を取得するのは、(単にリストにあるカテゴリ名をあげるときではなく)実際それを使用している時だけです。

LINQ to SQLデザイナでPictureプロパティを選択して、プロパティグリッドで遅延ロードの値を設定することで、 Pictureプロパティを遅延ロードに構成することができます。

注:エンティティ上のデフォルトのプレフェッチ・遅延ロードセマンテックを構成することに加え、エンティティクラス上でLINQクエリを実行する時にコードを通じてそれらをオーバーライドすることができます。(このシリーズの次の投稿でこの方法を説明します。)

ストアドプロシジャーの使用

LINQ to SQLで、必要に応じてDataContextクラス上のメソッドとしてストアドプロシジャーをモデル化することができます。例えば、以下の簡単なストアドプロシジャーを categoryIDに基づいて製品情報を取得するために定義したと仮定します。

Visual Studioでサーバーエクスプローラを使って、ストアドプロシジャーを呼ぶ強く型付けされたメソッドを追加するために、ストアドプロシジャーをLINQ to SQLデザイナ上にドラッグアンドドロップすることができます。もしストアドプロシジャーをデザイナ上で"Product"の上にドロップした場合、LINQ to SQLデザイナはIEnumerableの結果を返す為に、そのストアドプロシジャーを宣言します。

そうすればLINQクエリシンタックス(その時々のSQLクエリを生成するもの)を使う、もしくは代わりにデータベースから製品エンティティを取得するために上記で追加したストアドプロシジャーメソッドを呼ぶことのどちらでも行うことができます。

データの更新・削除・挿入にストアドプロシジャーを使用

デフォルトで、LINQ to SQLは、エンティティの挿入・更新・削除の際に自動的に適切なSQL文を作成します。例えば、もし以下のLINQ to SQLコードを書いて、"Product"エンティティインスタンス上の値を更新する場合、

デフォルトでは、LINQ to SQLは変更が行われた際に適切な"UPDATE"文を作成・実行します。(更新についてはまた後日詳細にカバーします。)

また代わりにINSERT、UPDATE、DELETE ストアドプロシジャーをカスタム定義して使うことも可能です。これらを構成するためには、LINQ to SQLデザイナのエンティティクラスをクリックし、そのプロパティグリッド内でDelete/Insert/Updateの値の"..."ボタンをクリックして、代わりに定義したストアドプロシジャーを選択します。

上記の設定を変更する利点は、純粋にLINQ to SQLのマッピングレイヤで行えることです。それは、前に紹介した更新コードが修正を行わずに継続して機能するということです。これで、LINQ to SQLデータモデルを使用している開発者は、もし後になってカスタムのストアドプロシジャー最適化に入れることを決定したとしても、コード変更しなくてはいけない状況は避けることができます。

まとめ

LINQ to SQLはアプリケーションのデータ層を上手できれいにモデル化する方法提供します。 一度データモデルを定義すればそれに対して簡単で効率的に検索、挿入、更新、削除を実行することができます。

Visual StudioやVisual Web Developer ExpressでビルドインのLINQ to SQLデザイナを使用すれば、LINQ to SQLに対するデータモデルを超高速に作成・管理することができます。またLINQ to SQLデザイナには、多くの適応性があるため、必要性に応じてデフォルトのカスタマイズや、システムのオーバーライド・拡張を行うことができます。

次の投稿では上記で作成したデータモデルを使用した検索、挿入、更新、削除を更に詳しく追及していきます。更新、挿入、削除の部分では、追加された検証ロジックを実行するために、上記で設計したエンティティに対して、カスタムのビジネス・データ検証のロジックをどのように追加するかを論議します。

Mike Taulty はLINQ to SQLビデオをたくさん持っていますので、 こちらもよろしければご覧ください。これらは、LINQ to SQLを実際に使って試している人を見ることができるので習得にはとてもいい方法を提供しています。

Hope this helps,

Scott

ScottGu's blog translated by Chica @ Wankuma 

※本翻訳に関しまして、Scottさんにはご了承頂いております。