Pergunta

I aparentemente tem duas opções:

  1. Faça minha classe implementar IDisposable. Criar meus casos DbCommand como campos private readonly, e no construtor, adicione os parâmetros que eles usam. Sempre que eu quero escrever para o banco de dados, se ligam a estes parâmetros (reutilizando as mesmas instâncias de comando), defina as propriedades Connection e Transaction, então ExecuteNonQuery chamada. No método Dispose, Dispose chamada em cada um desses campos.
  2. Cada vez que eu quiser escrever para o banco de dados, gravação using(var cmd = new DbCommand("...", connection, transaction)) ao redor do uso do comando, e adicionar parâmetros e se ligam a eles cada vez, bem como, antes de chamar ExecuteNonQuery. Eu suponho que eu não preciso de um novo comando para cada consulta, apenas um novo comando para cada vez que eu abrir o banco de dados (certo?).

Ambos parecem um tanto deselegante e possivelmente incorreto.

Por nº 1, é irritante para meus usuários que esta classe é agora IDisposable só porque eu usei algumas DbCommands (que deve ser um detalhe de implementação que eles não se preocupam com). Eu também sou um pouco suspeito que manter uma instância DbCommand redor pode inadvertidamente bloquear o banco de dados ou algo assim?

Para # 2, parece que eu estou fazendo um monte de trabalho (em termos de objetos .NET) cada vez que eu quero escrever para o banco de dados, especialmente com o parâmetro de agregação. Parece que eu criar o mesmo objeto de cada vez, o que só se sente como uma prática ruim.

Para referência, aqui está o meu código atual, 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
}
Foi útil?

Solução

Domenic, Descartando uma SQLiteCommand simplesmente sinaliza seu leitor ativo para eliminá-lo do leitor e define os parâmetros e ligação referência a null.

Você não está em risco de fuga de recursos, armazenando um comando enquanto você descartar corretamente o leitor executado e fechar / dispose da conexão.

Assim, a reutilização de um comando em cache e simplesmente atribuir valores aos parâmetros é de longe a mais eficiente implementação.

.Prepare () é uma noop em SQLiteCommand portanto, não há benefício a ser tido lá.

Outras dicas

Não há nenhum single "caminho certo" para lidar com o seu ciclo de banco de dados objeto vida. É tudo depende de suas necessidades de aplicação.

A minha preferência pessoal é manter o código o mais simples possível. I tendem a recriar objetos comando e parâmetro, conforme necessário. Isso permite que as minhas funções ser tão auto-suficientes quanto possível. Tem muito simplificada qualquer factoring re eu tinha que fazer.

Se você está preocupado com o hit de objetos recriando desempenho você deve carregar um profiler e ver onde seus gargalos são. Em aplicações eu construí, eu encontrei o tempo gasto na criação DbCommand objetos é tão inconsequente em comparação com o tempo gasto executar a consulta que ele realmente não fator no meu desempenho apps.

Eu encontrei com sqlserver se reutilizar o comando com o mesmo contexto, a sua muito mais rápido. Eu pretendo teste para diferentes conexões e transações, mas eles parecem ser mais rápido.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top