DbCommand インスタンスはどこに作成すればよいですか?
-
12-09-2019 - |
質問
どうやら 2 つの選択肢があるようです:
- クラスを実装する
IDisposable
. 。私のものを作成してくださいDbCommand
としてのインスタンスprivate readonly
フィールドを追加し、コンストラクターで使用するパラメーターを追加します。データベースに書き込みたいときは常に、これらのパラメータにバインドし(同じコマンド インスタンスを再利用)、Connection
そしてTransaction
プロパティを設定してから呼び出しますExecuteNonQuery
. 。の中にDispose
メソッド、呼び出しDispose
これらの各フィールドについて。 - データベースに書き込むたびに、次のように書きます。
using(var cmd = new DbCommand("...", connection, transaction))
コマンドの使用法について説明し、呼び出す前に毎回パラメータを追加してバインドします。ExecuteNonQuery
. 。クエリごとに新しいコマンドは必要なく、データベースを開くたびに新しいコマンドが必要なだけだと思います (そうですか?)。
これらはどちらもやや洗練されていないように思え、おそらく間違っているように思えます。
#1 については、このクラスが現在使用されていることがユーザーにとって迷惑です。 IDisposable
いくつか使ってみたので DbCommand
s (これは実装の詳細であり、彼らは気にしないはずです)。私も、 DbCommand
周囲のインスタンスが誤ってデータベースか何かをロックしてしまう可能性はありますか?
#2 については、データベースに書き込むたびに、特にパラメーターの追加で (.NET オブジェクトに関して) 多くの作業を行っているように感じます。毎回同じオブジェクトを作成しているようですが、これは悪い習慣のように思えます。
参考までに、#1 を使用した現在のコードを次に示します。
using System;
using System.Net;
using System.Data.SQLite;
public class Class1 : IDisposable
{
private readonly SQLiteCommand updateCookie = new SQLiteCommand("UPDATE moz_cookies SET value = @value, expiry = @expiry, isSecure = @isSecure, isHttpOnly = @isHttpOnly WHERE name = @name AND host = @host AND path = @path");
public Class1()
{
this.updateCookie.Parameters.AddRange(new[]
{
new SQLiteParameter("@name"),
new SQLiteParameter("@value"),
new SQLiteParameter("@host"),
new SQLiteParameter("@path"),
new SQLiteParameter("@expiry"),
new SQLiteParameter("@isSecure"),
new SQLiteParameter("@isHttpOnly")
});
}
private static void BindDbCommandToMozillaCookie(DbCommand command, Cookie cookie)
{
long expiresSeconds = (long)cookie.Expires.TotalSeconds;
command.Parameters["@name"].Value = cookie.Name;
command.Parameters["@value"].Value = cookie.Value;
command.Parameters["@host"].Value = cookie.Domain;
command.Parameters["@path"].Value = cookie.Path;
command.Parameters["@expiry"].Value = expiresSeconds;
command.Parameters["@isSecure"].Value = cookie.Secure;
command.Parameters["@isHttpOnly"].Value = cookie.HttpOnly;
}
public void WriteCurrentCookiesToMozillaBasedBrowserSqlite(string databaseFilename)
{
using (SQLiteConnection connection = new SQLiteConnection("Data Source=" + databaseFilename))
{
connection.Open();
using (SQLiteTransaction transaction = connection.BeginTransaction())
{
this.updateCookie.Connection = connection;
this.updateCookie.Transaction = transaction;
foreach (Cookie cookie in SomeOtherClass.GetCookieArray())
{
Class1.BindDbCommandToMozillaCookie(this.updateCookie, cookie);
this.updateCookie.ExecuteNonQuery();
}
transaction.Commit();
}
}
}
#region IDisposable implementation
protected virtual void Dispose(bool disposing)
{
if (!this.disposed && disposing)
{
this.updateCookie.Dispose();
}
this.disposed = true;
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
~Class1()
{
this.Dispose(false);
}
private bool disposed;
#endregion
}
解決
Domenic、 SQLiteCommandを配置することは、単にそれは読者のヌルにパラメータ及び接続リファレンスを設定し配置するその活性リーダに信号を送る。
あなたは限り、あなたは適切な接続の実行リーダーと近い/処分の処分などのコマンドをキャッシュすることでリソースリークのリスクがありません。
だから、キャッシュされたコマンドを再利用し、単にパラメータに値を代入することは、これまでで最も効率的な実装である。
.Prepare()は存在していたすべき利点がないSQLiteCommandでnoop
である。
他のヒント
あなたのデータベースオブジェクトのライフサイクルを処理するための単一の「正しい方法」はありません。これは、すべてのアプリケーションのニーズに依存します。
私の個人的な好みは、できるだけ簡単なコードを維持することです。私は、必要に応じてコマンドとパラメータオブジェクトを再作成する傾向があります。これは私の関数はできるだけ自己完結となります。それは非常に私がしなければならなかった任意の再ファクタリングを簡素化しています。
あなたがオブジェクトを再作成のパフォーマンスヒットを懸念している場合は、プロファイラをロードする必要があり、あなたのボトルネックがどこにあるか見ます。私が構築したアプリケーションでは、私は時間がされたDbCommandオブジェクトを作成する費やし見つけた時に比べてそれほど重要ではないが、それは本当に私のアプリケーションのパフォーマンスへの要因でないことをクエリを実行にかかっています。
私たちは同じ接続を使用してコマンドを再利用する場合は、SQLServerので見つかったそのはるかに速くています。私は、異なる接続およびトランザクションをテストすることを計画したが、彼らは速いように見えます。