Почему соединение не закрывается в этом коде

Простым способом:

objs.sort(function(a,b) {
  return b.last_nom.toLowerCase() < a.last_nom.toLowerCase();
});

См., что '.toLowerCase()' необходимо для предотвращения ошибок при сравнении строк.

0
задан Dale Burrell 16 January 2019 в 06:11
поделиться

3 ответа

Соединение закрывается только при удалении экземпляра класса DataBase. Однако, хотя этот класс реализует одноразовый шаблон, он не реализует интерфейс IDisposable - поэтому вы не можете использовать его в выражении using.
Более того, вы должны полагаться на тех, кто использует этот класс, чтобы распоряжаться им.
Если они этого не сделают, соединение не будет закрыто, пока не будет вызван финализатор, и это полностью вне контроля разработчика. Он может даже не вызываться вообще - сборщику мусора может не потребоваться очистка памяти во время выполнения того приложения, которое использует этот код.

Вот почему правильный способ обработки соединений с базой данных - это локальная переменная внутри оператора using.

То, что вы хотите сделать, это создать соединение и открыть его как можно позже, и утилизировать его как можно скорее.
Правильный метод для обработки вызовов к базе данных выглядит следующим образом:

int ExecuteNonQuery(string sql)
{
    using(var con = new SqlConnection(connectionString))
    {
        using(var cmd = new SqlCommand(sql, con))
        {
            con.Open();
            return cmd.ExecueNonQuery();
        }
    }
}

Конечно, вы захотите добавить аргументы для хранения любых параметров, которые вам нужно передать в базу данных, и аргумент для хранения Тип команды, но это должно быть построено на основе этой структуры.

У меня есть проект на GitHub под названием ADONETHelper (которым я пренебрегал в течение последнего года или около того из-за нехватки свободного времени), который был написан для уменьшения повторения кода при использовании ADO .Net напрямую.
Я написал это несколько лет назад, поэтому, конечно, теперь я имею в виду улучшения, но, как я уже сказал, у меня нет свободного времени, чтобы поработать над этим - но общая идея по-прежнему актуальна и полезна. По сути, у него есть единственный метод Execute, который выглядит следующим образом:

public T Execute<T>(string sql, CommandType commandType, Func<IDbCommand, T> function, params IDbDataParameter[] parameters)
{
    using (var con = new TConnection())
    {
        con.ConnectionString = _ConnectionString;
        using (var cmd = new TCommand())
        {
            cmd.CommandText = sql;
            cmd.Connection = con;
            cmd.CommandType = commandType;
            if (parameters.Length > 0)
            {
                cmd.Parameters.AddRange(parameters);
            }
            con.Open();
            return function(cmd);
        }
    }
}

, чем я добавил несколько методов, которые используют этот метод:

public int ExecuteNonQuery(string sql, CommandType commandType, params IDbDataParameter[] parameters)
{
    return Execute<int>(sql, commandType, c => c.ExecuteNonQuery(), parameters);
}

public bool ExecuteReader(string sql, CommandType commandType, Func<IDataReader, bool> populate, params IDbDataParameter[] parameters)
{
    return Execute<bool>(sql, commandType, c => populate(c.ExecuteReader()), parameters);
}

и так далее.

Не стесняйтесь заимствовать идеи из этого проекта - или даже использовать их как есть - у меня есть несколько приложений, использующих это, и они работают очень хорошо в течение довольно долгого времени.

0
ответ дан Zohar Peled 16 January 2019 в 06:11
поделиться

В то время как постоянный слой имеет смысл, вы должны создать его по-другому. То, что вы делаете, это упаковываете некоторую сложность в методы, которые все еще делают то же самое, такие как ChangeParam() или GetDataReader().

Как правило, у вас есть репозитории, которые знают о базовых технических особенностях и устраняют такие сложности, как GetAllCustomers() (с акцентом на доменное имя customer ).

Когда вы скажете 4 или 5 таких хранилищ, вы начнете рефакторинг, абстрагируя сложность в родительский класс. Таким образом, вы упаковываете сложность, такую ​​как в GetDataReader() и , продвигаете ее из репозиториев в абстрактный репозиторий , который находится поверх него.

Начав с того, с чего вы начали, вы получите еще один слой, который не абстрагируется почти так же сильно и обладает слишком большой, часто ненужной, функциональностью.

Если бы это было так просто, API ADO.NET уже удалил бы его.

Еще одна вещь, которую вы должны сделать, это взглянуть на этот простой, но постоянно повторяющийся фрагмент кода. Он перегоняет некоторые основные понятия о IDisposable и using(){}. Вы всегда встретите его в правильном коде:

string sql = "SELECT * FROM t";

using (SqlConnection con = new SqlConnection(connectionString))
using (SqlCommand cmd = new SqlCommand(sql, con))
{
    SqlDataReader reader;

    con.Open();
    reader = cmd.ExecuteReader();

    while (reader.Read())
    {
        // TODO: consume data
    }
    reader.Close();
}

Это то, что я ожидаю увидеть на уровне персистентности, и часть потребления данных на самом деле самая важная. , потому что это зависит от домена. Остальное - просто шаблонный код с небольшим интересом.

0
ответ дан pid 16 January 2019 в 06:11
поделиться

Вы не реализуете одноразовый шаблон через интерфейс IDisposable , у вас просто есть метод Dispose, в свою очередь вы не сможете вызвать его в операторе using.

public class Database : IDisposable { ... }

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

Также у вас есть деструктор, однако его использование некорректно в 99% случаев

0
ответ дан Michael Randall 16 January 2019 в 06:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: