.NET クライアント ライブラリ (ADO.NET Data Services フレームワーク)
ADO.NET Data Services には、.NET Framework と ADO.NET Data Services を使用するアプリケーションのための .NET クライアント ライブラリが含まれています。クライアント ライブラリを使用するアプリケーションは、データ サービスから返された結果を .NET オブジェクトとして操作できます。関連付けの走査は、共通言語ランタイム (CLR) オブジェクトによって管理されます。
.NET クライアント ライブラリは、HTTP および AtomPub 形式を使用します。クライアント ライブラリは、企業ネットワークとインターネット環境で問題なく実行できます。実行するのに必要なのは、直接またはプロキシ経由のいずれかによる、データ サービスへの HTTP レベルの接続だけです。
System.Data.Services.Client
クライアント ライブラリを使用するには、System.Data.Services.Client アセンブリへの参照をプロジェクトに追加します。クライアント ライブラリは、Windows フォーム、Windows Presentation Foundation、Web サイト プロジェクトなどのプロジェクトの種類から使用できます。
クライアント ライブラリの 2 つの主な構造は、DataServiceContext
クラスおよび DataServiceQuery
クラスです。DataServiceContext
は、指定されたデータ サービスを使用してランタイム コンテキストを表します。データ サービスはステートレスですが、コンテキストはステートレスではありません。クライアントでの状態は、変更管理などの機能をサポートするために、対話間で維持されます。
DataServiceQuery
クラスは、ADO.NET Data Services の URI 構文を使用して指定されたストレージに対するクエリを表します。クエリを実行して .NET オブジェクトの形式で結果を取得するには、たとえば、C# の foreach
構造または Visual Basic の For Each
を使用して、クエリ オブジェクトを列挙します。
.NET オブジェクトとしてデータ サービスで定義された各エンティティを表すには、対応するクラスをクライアント アプリケーションに対して定義する必要があります。これを行う方法の 1 つは、手動でクラスを定義することです。別の方法としては、次のセクションで説明する DataSvcUtil.exe ツールを使用します。
次の例は、SQL Server 2005 に付属する AdventureWorks サンプル データベースのデータに基づいた、Address
クラスの手書きの定義を示しています。この例では、Address
エンティティと、サービスに対してクエリを実行する小さなコードを使用します。返された Address
のプロパティが出力として表示されます。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.Services.Client;
namespace DataServiceClient
{
public class Address
{
public int AddressID { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string City { get; set; }
public DateTime ModifiedDate { get; set; }
public string PostalCode { get; set; }
public Guid rowguid { get; set; }
public int StateProvinceID { get; set; }
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button_Click(object sender, EventArgs e)
{
DataServiceContext ctx = new
DataServiceContext(new Uri("https://localhost:1492/AdvWksSales.svc/"));
// This example expects the user to enter
// an integer representing AddressID in textBox1.
DataServiceQuery<Address> query =
ctx.CreateQuery<Address>(
"SalesOrderHeader(45678)/Address");
StringBuilder output = new StringBuilder();
foreach (Address address in query)
{
output.Append("Id: " + address.AddressID +
" Line 1: " + address.AddressLine1 + "\r\n");
}
richTextBox1.Text = output.ToString();
}
出力は次のとおりです。
Id: 70 Address Line1: 1792 Belmont Rd. City: Monroe
DataSvcUtil ツールの使用
クラスを手動で記述する方法は、種類の少ない場合は適していますが、データ サービス スキーマがより複雑な場合、維持するクラスの数とサイズが増大するため、手動で維持するには複雑すぎます。ADO.NET Data Services に付属する DataSvcUtil.exe というコード生成ツールを使用する方が便利です。このツールは、データ サービス定義から .NET クラスを生成します。
DataSvcUtil.exe は、\WINDOWS\Microsoft.NET\Framework\v3.5\ ディレクトリにあります。コマンド ラインでは、生成される種類のデータ サービスの基本 URL を引数として指定します。たとえば、Northwind サービスが、https://localhost:1234/Northwind.svc にある Visual Studio 開発サーバーで実行されている場合、クラスを生成するコマンド ラインは次のようになります。
C:\Program Files\Microsoft Visual Studio 9.0\VC>"C:\WINDOWS\Microsoft.NET\Framework\v3.5\DataSvcUtil.exe"
/out:c:\northwind.cs /uri:https://localhost:1365/Northwind.svc
コマンドの出力は、データ サービスにある各エンティティ型のクラスが含まれる C# ファイルです (/language:VB
スイッチを使用すると Visual Basic の型を生成できます)。
生成されたクラスには、プリミティブ型の値を表すメンバと、オブジェクト モデルを通じたナビゲーションを容易にする関連付けが含まれます。
LINQ to ADO.NET Data Services
.NET クライアント ライブラリは、「Microsoft Data Web Client」で示されている DataServiceContext.CreateQuery
の呼び出しでデータ サービスをクエリすることに加えて、統合言語クエリ (LINQ) を使用したデータ サービスのクエリをサポートします。LINQ の詳細については、「LINQ to Entities」を参照してください。クライアント ライブラリは、ターゲット データ サービスで URI に LINQ ステートメントをマッピングし、指定されたリソースを .NET オブジェクトとして取得する場合の詳細を処理します。次の例は、返される結果セットにおいて、London 市内のすべての顧客を会社名順で取得する方法を示しています。
using System;
using System.Data.Services.Client;
using System.Linq;
using NorthwindModel;
namespace TestApplication
{
class Program
{
static void Main(string[] args)
{
NorthwindEntities ctx = new
NorthwindEntities(
new Uri("https://localhost:1365/Northwind.svc"));
var q = from c in ctx.Customers
where c.City == "London"
orderby c.CompanyName
select c;
foreach (var cust in q)
{
Console.WriteLine(cust.CompanyName);
}
}
}
}
[!メモ]
LINQ 構文で表現できるクエリのセットは、データ サービスによって使用される Representational State Transfer (REST) ベースの URI 構文で有効なクエリのセットよりも範囲が広くなります。クエリを対象のデータ サービスの URI にマップできない場合、例外がスローされます。REST の詳細については、「REST サービスおよびセマンティクス (ADO.NET Data Services フレームワーク)」を参照してください。
[!メモ]
このセクションと次の 2 つのセクションの例では、Northwind サンプル データベースを使用します。Northwind サンプルは、https://go.microsoft.com/fwlink/?linkid=24758 からダウンロードできます。
関連付け
オブジェクト間の関連付けは、DataServiceContext
クラスによって追跡および管理されます。関連付けられたオブジェクトは、"集中的に" または必要に応じて読み込むことができます。"集中" 読み込みと "レイジー" 読み込みについては、「ADO.NET エンティティ フレームワーク」ドキュメントの「オブジェクトとしてのデータのクエリ」および「クエリ結果の形成」を参照してください。URL 形式については、「URI によるデータの単純なアドレス指定スキーム (ADO.NET Data Services フレームワーク)」に説明されています。
関連付けられたエンティティを必要に応じて読み込むには、DataServiceContext
クラスの LoadProperty
メソッドを使用します。次の例は、Category
エンティティに関連付けられた Product
エンティティを遅延読み込みする方法を示しています。
using System;
using System.Data.Services.Client;
using NorthwindModel;
namespace TestApplication
{
class Program
{
static void Main(string[] args)
{
DataServiceContext ctx = new
DataServiceContext(
new Uri("https://localhost:1365/Northwind.svc"));
DataServiceQuery<Categories> categories =
ctx.CreateQuery<Categories>("/Categories");
foreach (Categories c in categories)
{
Console.WriteLine(c.CategoryName);
ctx.LoadProperty(c, "Products");
foreach (Products p in c.Products)
{
Console.WriteLine("\t" + p.ProductName);
}
}
}
}
}
}
シナリオによっては、関連付けられたオブジェクトが必要な場合に、オブジェクトを取得する際の追加要求が原因で増加する待機時間を回避する必要があります。このような場合は、URL 内で expand
オプションを使用できます。クライアント ライブラリは、結果に最上位エンティティおよび関連付けられたエンティティの両方が含まれていることを認識し、これらのすべてのエンティティをオブジェクト グラフとして具体化します。これを、集中読み込みと呼びます。集中読み込みは、前の例と似ていますが、1 回のラウンドトリップで関連製品をデータ サービスに読み込みます。
次の例は、カテゴリに関連付けられた製品が含まれる展開オプションを示しています。
using System;
using System.Data.Services.Client;
using NorthwindModel;
namespace TestApplication
{
class Program
{
static void Main(string[] args)
{
DataServiceContext ctx = new
DataServiceContext(
new Uri("https://localhost:1365/Northwind.svc"));
// get a single category
DataServiceQuery<Categories> categories =
ctx.CreateQuery<Categories>("/Categories(1)?$expand=Products");
foreach (Categories c in categories)
{
//Console.WriteLine(c.CategoryName);
richTextBox1.Text = c.CategoryName;
foreach (Products p in c.Products)
{
//Console.WriteLine("\t" + p.ProductName);
richTextBox1.Text = richTextBox1.Text +
"\r\n\t" + p.ProductName ;
}
}
}
}
}
更新のサポート
データ サービスで新しいインスタンスを作成するには、次のコード例に示すように、.NET オブジェクトを作成し、使用される DataServiceContext
インスタンスの AddObject
を呼び出して、オブジェクトと対象エンティティのセットを渡します。
using System;
using Microsoft.Data.WebClient;
using NorthwindModel;
namespace TestApplication
{
class Program
{
static void Main(string[] args)
{
DataServiceContext ctx = new
DataServiceContext(
new Uri("https://localhost:1365/Northwind.svc"));
Categories cNew = new Categories();
cNew.CategoryName = "NewCategory1";
cNew.Description = "Add Item Test.";
ctx.AddObject("Categories",cNew);
ctx.SaveChanges();
}
}
}
データ サービスでエンティティが作成または変更されると、サービスは、データベースまたは自動生成キーでトリガの結果として更新された可能性のあるプロパティ値を含む、エンティティの新しいコピーを返します。クライアント ライブラリは、これらの新しい値を使用して .NET オブジェクトを自動的に更新します。
既存のエンティティ インスタンスを変更するには、まず、そのオブジェクトをクエリしてそのプロパティに必要な変更を行い、UpdateObject
メソッドを呼び出して、オブジェクトの更新を送信する必要があることをクライアント ライブラリに示します。
[!メモ]
次の例では、上記のコード生成ツールによって作成され、
DataServiceContext
から派生したコンテキスト クラスNorthwindEntities
を使用します。この派生クラスは、サービスに対するコーディングを簡略化するサービス固有のプロパティを提供します。
次のコード例は、UpdateObject
メソッドを使用した更新の構文を示しています。
using System;
using Microsoft.Data.WebClient;
using System.Linq;
using NorthwindModel;
namespace TestApplication
{
class Program
{
static void Main(string[] args)
{
NorthwindEntities ctxN =
new NorthwindEntities(
new Uri("https://localhost:1365/Northwind.svc"));
var c1 = (from c in ctxN.Categories
where c.CategoryName == "NewCategory1"
select c).First();
c1.CategoryName = "UpdatedCategory";
//ctxN.AttachTo("Categories", c1);
ctxN.UpdateObject(c1);
ctxN.SaveChanges();
}
}
}
エンティティ インスタンスを削除するには、DataServiceContext
オブジェクトの Delete
メソッドを呼び出します。
変更は、DataServiceContext
インスタンスで追跡されますが、サーバーには直ちに送信されません。指定されたアクティビティに対して必要な変更が完了したら、SaveChanges
を呼び出して、すべての変更をデータ サービスに送信します。
関連付けの更新
更新インフラストラクチャは、関連付けの変更を管理することもできます。.NET オブジェクト間の関連付けを変更し、HTTP インターフェイスでの関連付けの作成または関連付けの削除操作としてクライアント ライブラリに変更を反映させることができます。これを説明するため、次の例では、Northwind データベースで Product
を作成し、これを既存の Category
に関連付けます。カテゴリと製品は、1 対多の関連付けにあるため、指定された製品は 1 つの特定カテゴリを持ちます。次のコードは、Add
メソッドを使用して、Category
への Product
の関連付けを追加する方法を示しています。
using System;
using Microsoft.Data.WebClient;
using System.Linq;
using NorthwindModel;
namespace TestApplication
{
class Program
{
static void Main(string[] args)
{
NorthwindEntities ctx = new
NorthwindEntities(new Uri(https://localhost:1234/Northwind.svc));
var c1 = (from c in ctx.Categories
where c.CategoryName == "UpdatedCategory"
select c).First();
Products p = new Products();
p.ProductName = "TestProduct";
p.Discontinued = false;
p.QuantityPerUnit = "1";
p.ReorderLevel = 100;
p.UnitPrice = 1.1M;
p.UnitsInStock = 200;
p.UnitsOnOrder = 0;
ctx.AddObject("Products", p);
// Add binding between product and category
p.Categories = c1;
ctx.SetLink(p, "Categories", c1);
ctx.SaveChanges();
Console.ReadKey();
}
}
双方向の関連付けを持つ任意のオブジェクト グラフへの変更を管理することは、複雑な問題です。ADO.NET エンティティ フレームワークのような高度なライブラリは、非常に高度で一貫性のある状態マネージャを提供し、部分的に具体化されたグラフの処理を可能にします。一方、ADO.NET クライアント ライブラリは、最小限のフットプリントを目的として設計されており、データ サービス操作の .NET オブジェクトへのマッピングを可能にするのに必要なプリミティブだけを提供します。
次のグラフは、ソース エンティティと対象エンティティ、およびさまざまな関連付けの更新メソッドを必要とするエンティティの状態を示しています。グラフの縦軸と横軸に従って、呼び出すことが有効であるメソッドを検索します。
対象エンティティ → ソース エンティティ ↓ |
null |
Added |
Modified |
Deleted |
Unchanged |
Added |
SetLink |
AddLink SetLink |
AddLink SetLink |
なし |
AddLink SetLink |
Modified |
SetLink |
AddLink SetLink |
AddLink AttachLink DeleteLink SetLink |
DeleteLink |
AddLink AttachLink DeleteLink SetLink |
Deleted |
SetLink |
なし |
DeleteLink |
DeleteLink |
DeleteLink |
Unchanged |
SetLink |
AddLink |
AddLink AttachLink DeleteLink SetLink |
DeleteLink |
AddLink AttachLink DeleteLink SetLink |
AttachLink は、ソース エンティティと対象エンティティの両方が未変更の状態である場合にのみ機能します。AttachLink では、リレーションシップが永続化されません。目的の結果が SavingChanges の呼び出しによりリンクを保存することである場合は、AddLink を使用しないでください。
Products
と Catagories
間のリレーションシップがあり、プロパティ Products.Categories
がコレクションである場合は、objCtx.AddLink(prod, "Categories", c1)
を使用します。
Products.Cateories
が単なる参照である場合は、objCtx.SetLink(prod, "Categories", c1);
を使用します。
Added
状態でソース エンティティの SaveChanges を実行する場合、HTTP POST には、変更状態または未変更状態であるその他のエンティティへのリンクが含まれます。
AttachLink メソッドは、EntityStates.Unchanged
状態のリンクを作成します。これは、ユーザーが、サーバーに送信されないコンテキストによって追跡されるリンクを作成するためのメカニズムです。
クライアント ライブラリの認証
.NET クライアント ライブラリは、HTTP プロトコルに対する .NET Framework サポートを使用します。その際、一連の資格情報が指定されると、フレームワーク インフラストラクチャは HTTP を通じて認証スキームを自動的に処理します。
既定では、クライアント ライブラリからは、HTTP スタックに資格情報が提供されません。ただし、DataServiceContext
で Credentials プロパティを設定して、ICredentials
インターフェイスを実装するオブジェクトを指定できます。資格情報の詳細については、「WebRequest.Credentials」を参照してください。
データ サービスとの非同期の対話
Web アプリケーションは、内部ネットワーク内で実行するアプリケーションより長い、クライアントとサーバー間の待機時間に対応するようにデザインする必要があります。サーバーとの非同期の対話を使用すると、アプリケーションがサーバーからの応答を待機している間、ユーザー インターフェイスの応答性を維持することができます。
このリリースでは、ADO.NET クライアント ライブラリが、DataServiceContext
クラスで利用可能な多くの操作 (変更の取得や変更の保存など) に対して非同期モードの操作をサポートしています。次の例は、コードでクライアント ライブラリの非同期の API を使用する方法を示しています。
using System;
using Microsoft.Data.WebClient;
using System.Linq;
using NorthwindModel;
namespace TestApplication
{
class Program
{
static void Main(string[] args)
{
NorthwindEntities ctx = new
NorthwindEntities(new Uri(https://localhost:51905/nw.svc));
DataServiceQuery<Customers> q = ctx.Customers;
q.BeginExecute(
delegate(IAsyncResult ar)
{
foreach (Customers c in q.EndExecute(ar))
{
Console.WriteLine(c.CompanyName);
}
},
null);
Console.ReadKey();
}
}
}
参照
概念
HttpWebRequest GET (ADO.NET Data Services フレームワーク)
ADO.NET Data Services の作成