ADO.NET Data Servicesを利用したWebサイトの作成
Data Servicesをホストするプロジェクトを作成し、動作も確認しました。続いてData Servicesを利用するクライアントプロジェクトを作成します。
プロジェクトの作成
ホストプロジェクトにクライアントプロジェクトを追加します。メニューの[ファイル]-[追加]-[新しいプロジェクト]と選択し、Webプロジェクトを作成します(サンプルではSampleAstoriaClientと名前設定)。
展開されたDefault.aspxページ上に、以下の要領でコントロールを追加してください(図9)。
コントロール | 個数 | プロパティ設定 |
GridView | 1個 | 特になし |
Button | 3個 | それぞれテキストに「挿入」「更新」「削除」と設定 |
ボタンコントロールはそれぞれクリックイベントを追加します。以上でフォームの設定は完了です。また、ポートの設定はホストプロジェクト同様の手順で''51000''と設定しておきましょう(分かりやすくするためであってそれ以上の意味はありません)。
.NETのクラスからADO.NET Data Servicesにアクセスする
フォームの準備もできたので、最初は.NETアプリケーションからData Servicesにアクセスする方法について解説します。
.NETクライアント クラスの作成
さて、下準備が済んだ所でホストプロジェクトのData Servicesにアクセスするための中間クラスを作成します。本来はData Servicesクラスをクライアントで利用するためのSystem.Data.Services.Clientクラスを利用して、手書きでData Servicesから返されるデータをクライアント上で、オブジェクトとして操作するためのクラスを作成します。
この作業はかなり煩雑です。しかし、VS2008 SP1のSDKツール''DataSvcUtil.exeツール''を利用すると、[Visual Studio 2008 コマンド プロンプト]上でコマンドを記述するだけで、EDMのデザイナクラス(サンプルで言うと、Pubs.Designer.cs)とほぼ同一の内容が記述されたパーシャルクラスを含んだクラスを自動生成します。EDMのデザイナクラスとの違いはパーシャルクラスである点と、利用するコンテキストが直接EDMを操作するコンテキストか、クライアントから操作するコンテキストかの違いです。尚、自動生成されるクラスはAtomPub形式を使用しています。
それでは、作成する手順を解説します。
Visual Studio 2008 コマンドプロンプトを管理者実行して以下のコマンドを実行します。
> cd C:\Windows\Microsoft.NET\Framework\v3.5 > DataSvcUtil.exe /out:c:\PubsTitles.cs /uri:http://localhost:50000/PubsAstoria.svc
今回利用したパラメータは以下の通りです。なお、既定で生成される言語はC#となっています。VBで生成したい場合は、ファイル名.vbの他に、/language:VBの設定が必要になります。
パラメータ | 概要 |
/out:<ファイル名> | クラスの出力先(クラス名の設定含む) |
/uri:<URI> | Data ServicesのURI |
/language:VB | VBでクラスを生成 |
生成されたクラスは対象となるData ServicesのEDM次第ですが、サンプルでは以下のようなクラスが生成されます。長くなるので一部抜粋させて頂きます。
// pubsModel名前空間の作成 namespace pubsModel { /// <summary> /// スキーマの pubsEntities にはコメントがありません。 /// </summary> // pubsEntitiesパーシャルクラスにグローバル名前空間を利用して設定 public partial class pubsEntities : global::System.Data.Services.Client.DataServiceContext { /// <summary> /// 新しい pubsEntities オブジェクトを初期化します。 /// </summary> // pubsEntitiesオブジェクトのパラメータにグローバル名前空間を利用して設定 public pubsEntities(global::System.Uri serviceRoot) : base(serviceRoot) { this.OnContextCreated(); } partial void OnContextCreated(); /// <summary> /// スキーマの publishers にはコメントがありません。 /// </summary> // グローバル名前空間を利用してDataServiceQuery<publishers>を設定 public global::System.Data.Services.Client.DataServiceQuery<publishers> publishers { get { if ((this._publishers == null)) { // DataServicesからpublishersエンティティオブジェクトの取得 this._publishers = base.CreateQuery<publishers>("publishers"); } return this._publishers; } } // 以下、残りのtitlesエンティティの各項目の記述のため中略 } }
''global::''は、グローバル名前空間(最優先される名前空間)を参照し、現在のエイリアスを参照しません。つまり、上記の例で言うと、pubsEntitiesパーシャルクラスはパラメータに''System.Uri serviceRoot''を適用しています。
DataServiceContextクラスは、Data Servicesの実行時のコンテキストを表すクラスで、機能的には持ち得ないData Servicesの状態(ステート)を保持するための機能を持つクラスです。今回は項目の追加という状態を保持しています。
DataServiceQueryクラスは、Data Servicesへの特定のHTTPクエリを表す抽象クラスです。このクラスのオブジェクト インスタンスは、DataServiceContextクラスのCreateQuery(T) メソッドを使用して作成します。CreateQuery(T) メソッドは指定されたデータについてのData Servicesのクエリを作成します。
簡単にまとめると、Data Servicesが利用しているEDMの名前空間を利用し、Data Servicesは経由するものの各エンティティへのアクセスが可能なオブジェクトをDataServiceContextクラスとDataServiceQueryクラスを利用して作成し、クライアント側に提供するクラスです。
LINQ to ADO.NET Data Servicesを使ってADO.NET Data Servicesにクエリを行う
DataSvcUtil.exeツールを使って生成されたクラス(以下、クライアント ライブラリ)はLINQを使ってData Servicesにクエリを行うこともできます。.NETアプリケーションからアクセスする場合は、クライアント ライブラリを使いLINQ to ADO.NET Data Servicesを利用することが多くなるでしょう。クラスは、URIにLINQのステートメントをマッピングして処理を行います。
最初は、ページロード時にGridViewコントロールにtitlesテーブルのデータを全て表示させてみましょう。最初に参照設定に[System.Data.Services.Client]名前空間を追加します。続いてWhereステートメントなどを利用していないので非常にシンプルなコードとなります。実行結果は図10になります。
// 既定の名前空間のほか以下の2つの名前空間を追加 using System.Data.Services.Client; using pubsModel; protected void Page_Load(object sender, EventArgs e) { // pubsEntitiesオブジェクトにData Servicesのアドレスを設定して生成 pubsEntities edm = new pubsEntities(new Uri("http://localhost:50000/PubsAstoria.svc")); // titlesテーブルをすべて選択 var pubas = from p in edm.titles select p; // GridView1にデータをバインディング GridView1.DataSource = pubas; GridView1.DataBind(); }
pubsModel名前空間はクライアント ライブラリを参照するために指定しています。クライアント ライブラリでは、ホストプロジェクトのEDMで定義されたPubsエンティティ型のオブジェクトであるpubsEntitiesオブジェクトにサービスがホストされているURIを初期値として設定して生成します。これにより、LINQ to ADO.NET Data Sevicesを実行するためのオブジェクトの準備ができます。その後、titlesテーブルのデータを全て抽出するLINQを行い、その結果をGridView1にバインディングして表示しています。
続いて、配置した3つのボタンにそれぞれ挿入/更新/追加の処理を記述します。それぞれのクリックイベントに以下のコードを追加してください。
// 既定の名前空間のほか以下の2つの名前空間を追加 using System.Data.Services.Client; using pubsModel; protected void Button1_Click(object sender, EventArgs e) { // 挿入 // Data Service実行時コンテキストをData Servicesのアドレスを設定して生成 DataServiceContext edm = new DataServiceContext(new Uri("http://localhost:50000/PubsAstoria.svc")); // Data Servicesのtitlesエンティティのインスタンス生成 titles titlesEntity = new titles(); DateTime dt = DateTime.Parse("2008/11/17"); // titlesエンティティ・オブジェクトにnullを許容しない列に値を設定 titlesEntity.pubdate = dt; titlesEntity.title = "Tamaki's Diary"; titlesEntity.title_id = "N1107"; titlesEntity.type = "Family"; // 新しいオブジェクトとして // titlesエンティティに追加 edm.AddObject("titles", titlesEntity); // 更新を反映 edm.SaveChanges(); } protected void Button2_Click(object sender, EventArgs e) { // 更新 // pubsEntitiesオブジェクトにData Servicesのアドレスを設定して生成 pubsEntities edm = new pubsEntities(new Uri("http://localhost:50000/PubsAstoria.svc")); // Data Servicesのtitlesエンティティのインスタンス生成 titles titlesEntity = new titles(); // titlesエンティティに対して主キーによる絞り込みを行い、1レコード返す titlesEntity = (from p in edm.titles where p.title_id == "N1107" select p).First(); // 該当するエンティティの値を更新 titlesEntity.title = "Tamaki's Photo Diary"; edm.UpdateObject(titlesEntity); // 更新を反映 edm.SaveChanges(); } protected void Button3_Click(object sender, EventArgs e) { // 削除 // pubsEntitiesオブジェクトにData Servicesのアドレスを設定して生成 pubsEntities edm = new pubsEntities(new Uri("http://localhost:50000/PubsAstoria.svc")); // Data Servicesのtitlesエンティティのインスタンス生成 titles titlesEntity = new titles(); // titlesエンティティに対して主キーによる絞り込みを行い、1レコード返す titlesEntity = (from p in edm.titles where p.title_id == "N1107" select p).First(); // 該当するエンティティを削除 edm.DeleteObject(titlesEntity); // 更新を反映 edm.SaveChanges(); }
追加を行う時には、titlesエンティティを用意して、必要な項目の設定を行いAddObjectメソッドでtitlesEntityオブジェクトに追加するだけです。追加された要素をSaveChangesメソッドでEDMからデータテーブルに追加の情報を反映させています。注目すべき点は、追加する対象として、Data Servicesのアドレスを設定したDataServiceContextオブジェクトを生成している点です。今回は項目の追加という状態を保持しています。
更新時には、LINQ to ADO.NET Data Servicesを使い、主キーによるtitlesQuery Builderメソッドの1つであるWhereメソッドを使い、更新対象となるtitlesEntityのレコードを取得します。更新を行いたいレコードの項目のプロパティを設定した後、SaveChangesメソッドで情報を反映させます。更新を行う対象として、Data Servicesのアドレスを設定したpubsEntitiesオブジェクトを生成しています。
削除も更新と同じ要領で行います。更新との違いは抽出したレコードをDeleteObjectメソッドで削除しているという点だけです。
LINQ to ADO.NET Data Servicesを使ってADO.NET Data Servicesにクエリを行う方法については以上です。途中にクライアント ライブラリを利用しているからではありますが、シームレスな連携を確認できたかと思います。