SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

SQL ServerとADO.NETを用いたBLOB(バイナリラージオブジェクト)の処理方法

読み出し処理の改良

 これまで示した例では、写真データの読み出しは次のように実行されていました。

p.PhotoData = (byte[])reader.GetValue(reader.GetOrdinal("Photo"));

 GetValue()メソッドは、指定された列のすべてのデータをオブジェクトとして返します。写真のサイズが大きい場合はどうなるでしょうか?  バイト配列のサイズが膨大である場合は、アプリケーションのパフォーマンスが低下します。幸いなことにSqlDataReaderクラスには、これよりもエレガントな方法が用意されています。SqlDataReaderのGetBytes()メソッドを使用すると、列値をチャンクで読み出すことができます。GetBytes()メソッドの動作を示すために、GetByID()メソッドをリスト14のように変更します。

リスト14 SqlDataReaderクラスのGetBytes()メソッドを使用する
public static Photo GetByID(int photoid)
{
   SqlConnection cnn = new SqlConnection(strConn);
   SqlCommand cmd = new SqlCommand();
   byte[] data = new byte[1000];

   cmd.CommandText = "select * from photos
                      where PhotoID=@photoid";
   cmd.Connection = cnn;

   SqlParameter pId = new SqlParameter("@photoid", photoid);
   cmd.Parameters.Add(pId);

   cnn.Open();
   SqlDataReader reader = cmd.ExecuteReader();
   Photo p = new Photo();
   while (reader.Read())
   {
      p.PhotoID = reader.GetInt32(reader.GetOrdinal("PhotoID"));
      p.Title = reader.GetString(reader.GetOrdinal("Title"));
      p.Description =
         reader.GetString(reader.GetOrdinal("Description"));
      MemoryStream ms = new MemoryStream();
      int index = 0;
      while (true)
{
long count = reader.GetBytes(reader.GetOrdinal("Photo"),
index, data, 0, data.Length);
if (count == 0)
{
break;
}
else
{
index = index + (int)count;
ms.Write(data, 0, (int)count);
}
}
p.PhotoData = ms.ToArray();
} cnn.Close(); return p; }

 太字で示されたコードに着目してください。まず読み出すデータチャンクを格納するバイト列を宣言します。次にデータ全体を格納するためのメモリストリームを宣言します。

 whileループは、すべてのバイトが読み出されるまでSqlDataReaderのGetBytes()メソッドを呼び出します。GetBytes()メソッドの最初の引数は列インデックスを指定し、2番目の引数は列における読み出し開始位置を指定します。3番目の引数はバイト配列における書き込み位置を示し、最後の引数は読み出される最大バイト数を示します。GetBytes()メソッドは、正常に読み出されたバイト数を返します。戻り値が0である場合は、データがまったく読み出されなかったことを意味します。

 データを読み出し、メモリストリームに格納したら、MemoryStreamクラスのToArray()メソッドを呼び出して、それをバイト配列に変換します。

更新処理の改良

 更新する写真が大容量である場合、アプリケーションのパフォーマンスに影響が生じてしまいます。このような場合には、更新処理もチャンクで実行することができます。リスト15は、PhotoHelperクラスのUpdate()メソッドを変更したものです。

リスト15 UPDATEステートメントの.WRITE句を使用する
public static int Update(Photo p)
{
   SqlConnection cnn = new SqlConnection(strConn);
   SqlCommand cmd = new SqlCommand();

   cmd.Connection = cnn;
   cmd.CommandText =
"update photos set title=@title,description=
@description,photo.write(@photo,@offset,@length)
where photoid=@photoid";
SqlParameter title = new SqlParameter("@title", p.Title); SqlParameter description = new SqlParameter("@description", p.Description); SqlParameter photo = new SqlParameter("@photo", SqlDbType.VarBinary); photo.Value = p.PhotoData; SqlParameter offset = new SqlParameter("@offset",SqlDbType.BigInt); offset.Value = 0; SqlParameter length = new SqlParameter("@length", p.PhotoData.Length); SqlParameter photoid = new SqlParameter("@photoid", p.PhotoID); cmd.Parameters.Add(title); cmd.Parameters.Add(description); cmd.Parameters.Add(photo); cmd.Parameters.Add(offset); cmd.Parameters.Add(length); cmd.Parameters.Add(photoid); cnn.Open(); int i = cmd.ExecuteNonQuery(); cnn.Close(); return i; }

 コードの中の太字で示された行に着目してください。UPDATEステートメントが.WRITE()句を使用するように変更されています。.WRITE()句は、varchar(MAX)、nvarchar(MAX)、varbinary(MAX)列に対して適用され、列の値全体を置き換えるのではなく、列の一部のみを変更することが可能です。これは、大量のデータを扱う際には非常に便利です。

 .WRITE()句には、列に書き込むデータ、列内の書き込み開始位置、書き込むデータの長さという3つの引数があります。ループ内でUPDATEステートメントを実行することにより、複数のチャンクで列値を更新することもできます。

まとめ

 BLOB(バイナリラージオブジェクト)を扱うアプリケーションでは、データをSQL Server内に格納するか、それとも物理的なファイルとして格納するかを決定しなければなりません。

 SQL Serverでは、BLOBを格納するためのデータ型としてvarbinary(MAX)を提供していますが、旧バージョンのImageデータ型もまだ使用することができます。.NETアプリケーションでは、SqlDataReaderクラスを用いることによってBLOBデータを読み出すことができます。

 SqlDataReaderのGetBytes()メソッドは、列からバイナリデータをチャンクで読み出すためのものです。バイナリデータをデータベースへと書き戻す際には、SQL Serverの.WRITE()句を使用すれば、データをチャンクで書き込むことができます。SQL ServerとADO.NETにより、ドキュメント、ファイル、写真などの大きなバイナリデータを容易に扱うことが可能です。

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Bipin Joshi(Bipin Joshi)

 コンサルティング会社BinaryIntellect Consultingを経営し、さまざまな.NET技術に関する優れたトレーニングプログラムを実施。ソフトウェアコンサルタント、メンター、数々の書籍の著者、Webマスター、Microsoft MVP、ASPInsiders会員など、さまざまな肩書きを...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/3026 2008/10/06 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー