¿Dónde debo crear mis casos DbCommand?
-
12-09-2019 - |
Pregunta
Me aparentemente tiene dos opciones:
- Haz de mi clase implemente
IDisposable
. Crear mis casosDbCommand
como camposprivate readonly
, y en el constructor, agregar los parámetros que utilizan. Siempre que quiero escribir en la base de datos, se unen a estos parámetros (reutilización de las mismas instancias de comando), establecer las propiedadesConnection
yTransaction
, entonces llamanExecuteNonQuery
. En el métodoDispose
, llameDispose
en cada uno de estos campos. - Cada vez que quiero escribir en la base de datos, escribir
using(var cmd = new DbCommand("...", connection, transaction))
alrededor del uso del comando, y añadir parámetros y se unen a ellos cada vez, así, antes de llamar aExecuteNonQuery
. Asumo que no necesito un nuevo comando para cada consulta, sólo un nuevo comando para cada vez que abra la base de datos (¿verdad?).
Ambos parecen poco elegante y posiblemente incorrecta.
Para # 1, es molesto para mis usuarios que esta clase es ahora IDisposable
sólo porque he utilizado unos DbCommand
s (que debe ser un detalle de implementación que no se preocupan). También estoy un poco sospechoso que el mantenimiento de una instancia DbCommand
alrededor podría bloquear inadvertidamente la base de datos o algo?
Para # 2, se siente como que estoy haciendo un montón de trabajo (en términos de objetos .NET) cada vez que quiero escribir en la base de datos, sobre todo con el parámetro añadido. Parece que creo el mismo objeto cada vez, que sólo se siente como una mala práctica.
Para referencia, aquí es mi código actual, usando # 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
}
Solución
Domenic, Disponer un SQLiteCommand simplemente señala su lector activo de disponer que es lector y establece los parámetros y referencia de conexión a null.
Usted no está en riesgo de fuga de recursos cambiando el comando todo el tiempo que disponer adecuadamente del lector ejecutado y cerrado / disponer de la conexión.
Por lo tanto, la reutilización de un comando en caché y simplemente asignar valores a los parámetros es, con mucho, la implementación más eficiente.
.Prepare () es una noop
en SQLiteCommand lo que no hay beneficio que se tenía allí.
Otros consejos
No hay una sola manera "correcta" para manejar su ciclo de objeto de base de la vida. Es todo depende de sus necesidades de aplicación.
Mi preferencia personal es mantener el código tan simple como sea posible. Tiendo recrear objetos de comando y los parámetros según sea necesario. De este modo, mis funciones sean tan independientes como sea posible. Se ha simplificado enormemente cualquier factorización re que he tenido que hacer.
Si usted está preocupado por el impacto en el rendimiento de los objetos que recrean usted debe cargar un generador de perfiles y ver dónde están sus cuellos de botella son. En las aplicaciones que he construido, he encontrado el tiempo dedicado a la creación de objetos DbCommand es tan insignificante en comparación con el tiempo de ejecutar la consulta que en realidad no factor en el rendimiento de mi aplicaciones.
he encontrado con sqlserver si reutilizamos el comando con misma conexión, es mucho más rápido. Mi plan para poner a prueba para diferentes conexiones y transacciones pero parecen ser más rápido.