ADO.NET 2.0 における XML データ型のサポート: SQL Server 2005 の XML データの使用
Bob Beauchemin
DevelopMentor
October 2004
日本語版最終更新日 2005 年 1 月 6 日
適用対象:
Microsoft SQL Server 2005
Microsoft ADO.NET 2.0
XML
概要: Microsoft ADO.NET 2.0 と Microsoft SQL Server 2005 の XML サポートが共に強化されて、アプリケーションで XML データをより簡単に扱えるようになったことについて説明します。
目次
はじめに
XML か文字列か
ドキュメント、断片、および FOR XML のサポート
クライアント側での XML スキーマのサポート
まとめ
はじめに
Microsoft SQL Server 2005 では、画期的な変更点として XML データ型が導入されています。 このデータ型は INT や VARCHAR と同様のファーストクラスのデータ型で、SQL Server 2005 では、一連の XML 用関数を使用してこのデータ型をインプレースでクエリおよび処理できます。 また、XML スキーマのコレクションをデータベースに格納できるため、データベースを使用したスキーマ検証も可能です。 このほか、XML 合成機能 (SELECT ... FOR XML ダイアレクト) や XML 分解関数 OpenXML() も拡張されています。より軽量の XML 分解機能として、XML データ型に対する nodes() 関数も新たに用意されています。
データベース サーバーの XML 機能がこれだけ新調され強化されていることを考えれば、Microsoft ADO.NET 2.0 の SqlClient データ プロバイダが同じように強化されているのも当然と言えます。 ADO.NET の DataSet にも変更が加えられており、XML 型の DataColumn がサポートされるようになっています。また、System.Data と System.Xml の "統合ポイント" も拡大されています。 ここでは、SQL Server 2005 の XML データ型をクライアント側で使用する方法について説明します。
SQL Server 2005 で生成できる XML 出力は 2 種類あります。 SELECT * FROM AUTHORS FOR XML AUTO ステートメントでは、1 列 1 行の行セットではなく XML のストリームが生成されます。 この種類の出力は SQL Server 2000 からの変更はありません。 XML ストリームの出力は、SQL Server クエリ アナライザでは 1 列 1 行の行セットとして表示されますが、これは単にクエリ アナライザ ツールの制限によるものです。 このストリームは、特殊な一意の識別子名 "XML_F52E2B61-18A1-11d1-B105-000805F49916B" によって "通常の" 列と区別できます。 この名前は、この列を通常の行セットとしてではなくストリームとしてクライアントに送信するように、背後にある TDS (tabular data stream、SQL Server のネットワーク形式) パーサーに対して指示するためのものです。 クライアント側では、この特殊なストリームを取得するために、SqlCommand.ExecuteXmlReader という特殊なメソッドを使用します。 SQL Server 2005 では、SELECT ... FOR XML ダイアレクトがさまざまな形で強化されています。 以下にその一部を紹介します。
- 使いやすい FOR XML PATH モードが新たに用意されています。ほとんどの場合、SQL Server 2000 の FOR XML EXPLICIT モードの代わりに使用できます。
- TYPE ディレクティブを使用することによって、ストリームだけでなく XML データ型の列も生成できます。
- FOR XML 式をネストできます。
- SELECT ... FOR XML は、ROOT ディレクティブを使用することによって、XML 断片だけでなく XML ドキュメントも生成できます。
- ストリームの先頭に標準の XSD スキーマを追加できます。
XML がファーストクラスのリレーショナル データベース用データ型になったことは、ADO.NET 2.0 のリレーショナル データ型の列挙体を参照すればすぐにわかります。 System.Data.DbType と System.Data.SqlDbType には、それぞれ DbType.Xml と SqlDbType.Xml という値が追加されています。 また、System.Data.SqlTypes 名前空間にも、SqlXml という新しいクラスが追加されています。 このクラスは、XML 型の値を処理する XmlReader インスタンスのファクトリとして機能します。 ここで簡単なコードを使って実際に見てみましょう。 次のような SQL Server テーブルがあったとします。
CREATE TABLE xmltab (
id INT IDENTITY PRIMARY KEY,
xmlcol XML)
クライアント側では、次の ADO.NET 2.0 コードを使用してこのテーブルにアクセスできます。
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Xml;
void GetXMLColumn {
// 構成ファイルから接続文字列を取得する方法については
// "...汎用的なコーディング" アーティクルを参照してください。
string s = GetConnectStringFromConfigFile("xmldb");
using (SqlConnection conn = new SqlConnection(s))
using (SqlCommand cmd = new SqlCommand(
"select * from xmltab", conn))
{
conn.Open();
SqlDataReader rdr = cmd.ExecuteReader();
DataTable t = rdr.GetSchemaTable();
while (rdr.Read())
{
SqlXml sx = rdr.GetSqlXml(1);
XmlReader xr = sx.CreateReader();
xr.Read();
Console.WriteLine(xr.ReadOuterXml());
}
}
}
GetSchemaTable によって生成される DataTable を参照すると、列のメタデータが返されます。これにより、列を正しく識別できます。
ProviderType: 25 (25 = XML)
ProviderSpecificDataType: System.Data.SqlTypes.SqlXml
DataType: System.Xml.XmlReader
DataTypeName:
SQL Server に組み込まれている他の型と同じように見えます。 この列の ".NET 型" は XmlReader なので、.NET には、ファイルから読み込まれたり XmlDocument クラスで生成されたりした XML と同じに見えます。 XML データ型の列を ADO.NET 2.0 の ストアド プロシージャやパラメータ化ステートメントのパラメータとして使用するのも同じように簡単です。
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Xml;
void AddARow {
// 構成ファイルから接続文字列を取得します
string s = GetConnectStringFromConfigFile("xmldb");
using (SqlConnection conn = new SqlConnection(s))
using (SqlCommand cmd = new SqlCommand(
"insert xmltab(xmlcol) VALUES(@x)", conn))
{
conn.Open();
cmd.Parameters.Add("@x", SqlDbType.Xml);
// パラメータの値をファイルに関連付けます
XmlReader xr = XmlReader.Create("somexml.xml");
cmd.Parameters[0].Value = new SqlXml(xr);
int i = cmd.ExecuteNonQuery();
}
}
XML か文字列か
上のコードのメソッドは両方とも、SqlTypes の SQL Server 固有のデータ型を使用しています。 SqlReader のより一般的なアクセサ メソッドである GetValue() を使用した場合は、値がまったく異なります。 この場合、列は XmlReader としてではなく .NET String クラスとして表されます。 列の .NET データ型が XmlReader であることはメタデータからわかりますが、列を XmlReader に単純にキャストすることはできません。 GetSqlXml() 以外のアクセサ メソッドを使用した場合には文字列が返されます。
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Xml;
void GetXMLColumn {
// 構成ファイルから接続文字列を取得します
string s = GetConnectStringFromConfigFile("xmldb");
using (SqlConnection conn = new SqlConnection(s))
using (SqlCommand cmd = new SqlCommand(
"select * from xmltab", conn))
{
conn.Open();
SqlDataReader rdr = cmd.ExecuteReader();
// "System.String" を出力します
Console.WriteLine(rdr[1].GetType());
// 無効なキャストのためエラーになります
XmlReader xr = (XmlReader)rdr[1];
// 今度はエラーになりません
string s = (string)rdr[1];
}
}
SqlReader.GetProviderSpecificValue() メソッドを使用しても文字列が返されます。 これはやや異常な動作です。というのも、GetProviderSpecificFieldType では System.Sql.Types.SqlXml が問題なく返されるからです。 現在のベータ版のプロバイダに問題があるようなので、このメソッドの使用はしばらく見合わせることにします。
// System.Data.SqlTypes.SqlXml
Console.WriteLine(rdr.GetProviderSpecificFieldType(1));
// System.Data.SqlTypes.SqlString
Object o = rdr.GetProviderSpecificValue(1);
Console.WriteLine(o.GetType());
SqlClient にも XML パラメータのための同様の機能が用意されており、同じように String データ型を使用できます。 XML 型が渡されるはずのところで文字列 (NVARCHAR) を渡すことができるのは、SQL Server によって VARCHAR や NVARCHAR から XML データ型への変換が自動的に行われるからです。 この変換は、次の例で示すようにクライアント側で行うこともできます。 ストアド プロシージャ insert_xml を指定すれば、どちらの方法でも string/NVARCHAR から XML への自動変換が機能します。
-- T-SQL のストアド プロシージャ定義
CREATE PROCEDURE insert_xml(@x XML)
AS
INSERT xmltab(xmlcol) VALUE(@x)
// クライアント側のコード
using System;
using System.Data;
using System.Data.SqlClient;
void InsertXMLFromClient {
// 構成ファイルから接続文字列を取得します
string s = GetConnectStringFromConfigFile("xmldb");
using (SqlConnection conn = new SqlConnection(s))
using (SqlCommand cmd1 = new SqlCommand(
"INSERT xmltab(xmlcol) VALUES(@x)", conn))
using (SqlCommand cmd2 = new SqlCommand(
" insert_xml", conn))
{
string str = "<somedoc/>";
conn.Open();
// サーバー側の変換
cmd1.Parameters.Add("@x", SqlDbType.NVarChar);
cmd1.Parameters[0].Value = str;
cmd1.ExecuteNonQuery();
// クライアント側の変換も可能
cmd2.CommandType = CommandType.StoredProcedure;
cmd2.Parameters.Add("@x", SqlDbType.Xml);
cmd2.Parameters[0].Value = s;
cmd2.ExecuteNonQuery();
}
}
ドキュメント、断片、および FOR XML のサポート
SQL Server 2005 の XML データ型は、XML ドキュメントと XML ドキュメントの断片の両方をサポートしています。 断片は、複数のトップレベル要素や単純なテキスト ノードを含めることができる点でドキュメントと異なります。 型指定された XML の列、変数、またはパラメータを使用する場合、DOCUMENT (断片は許可されない) または CONTENT (断片が許可される) のいずれかを使用して、断片を許可するかどうかを指定できます。 既定値は CONTENT で、型指定のない XML では断片が許可されます。 次の T-SQL コードは、断片をサポートする例です。
CREATE TABLE xmltab (
id INT IDENTITY PRIMARY KEY,
xmlcol XML)
GO
-- ドキュメントを挿入します
INSERT xmltab VALUES('<doc/>')
-- 断片、複数のトップレベル要素
INSERT xmltab VALUES('<doc/><doc/>')
-- 断片、単純なテキスト ノード
INSERT xmltab VALUES('Hello World')
-- このような断片にも対応します
INSERT xmltab VALUES('<doc/>sometext')
XML 断片は SELECT ... FOR XML でも生成されます。 たとえば、SELECT job_id, min_lvl, max_lvl FROM jobs FOR XML AUTO ステートメントの出力は次のようになります。 複数のルート要素がある点に注目してください。
<jobs job_id="1" min_lvl="10" max_lvl="10" />
<jobs job_id="2" min_lvl="200" max_lvl="250" />
<jobs job_id="3" min_lvl="175" max_lvl="225" />
<jobs job_id="4" min_lvl="175" max_lvl="250" />
<!-- スペースの節約のために一部の jobs 行が削除されています -->
ドキュメントと断片は、どちらも SqlXml を使用してサポートされます。 SqlXml の CreateReader() メソッドでは常に、新しい XmlReaderSettings クラスを使用して断片をサポートする XmlReader が作成されます。以下に例を示します。
// SqlXml.CreateReader からの擬似コード
Stream stm = stm; // 列のデータをストリームに書き込みます (コードは省略)
XmlReaderSettings settings = new XmlReaderSettings();
settings.ConformanceLevel = ConformanceLevel.Fragment;
XmlReader xr = XmlReader.Create(
stm, String.Empty, null, null,settings);
同じ方法で XmlReader を作成すると、XML 断片を入力パラメータで使用できます。 SqlXml 型を使用する場合は断片のサポートが組み込まれていますが、断片を含む XmlReader の扱いに関しては注意が必要です。 XmlReader.GetOuterXml() を呼び出しても、返されるのは最初の断片だけです。それに続く断片を取得するには、XmlReader の Read メソッドをもう一度呼び出して、XmlReader の位置を動かす必要があります。 これについては、後ほど例を紹介します。
T-SQL の "SELECT ... FOR XML" では、1 列 1 行の行セットではなく XML のストリームが生成されていました。 また、提供される XML データは、XML の標準のシリアル化形式ではなくバイナリ形式でした。 この形式の違いに加えて、"SELECT ... FOR XML" では常に断片が生成されるため、それを取り込むための特殊なメソッドが必要でした。 SqlClient には、そのためにプロバイダ専用のメソッド、SqlCommand.ExecuteXmlReader が実装されています。 SQL Server 2000 と ADO 1.0/1.1 を使用する場合、FOR XML クエリの結果を取得するには ExecuteXmlReader を使用する必要があります。そうしないと、文字列の連結を必要とする見苦しい方法で対処しなければならなくなります。 SQL Server 2005 では、FOR XML が強化されているほか、データ型としての XML もサポートされているため、SQL Server から XML の単一のストリームを取得する場合以外は ExecuteXmlReader を使用する必要はありません。 このメソッドは、SQL Server 2000 用に記述されたすべてのコードで使用されているため、ADO.NET 2.0 でもサポートされており、さらに強化されています。
ExecuteXmlReader を使用すると、以前のバージョンのように "FOR XML" クエリから任意のストリームを取得できます。 さらに、通常の SELECT ステートメントによって生成された XML データ型の列も取得できます。 ただし、通常の SELECT ステートメントによって複数の行が返される場合は、ExecuteXmlReader では最初の行の内容しか返されないので注意してください。 次の例は、前の例と同じテーブルを使用してこのことを示しています。
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Xml;
void UseExecXmlReader {
// 構成ファイルから接続文字列を取得します
string s = GetConnectStringFromConfigFile("xmldb");
using (SqlConnection conn = new SqlConnection(s))
using (SqlCommand cmd1 = new SqlCommand(
"select * from pubs..authors for xml auto,root('root')", conn))
using (SqlCommand cmd2 = new SqlCommand(
"select * from pubs..authors for xml auto", conn))
using (SqlCommand cmd3 = new SqlCommand(
"select * from xmltab", conn))
{
conn.Open();
// ドキュメントが含まれています
XmlReader xr1 = cmd1.ExecuteXmlReader();
// 断片が含まれています
XmlReader xr2 = cmd2.ExecuteXmlReader();
// xmltab の最初の行の内容のみが含まれています
XmlReader xr3 = cmd3.ExecuteXmlReader();
// XmlReader を使用します
xr1.Dispose(); xr2.Dispose(); xr3.Dispose();
}
}
これまで ADO.NET 2.0 における XML データの取得について説明してきましたが、最後に、さまざまな利用シナリオにおける XmlReader の内容の存続期間についても触れておきます。 XmlReader の存続期間について調べることは、SqlClient によって行われるバッファ処理や、このデータを使用してパフォーマンスを最大限に高める方法を理解する上でも役立ちます。 XmlReader はリソースを使用するため、SqlConnection、SqlCommand、および SqlDataReader と同様に、Close() メソッドや Dispose() メソッドを呼び出してリソースを解放する必要があります。 SqlDataReader を通じて XML 列を読み取る場合には、各行に 1 つの XmlReader が割り当てられることもあります。 ご存じのように、XmlReader の内容は、同じ行の前の列に戻ったり次の行に移動したりできるようにするためにメモリにバッファされます。 SqlCommand の CommandBehavior.SequentialAccess を使用する場合には XmlReader 全体がメモリにバッファされることはありませんが、このアクセス方法を使用する場合にはより注意が必要になります。 CommandBehavior.SequentialAccess を使用する際には、行セットの次の列に移動する前に、列に関連付けられた XmlReader の使用を完了しておく必要があります。次の列に移動した後もその XmlReader は有効なように見えますが、Read() メソッドを呼び出してもデータは生成されません。 ExecuteReader ではなく ExecuteXmlReader や ExecuteScalar を使用する場合には、この動作をそれほど意識する必要はありません。ただし、この場合も、忘れずに Close や Dispose を呼び出して XmlReader のリソースを解放する必要があります。
クライアント側での XML スキーマのサポート
SQL Server 2005 は、厳密に型指定された XML をサポートしています。厳密に型指定された XML では、XML データが 1 つまたは一連の XML スキーマに準拠している必要があります。 このサポートを利用するには、SQL Server の XML スキーマ コレクションを使用します。 XML スキーマ コレクションを他の SQL Server オブジェクトと同じように定義して、XML スキーマを SQL Server に格納します。 T-SQL DDL CREATE ステートメントと XML スキーマ コレクションの使用方法を以下に示します。
CREATE XML SCHEMA COLLECTION books_xsd
AS
-- ここに 1 つ以上の XML スキーマを指定します
GO
CREATE TABLE typed_xml (
id INT IDENTITY PRIMARY KEY,
-- rbooks_col の内容はスキーマに対して有効である必要があります
books_col XML(books_xsd)
)
-- ここで検証されます
INSERT typed_xml VALUES('<!-- 任意のドキュメント -->')
-- ここでも検証されます
UPDATE typed_xml
SET books_col.modify('<!-- 任意の XQuery DML -->')
WHERE id = 1
SQL Server 2005 の厳密に型指定された XML データをクライアントから使用する場合、検証はクライアント側ではなくサーバー側で行われます。 たとえば、前の例の AddARow メソッドを使用して typed_xml テーブルに行を追加する場合、データがネットワーク経由で SQL Server に送信されてから検証が行われます。 ただし、ほんの少しの作業で、SQL Server の XML スキーマ コレクションから XML スキーマを取得して、クライアント側で検証を行うこともできます。 これにより、ユーザーや Web サービスがスキーマに対して無効な XML を SQL Server に格納しようとしてクライアントに送信するのを防ぐことができるため、ラウンドトリップの回数を節約できます。ただし、注意すべき点が 2 つあります。 第 1 に、SQL Server から取得した XML スキーマの情報に依存することになるため、キャッシュされたクライアント側メタデータを使用する場合と同様の問題があります。 つまり、他のユーザーが、T-SQL ALTER XML SCHEMA ステートメントを使用してスキーマ コレクションを変更したり、スキーマ コレクションを削除して再作成したりする可能性があります。そのような場合は、クライアント側で検証を行っても無意味になります。 こうした突然の変化に備えるには、CREATE/ALTER/DROP XML SCHEMA DDL ステートメントに対して新しいイベント通知機能を使用することができます。 この場合は、クエリ通知で SqlNotificationRequest を使用する場合と同じように、カスタム コードを使用してサービス ブローカ サービスを監視します。 イベント通知は SQL Server 2005 の新機能ですが、以前に解説したクエリ通知に似ています (「ADO.NET 2.0 のクエリ通知」を参照)。 第 2 の注意点は、クライアント側で XML スキーマの検証を行っても、サーバー側で SQL Server によって再度チェックされるということです。 その XML (SQL Server のスキーマによって型指定された XML) のインスタンスがスキーマに対して有効であることは既に確認済みで改めて確認する必要はない、ということを SQL Server に伝える方法はありません。
クライアント側で XML スキーマの検証を行う場合は、T-SQL 関数 xml_schema_namespace() を使用して、SQL Server の XML スキーマ コレクションを取得します。 その際には、XML スキーマ コレクションの名前とデータベース スキーマの名前を指定する必要があります。これは、XML スキーマ コレクションはデータベース スキーマのスコープを持つためです。 これらの情報は、プログラムにハードコーディングすることも、クライアント側の行セットのメタデータから取り出すこともできます。 上で説明した SqlDataReader の GetSchemaTable メソッドを使用するか、新しい SqlMetaData クラスを使用すると、特定の列に関連付けられているスキーマ コレクションの名前を簡単に取得できます。 以下に短いコード例を示します。
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.Sql;
void GetCollectionInfo {
// 構成ファイルから接続文字列を取得します
string s = GetConnectStringFromConfigFile("xmldb");
using (SqlConnection conn = new SqlConnection(s))
using (SqlCommand cmd = new SqlCommand(
"select books_col from typed_xml", conn))
{
conn.Open();
// SQL Server のメタデータのみを取得します
SqlDataReader rdr = cmd.ExecuteReader(CommandBehavior.SchemaOnly);
SqlMetaData md = rdr.GetSqlMetaData(0);
string database = md.XmlSchemaCollectionDatabase;
string schema = md.XmlSchemaCollectionOwningSchema;
string collection = md.XmlSchemaCollectionName;
}
}
取得する XML スキーマ コレクションを特定できたら、T-SQL 関数を使用してクライアント側の XmlSchemaSet に取得します。 この例には、XmlReader を使用して断片を取得する方法も示されています。 この操作が必要なのは、XML スキーマ コレクションに複数の XML スキーマが含まれている可能性があるためです。xml_schema_namespace 関数では、コレクション内のすべての XML スキーマが断片として返されます。
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Xml;
using System.Xml.Schema;
void GetSchemaSet {
// 構成ファイルから接続文字列を取得します
string s = GetConnectStringFromConfigFile("xmldb");
using (SqlConnection conn = new SqlConnection(s))
using (SqlCommand cmd = new SqlCommand(
"SELECT xml_schema_namespace(N'dbo',N'books_xsd')", conn))
{
XmlSchemaSet ss = new XmlSchemaSet();
conn.Open();
SqlDataReader rdr = cmd.ExecuteReader();
rdr.Read();
XmlReader xr = rdr.GetSqlXml(0).CreateReader();
do
{
ss.Add(XmlSchema.Read(xr, null));
xr.Read();
}
while (xr.NodeType == XmlNodeType.Element);
}
}
XmlSchemaSet を用意できたら、後はクライアント側 XML 検証コードを Add ルーチンに組み込めば、クライアント側で検証を行えるようになります。
void ValidateAndStore(XmlSchemaSet ss)
{
// XmlSchemaSet を XmlReader に関連付けます
XmlReaderSettings settings = new XmlReaderSettings();
settings.Schemas = ss;
string s = GetConnectStringFromConfigFile("xmldb");
using (XmlReader xr = XmlReader.Create(
"file://c:/temp/somefile.xml", settings))
// 構成ファイルから接続文字列を取得します
using (SqlConnection conn = new SqlConnection(s))
using (SqlCommand cmd = new SqlCommand(
"insert typed_xml values(@x)", conn))
{
try
{
conn.Open();
// スキーマに対して有効でなかった場合はここで例外をスローします
cmd.Parameters.AddWithValue("@x", new SqlXml(xr));
int i = cmd.ExecuteNonQuery();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
クライアント側の XML スキーマ検証は、すべてのアプリケーションに必要な機能ではありませんが、アプリケーションで必要になった場合にはこのような方法で使用できます。 このほか、次のように、SELECT...FOR XML で XMLSCHEMA オプション (SQL Server 2005 の新しいオプション) を使用して XML スキーマを生成することもできます。
SELECT * FROM authors FOR XML AUTO, ELEMENTS, XMLSCHEMA
この種のクエリを使用した場合も、クライアント側で断片を分解して XmlSchemaSet を取得できます。ただし、現在のベータ版では実用上の制限があります。
まとめ
ここでは、新しい XML 型と FOR XML の新しい機能を使用して、Microsoft SQL Server の XML データを Microsoft ADO.NET の SqlClient で使用する方法や、SqlClient を使用して XML データを SQL Server のテーブルに挿入する方法を説明しました。 DataSet の XML 機能も改良されていますが、ここでは触れることができませんでした。これについては、今後、ADO .NET 2.0 の DataSet の強化に関する一連のアーティクルの中で取り上げていきます。 SQL Server の XML データの使用については MSDN オンラインの「Microsoft SQL Server 2005 での XML サポート」 (Shankar Pal、Mark Fussell、および Irwin Dolobowsky) を、SELECT...FOR XML の強化については MSDN オンラインの「What's New in FOR XML in Microsoft SQL Server 2005」 (Michael Rys) を、.NET 2.0 の System.Xml については「What's New in System.Xml for Visual Studio 2005 and the .NET Framework 2.0 Release」 (Mark Fussell) を、それぞれ参照してください。 XML が ADO.NET 2.0 と SqlClient にさまざまなレベルで統合されていることは間違いありません。そこでは、かつてないほどに緊密なデータ モデルの統合が実現されています。
執筆者紹介
Bob Beauchemin 氏は、DevelopMentor の教官、学習コースの作成者、およびデータベース カリキュラム コースの連絡係です。 データ中心の分散システムのアーキテクト、プログラマ、および管理者としての 25 年を超える経験を持っています。 Microsoft Systems Journal、SQL Server Magazine、およびその他のものに ADO.NET、OLE DB、SQL Server に関する記事を執筆したことがあり、『A First Look at SQL Server 2005 for Developers
』と『Essential ADO.NET
』の著者でもあります。