継承の質問-AccessデータベースファイルとSQL Expressからデータを取得する
-
05-07-2019 - |
質問
最初はAccessデータベースに接続するアプリケーションを開発しており、近い将来MS SQLまたはSQL Expressに切り替える予定です。データテーブル構造は両方のタイプのデータベースで同じであり、コードの重複を避け、コードを最小化する方法を見つけようとしています。
たとえば、Accessデータベースからデータを取得するために次の関数を作成しました:
public static DataTable GetActiveCalls()
{
string select = "SELECT call_id, call_time, msisdn, status FROM call WHERE status = 0 OR status = 1 ORDER by call_id ASC";
OleDbCommand cmd = new OleDbCommand(select, conn);
DataTable dt = new DataTable("Active Calls");
OleDbDataAdapter DA = new OleDbDataAdapter(cmd);
try
{
conn.Open();
DA.Fill(dt);
}
catch (Exception ex)
{
string sDummy = ex.ToString();
}
finally
{
conn.Close();
}
return dt;
}
次のコードはSQL Expressデータベース用です:
public static DataTable GetActiveCalls()
{
string select = "SELECT call_id, call_time, msisdn, status FROM call WHERE status = 0 OR status = 1 ORDER by call_id ASC";
SqlCommand cmd = new SqlCommand(select, conn);
DataTable dt = new DataTable("Active Calls");
SqlDataAdapter DA = new SqlDataAdapter(cmd);
try
{
conn.Open();
DA.Fill(dt);
}
catch (Exception ex)
{
string sDummy = ex.ToString();
}
finally
{
conn.Close();
}
return dt;
}
これら2つの方法はほとんど同じです。唯一の違いは、SqlCommand / OleDbCommandとSqlDataAdapter / OleDbDataAdapterです。 例えば引数を取るメソッドもいくつかあります:
public static void AddMessage(string callID, string content)
{
string select =
"INSERT INTO message(key, direction, content, read, write_time) VALUES (@callId, 0, @content, 0, @insertTime)";
OleDbCommand cmd = new OleDbCommand(select, conn);
cmd.Parameters.AddWithValue("callId", callID.ToString());
cmd.Parameters.AddWithValue("content", content);
cmd.Parameters.AddWithValue("insertTime", DateTime.Now.ToString());
try
{
conn.Open();
cmd.ExecuteScalar();
}
catch (Exception ex)
{
string sDummy = ex.ToString();
}
finally
{
conn.Close();
}
}
この場合、SQLクエリ文字列は両方のデータベースで同じですが、cmdのタイプ(SqlCommand / OleDbCommand)には違いがあります。
コードの重複を回避し、与えられた問題を最適化する方法について提案できる人がいれば幸いです。
解決
データベースに依存しないインターフェイスIDbDataAdapterおよびIDbCommandを使用し、ファクトリを使用して具体的なインスタンスを作成できます。 こちらは例です。
ただし、アプリケーションが非常に単純でない場合は、 NHibernate などのORMソリューションを使用することをお勧めします。 AccessとSQL ServerのSQL言語のわずかな違いにより、データアクセスコードがより複雑になります。
他のヒント
エンタープライズライブラリデータアクセスビットをご覧ください。基礎となるデータベースプロバイダーの詳細は抽象化されています。例:
string sql = @"UPDATE tblContent
SET Title = @Title, Content = @Content, IsPublic = @IsPublic, ItemOrder = @ItemOrder
WHERE ContentItemID = @ContentItemID";
Database db = DatabaseFactory.CreateDatabase();
using(DbCommand cmd = db.GetSqlStringCommand(sql))
{
db.AddInParameter(cmd, "Title", DbType.String, title);
db.AddInParameter(cmd, "Content", DbType.String, content);
db.AddInParameter(cmd, "IsPublic", DbType.Boolean, isPublic);
db.AddInParameter(cmd, "ItemOrder", DbType.Int32, itemOrder);
db.AddInParameter(cmd, "ContentItemID", DbType.Int32 , contentItemID);
db.ExecuteNonQuery(cmd);
}
...または...
string sql = "SELECT MenuText FROM tblMenuItems WHERE MenuItemID = @MenuItemID";
Database db = DatabaseFactory.CreateDatabase();
using(DbCommand cmd = db.GetSqlStringCommand(sql))
{
db.AddInParameter(cmd, "MenuItemID", DbType.Int32, menuItemID);
using(IDataReader dr = db.ExecuteReader(cmd))
{
while(dr.Read())
{
return dr["MenuText"].ToString();
}
return null;
}
}
上記の例はいずれもAccessとMS SQLで動作し、JetとMS SQLの両方と互換性のあるSQLステートメントに固執していれば、問題はないはずです。
AccessからMS SQLに切り替えるときは、次のように接続文字列を変更するだけです。
<connectionStrings>
<add
name="ContentManager"
connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|Content.mdb;"
providerName="System.Data.OleDb"/>
</connectionStrings>
... to ...
<connectionStrings>
<add
name="ContentManager"
connectionString="Data Source=your.sql.server;Initial Catalog=content;Persist Security Info=True;User ID=cmuser;Password=password"
providerName="System.Data.SqlClient" />
</connectionStrings>
これを実現するには、ELディストリビューションで次のDLLを参照する必要があります。
Microsoft.Practices.EnterpriseLibrary.Common.dll
Microsoft.Practices.EnterpriseLibrary.Data.dll
一見の価値あり。
乾杯
ケブ