データベース接続オブジェクトを(他のモジュールに)渡すことをお勧めするか、(他のモジュールの)メソッドに設定を任せることが推奨されるかどうか疑問に思っていました。私は、メソッドを使用する前に接続の状態を確認する必要がないようにメソッドを設定させ、呼び出し元が必要なデータを呼び出し元のメソッドに渡して接続を設定することに傾いています。
9 に答える
個人的には、厳密に範囲が限定された接続を使用するのが好きです。それらを後で開き、使用し、閉じます(すべてローカルメソッド内の「使用中」ブロック内)。ほとんどの場合、接続プーリングは接続の再利用に対処するため、このアプローチでは実際のオーバーヘッドはありません。
以前は、接続を渡すことの主な利点は、トランザクションを渡すことができることでした。ただし、TransactionScope
メソッド間でトランザクションを共有するより簡単な方法です。
クラスは実装固有であるため、それぞれ独自のネイティブ トランザクションを開くように記述します。それ以外の場合は、ado.net ファクトリ メソッドを使用して、構成ファイル (プロバイダー名) から適切な型を作成できます。
個人的には、 SetData と GetData を使用して、現在開いている接続とトランザクションのスタックをThread Local Storageの上に保存するのが好きです。データベースへの接続を管理するクラスを定義し、dispose パターンを使用できるようにします。これにより、接続とトランザクションを渡す必要がなくなります。これは、コードが乱雑で複雑になると思います。
データが必要になるたびに接続を開くメソッドに任せないことを強くお勧めします。アプリケーション全体でトランザクションを管理するのが難しく、あまりにも多くの接続が開かれたり閉じられたりするという、非常に悪い状況につながります (私は接続プーリングについて知っていますが、プールから接続を検索する方が実際よりもコストがかかります)オブジェクトを再利用するため)
だから私はこれらの行に沿って何かを持っています(完全にテストされていません):
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
}
自動テストの目的では、通常はそれを渡す方が簡単です。これは依存性注入と呼ばれます。
テストを作成する必要がある場合は、モック データベース接続オブジェクトを作成し、実際のオブジェクトの代わりにそれを渡すことができます。そうすれば、自動化されたテストは、毎回データを再入力する必要がある実際のデータベースに依存しなくなります。
私は個人的にデータアクセスを可能な限り一元化するように取り組んでいますが、実際の接続を渡すときに邪魔になる可能性のあるものが多すぎることがわかったので、それが不可能な場合は常に他のクラスで新しい接続を開きます物体。
接続の設定にはコストがかかる可能性があり、往復が追加される可能性があります。したがって、接続オブジェクトを渡すほうがよい設計になる可能性があります。
Microsoft ADO アプリの場合は、おそらく接続プールを使用している可能性があるためです....
ここで、この問題についてもう少し詳しく説明します。データベース接続を管理するクラスがあり、インターフェイスを実装する 2 つのクラスがあります。クラスの 1 つは SQL 用で、もう 1 つは OLAP 用です。マネージャーは、使用する接続を認識しているため、正確な接続をタイプに渡すことも、タイプが独自の接続を作成することもできます。
接続オブジェクトを問題なく渡すことができます (たとえば、Microsoft Enterprise Library では静的メソッド呼び出しを接続で渡すことができます)。または、設計次第で外部から管理することもできます。直接的な技術的なトレードオフはありません。
ソリューションを他のデータベースに移植する場合は、移植性のために特定の接続を渡さないように注意してください (つまり、他のデータベースで作業する予定がある場合は SqlConnection を渡さないでください)。
接続オブジェクトとその状態 (オープン、クローズ) を区別することをお勧めします。
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>
その後、アプリケーションのどこからでも参照できます