Соединение с моей БД закрыто? (Линк в Sql) - PullRequest
4 голосов
/ 28 февраля 2010

Я использую Linq to SQL и читаю в блоге сообщение о закрытии соединений с базой данных как можно скорее. В качестве примера они показали, что переменная преобразуется в список (с использованием .ToList ()) вместо фактического возврата запроса Linq. У меня есть следующий код:

 public static bool HasPassword(string userId)
 {

    ProjDataContext db = new ProjDataContext();

    bool hasPassword = (from p in db.tblSpecUser
                                    where p.UserID == userId
                                    select p.HasPassword).FirstOrDefault();


    return hasPassword;
 }

Этот запрос в порядке? Или соединение с базой данных останется открытым дольше, чем необходимо?

Спасибо за любой совет

Ответы [ 5 ]

5 голосов
/ 28 февраля 2010

Соединение будет управляться автоматически. Однако существуют (или, по крайней мере, могут быть, как показывают комментарии) дополнительные ресурсы, связанные с DataContext. Эти ресурсы не будут освобождены, пока DataContext не будет уничтожен сборщиком мусора. Поэтому обычно лучше убедиться, что dispose вызывается, когда вам больше не нужен DataContext.

using (ProjDataContext db = new ProjDataContext()) {
    bool hasPassword = (from p in db.tblSpecUser
                                    where p.UserID == userId
                                    select p.HasPassword).FirstOrDefault();


    return hasPassword;
}

Здесь гарантируется, что db.Dispose() вызывается при выходе из блока использования, тем самым явно закрывая соединение.

Редактировать: После обсуждения я посмотрел на DataContext избавиться (также с помощью Reflector) и нашел следующий код (FW 3.5), который вызывается из DataContext.Dispose:

protected virtual void Dispose(bool disposing)
{
    if (disposing)
    {
        if (this.provider != null)
        {
            this.provider.Dispose();
            this.provider = null;
        }
        this.services = null;
        this.tables = null;
        this.loadOptions = null;
    }
}

Итак, есть ресурсов, которые освобождаются:

  • Провайдер, который может хранить DbConnection, журнал (TextWriter) и DbTransaction.
  • The CommonDataServices.
  • Словарь таблиц.
  • LoadOptions.

Поставщик может хранить ресурсы, которые необходимо утилизировать (DbConnection и DbTransaction). Кроме того, TextWriter для журнала может потребоваться в зависимости от того, какой экземпляр TextWriter пользователь назначил для механизма ведения журнала DataContext, например, FileWriter, который затем автоматически закрывается.

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

Итак, наконец, я полностью согласен с утверждением casparOne:

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

Вы должны создать свои ресурсы для доступа к БД, выполнить свои операции, а затем утилизировать их по завершении.

2 голосов
/ 28 февраля 2010

С точки зрения реализации нет, вам не о чем беспокоиться. Однако это связано не с запросом, а с управлением самим DataContext .

Класс DataContext реализует интерфейс IDisposable , поэтому вы должны вызывать Dispose для реализации DataContext всякий раз, когда вы закончите с ним.

Итак, это хорошо известный факт, что вызов Dispose для экземпляров DataContext ничего не делает, и поэтому технически не требуется .

К сожалению, это тоже очень плохая практика. Вы всегда должны кодировать против контракта , а не реализации . Поскольку DataContext реализует IDisposable, вы должны закрыть его, , даже если вы знаете, что он ничего не делает , потому что это может абсолютно измениться в будущих реализациях.

Кроме того, если вы переключаетесь на другого поставщика LINQ, скажем, LINQ-to-Entities, тогда вы должны вызвать Dispose, когда закончите, потому что время жизни соединений с базой данных в ObjectContext экземпляры (которые также реализуют IDisposable) сильно отличаются, и вызов Dispose влияет на эти соединения с базой данных.

Все это, как говорится, вас больше беспокоит. Если вы используете один DataContext, вы рискуете отследить слишком много объектов. Если вы не установили для свойства ObjectTrackingEnabled значение false, DataContext отслеживает каждый объект, выбранный через него. Если вы не выполняете операции обновления (или даже выполняете это) в течение всего жизненного цикла приложения, количество ресурсов, выделяемых для отслеживания объектов в общем DataContext, может стать значительным.

Правила, применяемые для других технологий баз данных (например, классы в пространстве имен System.Data.SqlClient ), по-прежнему применяются.

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

Вы должны создать свои ресурсы для доступа к БД, выполнить свои операции, а затем утилизировать их по завершении.

1 голос
/ 28 февраля 2010

С Linq-To-SQL вам, как правило, не нужно беспокоиться об открытии и закрытии соединения, являющегося частью объекта контекста (в нашем примере это db). Единственный раз, когда вам нужно было бы сделать это конкретно, это если бы вы отправляли прямые вызовы SQL через объект контекста вместо использования Linq.

С L2S вы обычно хотите создать свой контекстный объект, выполнить свою единицу работы, а затем избавиться от объекта как можно быстрее. Ваш пример кода выглядит хорошо для меня.

0 голосов
/ 28 февраля 2010

Соединение с базой данных будет закрыто сразу после того, как ваш объект db больше не будет существовать (удален) или явно закрыт. В вашем примере он (рано или поздно) будет собирать мусор.

0 голосов
/ 28 февраля 2010

Я думаю, что хорошей практикой является использование оператора using. Но я думаю, что в вашем запросе нет ничего плохого.

public static bool HasPassword(string userId)
 {

    using(var db = new ProjDataContext())
    {

       bool hasPassword = (from p in db.tblSpecUser
                                    where p.UserID == userId
                                    select p.HasPassword).FirstOrDefault();


        return hasPassword;
    }
}
...