C#でDataReaderを戻り値とするメソッドの実装について相談
●概要
以下のようなプログラムを作成しています。
・MySQLからレコードを取得(MySqlConnector/NET 8.16を使用)
・取得したレコードを1行ずつCSVに出力
・DBアクセス部分とCSV出力部分はクラスで分けるなどして分離させた実装とする。
・DBアクセスメソッド内でCSV出力メソッドを呼び出すのはNG
以下①②③の背景があり現在は③の実装をしています。
もっと良い手法は無いのなという思いがあり、質問させていただきました。
独学のため先人のベストプラクティスを見る機会などがあまりなく、何かご教示いただけると幸いです。
●実装背景
①
私は最初、DBアクセスとして下記①のようなDataTableを戻り値とするメソッドを実装をしました。
②
しかし、今回の目的ではDataTableで全てのレコードをメモリに展開する必要は無いと思い、下記②のようなMySqlDataReaderを戻り値とするメソッドに変更しました。
ところが②のコードで戻り値として取得したMySqlDataReaderからデータを読み出そうとすると実行時エラーになりました。
原因としては、データを読み出す時点でMySqlDataReaderを生成したMySqlConnectionとMySqlCommandが既にDisposeされているからでした。
③
現在、下記③の実装になりました。
クラス変数としてconnectionとcommandを持つ形になったのですが、この実装でいくつか残念に思っている点があります。
1.using句での自動Disposeではなく、呼び出し側で明示的にDisposeメソッドを呼ばないといけない点
2.DataAccessクラスに他のデータ取得メソッドが追加された場合、SqlDataConnectionやSqlDataCommandの競合が起きる可能性のある点。それを避けるためにはDataAccessクラスを複数インスタンス化しないといけない点。
他のDBMSでもADO.NETデータプロバイダであれば同じような実装だと認識しているので、他のDBMSでの知見でも構わないです。
よろしくお願いします。
①
class DataAccess
{
public DataTable GetXyzData()
{
MySqlConnectionStringBuilder builder = new MySqlConnectionStringBuilder();
builder.Server = "aaa";
builder.Database = "bbb";
builder.UserID = "ccc";
builder.Password = "ddd";
using (MySqlConnection conn = new MySqlConnection(builder.ConnectionString))
{
StringBuilder sql = new StringBuilder();
sql.AppendLine("SELECT");
sql.AppendLine(" COL1");
sql.AppendLine(" , COL2");
sql.AppendLine(" , COL3");
sql.AppendLine("FROM");
sql.AppendLine(" TABLE_XYZ");
using (MySqlCommand cmd = new MySqlCommand(sql.ToString(), conn))
{
MySqlDataAdapter adp = new MySqlDataAdapter(cmd);
DataTable tbl = new DataTable();
adp.Fill(tbl);
return tbl;
}
}
}
}
②
class DataAccess
{
public MySqlDataReader GetXyzData()
{
MySqlConnectionStringBuilder builder = new MySqlConnectionStringBuilder();
builder.Server = "aaa";
builder.Database = "bbb";
builder.UserID = "ccc";
builder.Password = "ddd";
using (MySqlConnection conn = new MySqlConnection(builder.ConnectionString))
{
StringBuilder sql = new StringBuilder();
sql.AppendLine("SELECT");
sql.AppendLine(" COL1");
sql.AppendLine(" , COL2");
sql.AppendLine(" , COL3");
sql.AppendLine("FROM");
sql.AppendLine(" TABLE_XYZ");
using (MySqlCommand cmd = new MySqlCommand(sql.ToString(), conn))
{
MySqlDataReader dataReader = cmd.ExecuteReader();
return dataReader;
}
}
}
}
③
class DataAccess
{
private MySqlConnection conn;
private MySqlCommand cmd;
public void GetConnection()
{
MySqlConnectionStringBuilder builder = new MySqlConnectionStringBuilder();
builder.Server = "aaa";
builder.Database = "bbb";
builder.UserID = "ccc";
builder.Password = "ddd";
this.conn = new MySqlConnection(builder.ConnectionString);
}
public void DisposeConnection()
{
this.conn.Dispose();
}
private void GetCommand(string sql)
{
this.cmd = new MySqlCommand(sql, this.conn);
}
public void DisposeCommand()
{
this.cmd.Dispose();
}
public MySqlDataReader GetXyzData()
{
StringBuilder sql = new StringBuilder();
sql.AppendLine("SELECT");
sql.AppendLine(" COL1");
sql.AppendLine(" , COL2");
sql.AppendLine(" , COL3");
sql.AppendLine("FROM");
sql.AppendLine(" TABLE_XYZ");
GetCommand(sql.ToString());
MySqlDataReader dataReader = this.cmd.ExecuteReader();
return dataReader;
}
}