Где я должен создать свои экземпляры DbCommand? - PullRequest
1 голос
/ 09 августа 2009

У меня, похоже, есть два варианта:

  1. Заставить мой класс реализовать IDisposable. Создайте мои DbCommand экземпляры как private readonly поля и в конструкторе добавьте параметры, которые они используют. Всякий раз, когда я хочу записать в базу данных, привязать к этим параметрам (повторно используя те же экземпляры команд), установить свойства Connection и Transaction, затем вызвать ExecuteNonQuery. В методе Dispose вызовите Dispose для каждого из этих полей.
  2. Каждый раз, когда я хочу записать в базу данных, пишите 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
}

Ответы [ 3 ]

2 голосов
/ 25 апреля 2010

Доменик, Удаление SQLiteCommand просто сигнализирует активному считывающему устройству об утилизации этого считывающего устройства и устанавливает для параметров и ссылки на соединение значение null.

Вы не подвержены риску утечки ресурса, кэшируя команду, если вы правильно утилизируете выполненный считыватель и закроете / утилизируете соединение.

Таким образом, повторное использование кэшированной команды и простое присвоение значений параметрам является безусловно наиболее эффективной реализацией.

.Prepare () - это noop в SQLiteCommand, поэтому здесь нет никакой выгоды.

2 голосов
/ 12 августа 2009

Не существует единственного «правильного способа» обработки жизненного цикла объекта базы данных. Все зависит от потребностей вашего приложения.

Мое личное предпочтение - сохранять код как можно более простым. Я склонен воссоздавать объекты Command и Parameter по мере необходимости. Это позволяет моим функциям быть максимально автономными. Это значительно упростило любой рефакторинг, который мне приходилось делать.

Если вас беспокоит снижение производительности при воссоздании объектов, вам следует загрузить профилировщик и посмотреть, где находятся ваши «горлышки бутылок». В приложениях, которые я создал, я обнаружил, что время, затрачиваемое на создание объектов DbCommand, настолько незначительно по сравнению со временем, затрачиваемым на выполнение запроса, что оно не влияет на производительность моих приложений.

0 голосов
/ 02 ноября 2009

Я нашел с sqlserver, если мы повторно используем команду с тем же соединением, это намного быстрее. Я планирую проверить различные соединения и транзакции, но они выглядят быстрее.

...