none
Problema no fechamento de conexão RRS feed

  • Pergunta

  • Olá pessoal. Estou tendo um problema no fechamento de conexões com o SQL Server, apenas em Debug.

    O que ocorre é que ao tentar fechar a conexão (conexão aberta em Pooling FALSE), tenho a seguinte  mensagem, na clinha do método Close():
    "InvalidOperationException was unhandled. Handle is not initialized."

    System.InvalidOperationException was unhandled
      Message="Handle is not initialized."
      Source="mscorlib"
      StackTrace:
           at System.WeakReference.set_Target(Object value)
           at System.Data.ProviderBase.DbConnectionInternal.CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory)
           at System.Data.SqlClient.SqlConnection.Close()
           at DataBaseLayers.SqlServerLayer.Close() in H:\Controls\DataBaseLayers\SqlServerLayer.cs:line 80
           at DataBaseLayers.SqlServerLayer.Finalize() in H:\Controls\DataBaseLayers\SqlServerLayer.cs:line 91

    Antes do fechamento eu verifico a necessidade do fechamento...

    if (conexaoSql.State == ConnectionState.Open)
         conexaoSql.Close();

    Porque disto?!

    quarta-feira, 19 de julho de 2006 14:01

Respostas

  • Talvez o problema seja esse. Você, como programador, não sabe quando o destrutor da classe é chamado efetivamente. Essa chamada é feita exclusivamente pelo Garbage Collector. O destrutor do objeto connection também é determinado pelo Garbage Collector. Em outras palavras, você não tem determinada a ordem que os objetos são retirados da memória. O que pode estar ocorrendo é que quando o destrutor da sua classe é chamada pelo GC, o objeto conexaoSql pode já ter sido retirado da memória pelo GC. Para resolver isso você pode: 1) fechar a conexão em outro local que não o destrutor, em um método, por exemplo, e chama-lo sempre que não for mais usar a instancia da sua classe; 2)chamar o GC para limpar a memória; 3) Implementar o método Dispose da interface IDisposable, fazendo com que o destrutor seja chamado sempre que terminar de usar os objetos de sua classe.

    Espero ter ajudado.

     

    quarta-feira, 19 de julho de 2006 17:28

Todas as Respostas

  • Felipe ,

    Na verdade a referencia a conexão já não existe mais por isso e erro de exeption,o objeto conexaoSql não esta mais referenciado.

    Espero ter ajudado e qualquer duvida retorne.

    quarta-feira, 19 de julho de 2006 14:18
  • Olá Daniel. Como a referência não existe mais se eu consigo ver o estado da conexão na linha 1 do código abaixo? Mandei o Debug parar na linha 1 para ver o estado. Quando está Open, vai para a linha 2 (claro!). Algumas vezes fecha e o estado é alterado para Close sem problemas. Mas algumas vezes, a conexão está Open na linha 1 e, antes de executar a linha 2, já está Close!!! Daí, quando executa a linha 2 ocorre esse problema. Será que o negócio é tão eficiente que fecha antes mandar fechar?!

    1    if (conexaoSql.State == ConnectionState.Open)
    2         conexaoSql.Close();

    Vlw!

    quarta-feira, 19 de julho de 2006 14:27
  • Felipe,

    Por um acaso este código de verificação está no destrutor da classe? 

    quarta-feira, 19 de julho de 2006 16:53
  • Frederico, eu sempre fecho a conexão usando um método chamado Close, da minha classe. Este, por sua vez, verifica a necessidade de fechar a conexão ou não. E o Destrutor da classe também está ai embaixo.. mas ele chama o mesmo método, para fazer o tratamento.

     

    public void Close()

    {

    if (conexaoSql.State == ConnectionState.Open)

    conexaoSql.Close();

    }

    ~SqlServerLayer()

    {

    Close();

    }

    Vlw!

    quarta-feira, 19 de julho de 2006 17:05
  • Talvez o problema seja esse. Você, como programador, não sabe quando o destrutor da classe é chamado efetivamente. Essa chamada é feita exclusivamente pelo Garbage Collector. O destrutor do objeto connection também é determinado pelo Garbage Collector. Em outras palavras, você não tem determinada a ordem que os objetos são retirados da memória. O que pode estar ocorrendo é que quando o destrutor da sua classe é chamada pelo GC, o objeto conexaoSql pode já ter sido retirado da memória pelo GC. Para resolver isso você pode: 1) fechar a conexão em outro local que não o destrutor, em um método, por exemplo, e chama-lo sempre que não for mais usar a instancia da sua classe; 2)chamar o GC para limpar a memória; 3) Implementar o método Dispose da interface IDisposable, fazendo com que o destrutor seja chamado sempre que terminar de usar os objetos de sua classe.

    Espero ter ajudado.

     

    quarta-feira, 19 de julho de 2006 17:28
  • Olá Frederico. Eu sempre chamo o Close(). Mas pela boa intenção, eu acabei programando o Destructor para chamá-lo também, mesmo que não seja mais necessário. Talvez tenha pecado pelo excesso de preocupação em fechar a conexão. Mas o que você disse está perfeito, eu não sei quando o destructor é chamado. Ocorre, inclusive, de eu estar com a página já renderizada no browser e o foco ser alterado para dentro do Visual Studio para me informar que ocorreu um erro no fechamento da conexão. Ou seja, o GC trabalhou neste momento, chamando o destructos, que por sua vez chama o (meu) Close. Vou testar ainda, mas estou quase certo de que você foi perfeito no que disse!

    quarta-feira, 19 de julho de 2006 17:39
  • Felipe,

    Espero que tudo funcione de agora em diante por aí. Para completar, sempre recomendo não usar destrutores em classes caso estas não usem recursos não gerenciados, pois isso aumenta de forma desnecessária o trabalho do GC.

    Abraços

    quarta-feira, 19 de julho de 2006 17:42
  • Oi Frederico. Já não há mais dúvidas, era mesmo o que você falou. Muito obrigado! Vlw!
    quarta-feira, 19 de julho de 2006 17:55