C# Programming

Image

ADO.NET 2.0 β

開発環境: Visual Studio 2005 

1.目次

.目次
2.目的
3.参考書
4.ADO.NET 1.1 からの変更点
4.1 MDACからSNACへ
4.2 DataSetの高速化(XMLシリアライズのバイナリーフォーマット)
4.3 ファクトリーパターンの導入
5.データセットを使用する場合の注意点
5.1 データのやり取りを最小限に抑える
5.2 データセットを保存するか、毎回再作成するか
5.3 データセットをサーバーとクライアントのどちらに保存するか
5.4 RemotingFormat にバイナリーフォーマット

2.目的

ADO.NET V2.0 β に基づく情報で、自分のためのメモです。

3.参考書

  1. MSDN:ADO.NET 2.0 基本クラスおよびファクトリによる汎用的なコーディング
  2. MSDN:データ アクセスに関する推奨事項

4.ADO.NET 1.1 からの変更点

ADO.NET 1.1 から ADO.NET 2.0で変更されると思われる代表的な点です。詳細は参考文献(1)からたどってください。

4.1 MDACからSNACへ

MDACから SNAC (SQL Native Client) へ変更になる。使用されるファイルは、SqlClient.dll, SqlClientR.dll。

4.2 DataSetの高速化(XMLシリアライズのバイナリーフォーマット)

参考文献1では、N層アプリケーションでデータを受け渡しする場合は、DataSetがいいよと書いているにもかかわらず、一方で大量のデータをDataSetで扱うのは良くないよ、と矛盾することが書いてあります。実際、ADO.NET V1.1までのDataSetでは、RemotingFormat にXMLシリアライズを使用しており、DataSetのデータ量が増大すると性能が著しく劣化するという問題があったようです。これに対して、ADO.NET V2.0 ではRemotingFormat にバイナリーフォーマットがサポートされるようになります。

ただし、互換性のためRemotingFormat はデフォルトでXML になっています。バイナリーフォーマットを使用する場合は、DataSetのRemotingFormat プロパティを明示的にBinary にする必要があります。

また、DataTableの機能強化も図られている。これは、通常は1つのテーブルだけを扱う場合が多く、DataSetで複数のテーブルを一度に扱うことは少ないので、DataTable をDataSetと同じぐらいに機能強化したようです。

4.3 ファクトリーパターンの導入

ADO.NET V1.1までは、プロバイダー依存のクラス(SqlConnection, OracleConnection)を直接使用します。ADO.NET V2.0では、GOFのFactory デザインパターンが導入された。これにより、次のようにプロバイダーへの依存度の低いコードを書けるようになります。

Factory パターンを使用する場合
...
using System.Configuration;
using System.Data.Common;
using System.Data.SqlClient;
...
DbConnection conn = null;
ConnectionStringSettings s = ConfigurationSettings.ConnectionStrings["ConnectionStrings"];

DbProviderFactory factory = DbProviderFactories.GetFactory(s.ProviderName);

if ((factory.SupportedClasses & DbProviderSupportedClasses.DbConnection) > 0)
{
	conn = factory.CreateConnection();
	conn.ConnectionString = s.ConnectionString;
}

DbCommand selectCommand = null;
if ((factory.SupportedClasses & DbProviderSupportedClasses.DbCommand) > 0)
{
	selectCommand = factory.CreateCommand();
	selectCommand.CommandText = "SELECT * from dbo.Customers";
	selectCommand.Connection = conn;
}

conn.Open();

DbDataReader dataReader = selectCommand.ExecuteReader();

while (dataReader.Read())
	Console.WriteLine(sqlDataReader.GetString(0));

conn.Close();

ConfigurationSettingsクラスでは、次のようなapp.config ファイルからコネクションストリング、プロバイダーネームを取得します。これは、ADO.NET 2.0正式版で変更される可能性あります。

疑問1:エラーチェックがいやらしい。単に例外処理にした場合問題ないのか?

疑問2:パラメータなどのプロバイダ依存性をどうのように処理するのか?

app.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<connectionStrings>
	<add name="ConnectionStrings" 
	connectionString="Server=localhost;Integrated Security=True;Database=Northwind" 
	providerName="System.Data.SqlClient" />
</connectionStrings>
</configuration>

でも、データプロバイダーは不変で、たとえばMS SQLサーバーしか使わないような場合であれば、あえてFactory パターンを使用する必要は無いと思います。

Factory パターンを使用しない場合
...
using System.Configuration;
using System.Data.Common;
using System.Data.SqlClient;
...
ConnectionStringSettings s = ConfigurationSettings.ConnectionStrings["ConnectionStrings"];
SqlConnection conn = new SqlConnection(s.ConnectionString);
SqlCommand myCommand = new SqlCommand("SELECT * from dbo.Customers", conn);

conn.Open();

SqlDataReader sqlDataReader = myCommand.ExecuteReader();

while (sqlDataReader.Read())
	Console.WriteLine(sqlDataReader.GetString(0));
conn.Close();

5.データセットを使用する場合の注意点

データベースをアクセスする際に、データコマンドでSQL を直接アクセスすべきか、DataSetによる非接続型にすべきか、データコマンドにするべきなのか、悩みませんか?

参考文献(2)から、それぞれ向いている用途をまとめると次のようになります。

方法 向いている用途
データ コマンド
  • DDL コマンドなどの非クエリ操作
  • ストアド プロシージャ
  • スカラ値を取得する場合
  • 柔軟な実行制御
DataSet
  • 複数の個別のテーブルまたは異なるデータ ソースのテーブルを使用する場合
  • 同じレコードを繰り返し使用する場合
  • 分散アプリケーションの層間でのデータの移動
  • 簡単なプログラミング

ADO.NET 2.0 では、データセットにバイナリーフォーマットが導入されたことにより、データセットを使用する場合の敷居が下がっています。そうであったとしてもデータセットを使用する場合の注意点 は変わらないので、次にまとめます。

5.1 データのやり取りを最小限に抑える

どんな場合もそうですが、クライアントサーバ間でデータの転送量を最小限に抑えることにより、通信のオーバヘッドを下げることができます。特にデータセットの場合、簡単に組めてしまう分、気がつかないうちに大量のデータを送受信していたということになりかねないので、どのぐらいのデータ量なのか把握しておく必要があるでしょう。

また、一度に100項目を表示するのではなく、10項目づつ10ページに分けて、それぞれ別のデータセットで扱うようにするなど、状況に応じて表示するレコードの数を減らすことも考える必要があります。

特に、ASP.NETの場合は、Web フォーム ページは、ラウンド トリップごとに初期化され、処理され、破棄されます。単にページ上にデータを表示するだけの場合は、データセットがすぐに破棄されるため、データセットのほうが処理が重くなります。

5.2 データセットを保存するか、毎回再作成するか

次に、データセットを保存して使いまわすのか、毎回再作成するのかを検討します。

方法 適用 説明
毎回作成 変更される可能性の高いデータ たとえば、在庫データなどの変更される可能性の高いデータ は、ラウンド トリップごとにデータセットを再作成した方がよい場合があります。

ページを処理するたびに、データセットのインスタンスを作成してデータを読み込みます。ページ処理が完了してページがブラウザに送信されると、データセットは破棄されます。

保存する 変更される可能性が低く、複数回参照されるデータ データセットを一度だけ作成してデータを読み込みます。そして、以降の各ラウンド トリップで取得できるようにデータセットを保存します。

5.3 データセットをサーバーとクライアントのどちらに保存するか

次に、データセットをサーバーとクライアントのどちらに保存するかを検討します。保存方法には次のような方法が考えられます。

保存場所 方法 説明
サーバー セッション セッションにデータセットを保存する。
キャッシュ キャッシュを使用して保存する。
クライアント ビューステート ビューステートに保存する。
隠しフィールド 隠しフィールドに保存する。

 

セッションにデータセットを保存する場合のパターン
private void Page_Load(object sender, System.EventArgs e)
{
    if (Page.IsPostBack) 
    {
        dsCustomers1 = (dsCustomers) Session["myDsCustomers"];
    }
    else
    {
        if (Session["myDsCustomers"] == null) 
        {
            oleDbDataAdapter1.Fill(dsCustomers1);
            Session["myDsCustomers"] = dsCustomers1;
        }
    }
}

5.4 RemotingFormat にバイナリーフォーマット

 4.2に書いたように、ADO.NET V2.0で導入されるDataSetのバイナリーフォーマットを試してみましょう。