2008-11-06 3 views
16

Пожалуйста, помогите!.net SqlConnection не закрывается даже при использовании {}

Справочная информация

У меня есть приложение WPF, который получает доступ к базе данных SQL Server 2005. База данных выполняется локально на компьютере, на котором запущено приложение.

Всюду, где я использую Linq DataContext, я использую оператор {} и передаю результат функции, которая возвращает объект SqlConnection, который был открыт, и выполнил его с помощью SqlCommand, прежде чем вернуться к конструктору DataContext .. Т.е.

// In the application code 
using (DataContext db = new DataContext(GetConnection())) 
{ 
    ... Code 
} 

где GetConnection выглядит следующим образом (я раздел на «пушок» из функции, чтобы сделать его более удобным для чтения, но нет никакой дополнительной функциональности, которая отсутствует).

// Function which gets an opened connection which is given back to the DataContext constructor 
public static System.Data.SqlClient.SqlConnection GetConnection() 
{ 
    System.Data.SqlClient.SqlConnection Conn = new System.Data.SqlClient.SqlConnection(/* The connection string */); 

    if (Conn != null) 
    { 
     try 
     { 
      Conn.Open(); 
     } 
     catch (System.Data.SqlClient.SqlException SDSCSEx) 
     { 
      /* Error Handling */ 
     } 

     using (System.Data.SqlClient.SqlCommand SetCmd = new System.Data.SqlClient.SqlCommand()) 
     { 
      SetCmd.Connection = Conn; 
      SetCmd.CommandType = System.Data.CommandType.Text; 

      string CurrentUserID = System.String.Empty; 
      SetCmd.CommandText = "DECLARE @B VARBINARY(36); SET @B = CAST('" + CurrentUserID + "' AS VARBINARY(36)); SET CONTEXT_INFO @B"; 

      try 
      { 
       SetCmd.ExecuteNonQuery(); 
      } 
      catch (System.Exception) 
      { 
       /* Error Handling */ 
      } 
     } 

     return Conn; 
    } 

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

Проблема, которую я имею

Несмотря на SqlConnection расположены вместе с DataContext в студии управления Sql Server я до сих пор можно увидеть кучу открытых соединений с:

status : 'Sleeping' 
command : 'AWAITING COMMAND' 
last SQL Transact Command Batch : DECLARE @B VARBINARY(36); SET @B = CAST('GUID' AS VARBINARY(36)); SET CONTEXT_INFO @B 

В конце концов соединения пул истощается, и приложение не может продолжаться.

Поэтому я могу только заключить, что каким-то образом запуск SQLCommand для установки Context_Info означает, что соединение не удаляется, когда DataContext удаляется.

Может ли кто-нибудь заметить что-либо очевидное, что будет прекращать соединение из-за закрытия и удаления, когда используется DataContext, который они используют?

ответ

19

От MSDN (DataContext Constructor (IDbConnection)):

Если вы предоставите открытое соединение, DataContext не закрывать его. Следовательно, не создавайте экземпляр DataContextс открытым подключением , если у вас нет веских причин делать .

В целом, похоже, что ваши соединения ждут завершения GC, прежде чем они будут выпущены. Если у вас много кода, который делает это, один из подходов может заключаться в том, чтобы переопределить Dispose() в частичном классе данных-контекста и закрыть соединение - просто убедитесь, что документ-контекст предполагает право собственности на соединение!

protected override void Dispose(bool disposing) 
    { 
     if(disposing && this.Connection != null && this.Connection.State == ConnectionState.Open) 
     { 
      this.Connection.Close(); 
      this.Connection.Dispose(); 
     } 
     base.Dispose(disposing); 
    } 

Лично я бы с удовольствием дать ему (обычные данные, контекст, ж/о вышеприведенном хака) открытое соединение до тех пор, как я «используя» соединение (позволяет мне выполнять несколько операций) - т.е.

using(var conn = GetConnection()) 
{ 
    // snip: some stuff involving conn 

    using(var ctx = new FooContext(conn)) 
    { 
     // snip: some stuff involving ctx 
    } 

    // snip: some more stuff involving conn 
} 
0

Dispose должен закрыть соединение, так как MSDN указывает:

Если SqlConnection выходит из сферы, он не будет закрыт. Поэтому вы должны явно закрыть соединение , вызвав Close или Dispose. Close и Dispose - функционально эквивалентны. Если значение объединения пулов Pooling равно , установленное в true или yes, базовое соединение возвращается обратно в пул соединений . С другой стороны, если В пуле установлено значение «ложь» или «нет», то базовое соединение с сервером будет закрыто.

Я предполагаю, что ваша проблема имеет отношение к GetContext().

7

SqlProvider, используемый LINQ DataContext, только закрывает соединение SQL (через SqlConnectionManager.DisposeConnection), если он был открыт. Если вы предоставите уже открытый объект SqlConnection конструктору DataContext, он не закроет его для вас. Таким образом, вы должны написать:

using (SqlConnection conn = GetConnection()) 
using (DataContext db = new DataContext(conn)) 
{ 
    ... Code 
} 
1

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

Решение:

Создайте свой собственный класс DataContext, который является производным от автоматического генерироваться один. (переименуйте базовый, чтобы вам не пришлось менять какой-либо другой код).

В вашем производном DataContext - добавьте функцию Dispose(). В этом - распоряжаться внутренним соединением.

+0

Вы можете просто добавить частичный класс для расширения автоматически генерируемого контекста данных; нет необходимости в подклассе. – 2008-11-06 15:10:22

1

Ну спасибо за помощью парней, она была теперь решено ..

По существу я взял элементы большинства из вышеуказанных ответов и реализован конструктор DataContext, как описано выше (я уже перегружен конструкторы, так что WASN» т большое изменение).

// Variable for storing the connection passed to the constructor 
private System.Data.SqlClient.SqlConnection _Connection; 

public DataContext(System.Data.SqlClient.SqlConnection Connection) : base(Connection) 
{ 
    // Only set the reference if the connection is Valid and Open during construction 
    if (Connection != null) 
    { 
     if (Connection.State == System.Data.ConnectionState.Open) 
     { 
      _Connection = Connection;      
     } 
    }   
} 

protected override void Dispose(bool disposing) 
{   
    // Only try closing the connection if it was opened during construction  
    if (_Connection!= null) 
    { 
     _Connection.Close(); 
     _Connection.Dispose(); 
    } 

    base.Dispose(disposing); 
} 

Причина для этого, а не некоторые из указанных выше предложений является то, что доступ к this.Connection в методе Dispose бросает ObjectDisposedException.

И вышеупомянутые работы так же, как я надеялся!

+0

Эй, вот что я сказал. Я должен быть умным. – GeekyMonkey 2008-11-06 21:57:54

3

Я столкнулся с той же проблемой, используя платформу Entity Framework. Мой ObjectContext был обернут вокруг блока using.

Соединение было установлено, когда я позвонил SaveChanges(), но после того, как заявление using было вне области видимости, я заметил, что SQL Management Studio по-прежнему имеет "AWAITING COMMAND" для .NET SQL Client. Похоже, что это связано с поведением поставщика ADO.NET, который включил пул соединений по умолчанию.

С «Использование Пулы соединений с SQL Server» на MSDN (курсив мой):

Пулы соединений уменьшает количество раз, которые должны быть открыты новые соединения. Пулёт поддерживает право собственности на физическое соединение. Он управляет соединениями, поддерживая живой набор активных соединений для каждой конкретной конфигурации соединения. Всякий раз, когда пользователь вызывает Open при подключении, пулер смотрит, есть ли доступное соединение в пуле. Если объединенное соединение доступно, оно возвращает его вызывающему абоненту вместо открытия нового соединения. Когда приложение вызывает Close в соединении, пул вернет его в объединенный набор активных соединений вместо фактического его закрытия. После того, как соединение будет возвращено в пул, он будет готов к повторному использованию в следующем вызове Open.

Также ClearAllPools и ClearPool кажется полезным явно закрыть все объединенные соединения, если это необходимо.

Смежные вопросы