2010-09-23 4 views
0

J'essaie de m'assurer que je ne laisse aucune extrémité ouverte dans mon application et suis inquiet au sujet de quelques-uns mais pourrait obtenir ma réponse de celui-ci. J'ai "outrepassé" certaines fonctions afin que je puisse essayer de garder toutes les ressources aussi propres et libres que possible. Donc, dans cette instance, j'ai une fonction appelée ExecuteReader qui renvoie un DbDataReader comme d'habitude, mais tout ce que je devais passer à elle était une chaîne SQL plutôt que de recréer une commande DbCommand à chaque fois. Je veux m'assurer que même si je suis incapable d'appeler le dbCommand.Dispose(), c'est effectivement le cas. Toute aide est appréciée.Cette fonction libère-t-elle les ressources correctement?

Public Function ExecuteReader(ByVal strSQL As String) As DbDataReader 
    Dim dbCommand = _dbConnection.CreateCommand() 
    dbCommand.CommandText = strSQL 
    dbCommand.Prepare() 
    Return dbCommand.ExecuteReader() 
End Function 

Je pensais à l'aide d'une déclaration using, mais je me souviens avoir vu un fil où quelqu'un a dit qu'ils pensent qu'il leur posait des problèmes ayant un retour dans la déclaration using. Aussi, je ne suis pas sûr que ce soit wiki communautaire ou non. Si c'est le cas, faites le moi savoir. Merci.

Code de mise à jour:

Voici un exemple de la façon dont je l'utilise.

Public Sub RevertDatabase() 
    'This function can be used whenever all changes need to be undone, but was created' 
    'for saving the data as a .out file. It sets all changes back to their original value.' 

    'Set the data reader to all parts and columns that were changed.' 
    _dbReader = ExecuteReader("SELECT PART_ID, PART_PREV_VALUE, REPORT_COLUMN_NAME FROM REPORTS WHERE PART_PREV_VALUE NOT NULL") 
    'Create an instance of the Command class.' 
    Dim cmd = New Command() 

    While _dbReader.Read() 
     'For each part and columns that has been changed, set the values in the' 
     'new cmd variable and then update the value using the same function' 
     'that is used whenever a value is changed in the data grid view.' 
     cmd.CommandString = _dbReader("REPORT_COLUMN_NAME").ToString().Replace("_", " ") 
     cmd.Value = _dbReader("PART_PREV_VALUE").ToString() 
     cmd.ID = _dbReader("PART_ID").ToString() 
     UpdateValue(cmd) 
    End While 

    'Close the reader.' 
    _dbReader.Close() 
End Sub 

Ici, je mis le _dbReader à ce que je reçois de la fonction et, finalement, je ferme la _dbReader. Je ne ferme pas la connexion car je ne l'ouvre pas chaque fois que je fais une requête. Il s'agit d'une base de données SQLite qu'un seul utilisateur utilisera à la fois (petite application avec très très peu de probabilité de croissance) donc je n'ai pas jugé nécessaire de fermer et d'ouvrir la connexion tout le temps. Peut-être que je me trompe, pas sûr. En l'utilisant de cette façon cependant, il est potentiellement acceptable pour le nettoyage des ressources?

Répondre

3

C'est une mauvaise idée de renvoyer DbDataReader car cela nécessite que le flux soit maintenu ouvert et repose sur le code appelant pour faire la bonne chose en disposant le lecteur. Il est également difficile de fermer la commande sous-jacente et les objets de connexion. Une façon de faciliter cela si vous voulez vraiment exposer le lecteur, est d'utiliser CommandBehavour. Cela peut être utilisé pour fermer la connexion sous-jacente lorsque le lecteur lui-même est fermé.

dbCommand.ExecuteReader(CommandBehavour.CloseConnection) 

Comme DbConnection, DbCommand et DbDataReader sont à usage unique que vous devez factoriser le code pour permettre à ceux-ci nettoyé lorsque le code a terminé avec eux. Une façon consiste à implémenter IDisposable dans votre propre classe et à éliminer les bulles à tous les objets encapsulés. Le code appelant peut ensuite mettre en œuvre en utilisant pour s'assurer que les ressources sont libérées.

Using helper As New DatabaseHelper() 
    Using reader As IDataReader = helper.LoadSomeDataReader() 

     ' do something with reader 

    End Using 
End Using 

MISE À JOUR:

Votre deuxième bloc de code deviendrait plus comme:

Public Sub RevertDatabase() 
    Using _dbReader As IDataReader = ExecuteReader(...) 

     While _dbReader.Read() 

     Using cmd As New Command() 
      cmd.CommandString = _dbReader("REPORT_COLUMN_NAME").ToString().Replace("_", " ") 
      cmd.Value = _dbReader("PART_PREV_VALUE").ToString() 
      cmd.ID = _dbReader("PART_ID").ToString() 
      UpdateValue(cmd) 
     End Using 

     End While 

    End Using 
End Sub 

Vous devez toujours ouvrir et fermer la connexion, plutôt que de simplement le laisser ouvert. Il pourrait pratiquer et bien que très improbable dans une très petite application, vous pourriez rencontrer des problèmes. Vous ne devriez pas non plus garder une référence à l'OMI _dbReader.

+0

Vérifiez mon code mis à jour. Je me suis dit que je devrais montrer comment je l'utilise pour voir si c'est encore dangereux ou non. Merci d'avoir répondu. – XstreamINsanity

+0

Oui, après avoir fait le post de ne pas avoir besoin de l'ouvrir et de le fermer, j'ai pensé que je testerais pour voir combien de temps il faut pour l'ouvrir, et ça ne prend pas très longtemps, donc je le ferais aussi. Je vous remercie de votre réponse et j'essaierai de l'appliquer partout où je l'utiliserai. – XstreamINsanity

0

Renvoyer une instance IDisposable à partir d'une fonction est parfaitement bien. La propriété de l'instance est transférée de la fonction à l'appelant et il appartient maintenant à l'appelant d'appeler le Dispose. C'est exactement le même principe en jeu lors de l'appel IDbCommand.ExecuteReader.

Vous devez absolument utiliser l'instruction Using. Il rend le code plus lisible puisqu'il insère automatiquement le bloc try-finally correct qui appelle la méthode Dispose. Je ne connais pas les détails de la question dont vous parliez, mais vous ne devriez pas avoir de problèmes vous-même puisque vous ne faites rien d'inhabituel.

Public Sub RevertDatabase() 
    Using dbReader As DbDataReader = ExecuteReader(...) 
     // Use the data reader here. 
    End Using 
End Sub 
Questions connexes