DB接続オブジェクトをメソッドに渡す
-
05-07-2019 - |
質問
データベース接続オブジェクトを他のモジュールに渡す(他のモジュールに)か、メソッド(他のモジュール内)に設定を任せるのがお勧めかと思いました。メソッドを使用する前に接続の状態を確認する必要がないようにメソッドを設定し、呼び出し元が接続をセットアップするために必要な呼び出しメソッドに必要なデータを渡すようにします。
解決
個人的には、厳密にスコープされた接続を使用します。それらを遅く開いて使用し、閉じます(「using」ブロック内で、すべてローカルメソッド内で)。接続プーリングは、ほとんどの場合、接続の再利用に対処するため、このアプローチに実際のオーバーヘッドはありません。
接続を渡す主な利点は、トランザクションを渡すことができるようにすることです使用。ただし、 TransactionScope
は、メソッド間でトランザクションを共有する簡単な方法です。
クラスは実装固有であるため、各クラスを作成して独自のネイティブトランザクションを開きます。それ以外の場合は、ado.netファクトリメソッドを使用して、構成ファイル(プロバイダー名)から適切なタイプを作成できます。
他のヒント
個人的には、現在開いている接続とトランザクションのスタックをスレッドローカルストレージ SetDataおよびGetDataを使用します。データベースへの接続を管理するクラスを定義し、破棄パターンを使用できるようにします。これにより、接続とトランザクションをやり取りする必要がなくなります。これは、コードを混乱させ複雑にするものだと思います。
データが必要になるたびに接続を開く方法に任せるに対してを強くお勧めします。アプリケーション全体でトランザクションを管理するのが難しく、開いている接続と閉じている接続が多すぎるという非常に悪い状況につながります(接続プーリングについて知っていますが、プールから接続を検索するのはそれよりもさらに高価です)オブジェクトを再利用します)
だから私はこれらの行に沿って何かを持つことになります(完全にテストされていません):
class DatabaseContext : IDisposable {
List<DatabaseContext> currentContexts;
SqlConnection connection;
bool first = false;
DatabaseContext (List<DatabaseContext> contexts)
{
currentContexts = contexts;
if (contexts.Count == 0)
{
connection = new SqlConnection(); // fill in info
connection.Open();
first = true;
}
else
{
connection = contexts.First().connection;
}
contexts.Add(this);
}
static List<DatabaseContext> DatabaseContexts {
get
{
var contexts = CallContext.GetData("contexts") as List<DatabaseContext>;
if (contexts == null)
{
contexts = new List<DatabaseContext>();
CallContext.SetData("contexts", contexts);
}
return contexts;
}
}
public static DatabaseContext GetOpenConnection()
{
return new DatabaseContext(DatabaseContexts);
}
public SqlCommand CreateCommand(string sql)
{
var cmd = new SqlCommand(sql);
cmd.Connection = connection;
return cmd;
}
public void Dispose()
{
if (first)
{
connection.Close();
}
currentContexts.Remove(this);
}
}
void Test()
{
// connection is opened here
using (var ctx = DatabaseContext.GetOpenConnection())
{
using (var cmd = ctx.CreateCommand("select 1"))
{
cmd.ExecuteNonQuery();
}
Test2();
}
// closed after dispose
}
void Test2()
{
// reuse existing connection
using (var ctx = DatabaseContext.GetOpenConnection())
{
using (var cmd = ctx.CreateCommand("select 2"))
{
cmd.ExecuteNonQuery();
}
}
// leaves connection open
}
自動化されたテスト目的の場合、通常は簡単に渡すことができます。これは依存性注入と呼ばれます。
テストを記述する必要がある場合、模擬データベース接続オブジェクトを作成し、実際のオブジェクトの代わりに渡すことができます。そうすれば、自動テストは毎回データを再投入する必要がある実際のデータベースに依存しなくなります。
個人的にデータアクセスを可能な限り集中化するように努力していますが、不可能な場合は、他のクラスで常に新しい接続を開きます。実際の接続オブジェクト。
この問題についてもう少し詳しく説明します。 db接続を管理するクラスと、インターフェイスを実装する2つのクラスがあります。クラスの1つはSQL用で、もう1つはOLAP用です。マネージャーは、使用する接続を認識しているため、正確な接続をタイプに渡すか、タイプが独自の接続を作成できます。
問題なく接続オブジェクトを渡すことができます(たとえば、Microsoft Enterprise Libraryは接続での静的メソッド呼び出しを許可します)。または、設計に応じて外部で管理できます。直接的な技術的なトレードオフはありません。
ソリューションを他のデータベースに移植する場合、特定の接続を渡さないように移植性に注意してください(つまり、他のデータベースで作業する予定のSqlConnectionを渡さないでください)
接続の設定は潜在的に高価であり、潜在的に往復を追加します。そのため、潜在的には、接続オブジェクトを渡す方が良いでしょう。
Microsoft ADOアプリを使用している場合、おそらく接続プールを使用している可能性があります。...
接続オブジェクトとその状態(オープン、クローズ)を区別することをお勧めします。
web.configから接続文字列を読み取る単一のメソッド(またはプロパティ)を持つことができます。毎回同じバージョンの接続文字列を使用すると、接続プーリングのメリットが得られます。
接続を開く必要がある場合、そのメソッドを呼び出します。最後の瞬間に、すべてのSqlCommandプロパティを設定した後、接続を開き、使用してから閉じます。 C#では、usingステートメントを使用して、接続が閉じられていることを確認できます。そうでない場合は、finallyブロックで接続を閉じてください。
web.configを使用します
<configuration>
<connectionStrings>
<add name="conn1" providerName="System.Data.SqlClient" connectionString="string here" />
<add name="conn2" providerName="System.Data.SqlClient" connectionString="string here" />
</connectionStrings>
</configuration>
その後、アプリケーションのどこからでも参照できます