Où dois-je créer mes instances dbcommand?
-
12-09-2019 - |
Question
J'ai apparemment deux choix:
- Faites ma classe
IDisposable
mettre en œuvre. Créer mes instancesDbCommand
comme des champs deprivate readonly
, et dans le constructeur, ajouter les paramètres qu'ils utilisent. Chaque fois que je veux écrire à la base de données, se lier à ces paramètres (réutilisant les mêmes instances de commande), définissez les propriétés deConnection
etTransaction
, puis appelezExecuteNonQuery
. Dans la méthodeDispose
, appelezDispose
sur chacun de ces champs. - Chaque fois que je veux écrire à la base de données, écrivez
using(var cmd = new DbCommand("...", connection, transaction))
autour de l'utilisation de la commande, et ajouter des paramètres et se lient à eux chaque fois ainsi, avant d'appelerExecuteNonQuery
. Je suppose que je ne suis pas besoin d'une nouvelle commande pour chaque requête, juste une nouvelle commande pour chaque fois que j'ouvre la base de données (à droite?).
Ces deux semblent un peu inélégante et peut-être incorrect.
Pour # 1, il est gênant pour mes utilisateurs que je cette classe est maintenant IDisposable
juste parce que je l'ai utilisé quelques DbCommand
s (qui devrait être un détail de mise en œuvre qu'ils ne se soucient pas). Je suis aussi un peu suspecte que le maintien d'une instance de DbCommand
autour peut verrouiller la base de données par inadvertance ou quelque chose?
Pour # 2, on dirait que je fais beaucoup de travail (en termes d'objets .NET) chaque fois que je veux écrire à la base de données, en particulier avec le paramètre ajoutée. Il semble que je crée le même objet à chaque fois, ce qui se sent comme une mauvaise pratique.
Pour référence, voici mon code actuel, en utilisant # 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
}
La solution
Domenic, La disposition d'un SQLiteCommand signale simplement son lecteur actif pour disposer son lecteur et établit les paramètres de connexion et de référence à null.
Vous n'êtes pas à risque de fuite de ressource en mettant en cache une commande aussi longtemps que vous éliminer de manière appropriée du lecteur exécuté et proche / Éliminez de la connexion.
Ainsi, la réutilisation d'une commande en cache et en attribuant simplement des valeurs aux paramètres est de loin la mise en œuvre la plus efficace.
.Prepare () est un noop
en SQLiteCommand donc il n'y a aucun avantage à être pris sur place.
Autres conseils
Il n'y a pas simple « droit chemin » pour gérer le cycle de vie de l'objet de base de données. Il est tout dépend de vos besoins d'application.
Ma préférence personnelle est de garder le code aussi simple que possible. J'ai tendance à recréer des objets de commande et paramètres au besoin. Cela permet à mes fonctions être aussi autonome que possible. Il a grandement simplifié toute l'affacturage re que j'ai dû le faire.
Si vous êtes préoccupé par l'impact sur les performances des objets recréant vous devez charger un profileur et voir où votre cou de bouteille sont. Dans les applications que j'ai construit, j'ai trouvé le temps passé à la création d'objets DbCommand est tellement sans conséquence par rapport au temps passé à exécuter la requête qu'il ne tient pas vraiment à mes performances des applications.
Je l'ai trouvé avec SQLServer si nous réutilisons la commande avec la même connexion, son beaucoup plus rapide. Je prévois de tester les connexions et les transactions différentes, mais ils semblent être plus rapide.