1. #1
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    juin 2011
    Messages
    48
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations professionnelles :
    Secteur : Industrie

    Informations forums :
    Inscription : juin 2011
    Messages : 48
    Points : 16
    Points
    16

    Par défaut Procedure stockée dans une boucle.

    Bonjour,

    J'ai codé un service qui à pour fonction de mettre en base le contenu de fichiers texte dans une base de données. Les données sont analysées et "rangées" au passage. Le fichier contient entre 231 et 31000 lignes. Ce service lance le traitement d'un fichier toutes les 10 secondes. Le temps de traitement est entre 0 et 3 secondes.

    Tout fonctionne bien la plupart du temps, sauf, de temps à autre, j'ai cette erreur: "System.InvalidOperationException: There is already an open DataReader associated with this Command which must be closed first."
    Le service se plante et ne fait plus rien tant qu'il n'est pas relancé.

    Mon code:
    - Lecture de l'emplacement du fichier via procédure stockée (avec datareader)
    - Lecture du fichier à traiter dans une string
    - écriture en base d'une trace de début de transfert (via ExecuteNonQuery)
    - Pour chaque ligne du fichier contenue dans la string
    - insert de la ligne via une procédure stockée (via ExecuteNonQuery)---->> plante ici de temps en temps avec l'erreur cité
    - écriture en base d'une trace de fin de transfert (via ExecuteNonQuery)

    Tout cela fonctionne des milliers de fois par jours et soudainement j'ai cette erreur. Pourriez vous m'aidez pour ce problème, je ne trouve pas de solution.

    Merci.

  2. #2
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    avril 2007
    Messages
    12 843
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : avril 2007
    Messages : 12 843
    Points : 23 126
    Points
    23 126

    Par défaut

    Quand tu fais executereader tu récupères une variable de type datareader, il faut appeler .close dessus quand tu as finis de l'utiliser , sur la meme connexion un exevute plantera sinon
    Si tu fais une boucle qui lit les données d'un datateader, la connexion ne peut être utilisée en meme temps pour autre chose, sinon utiliser une autre connexion
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  3. #3
    Rédacteur/Modérateur

    Avatar de François DORIN
    Homme Profil pro
    Consultant informatique
    Inscrit en
    juillet 2016
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : juillet 2016
    Messages : 1 415
    Points : 4 773
    Points
    4 773
    Billets dans le blog
    5

    Par défaut

    Bonjour,

    Il nous faudrait ton code. Sans cela, difficile de t'aider...

    A priori, juste le code C#
    François DORIN
    Consultant informatique : conception, modélisation, développement (C#/.Net et SQL Server)
    Site internet | Profils Viadéo & LinkedIn
    ---------
    Page de cours : fdorin.developpez.com
    ---------
    N'oubliez pas de consulter la FAQ C# ainsi que les cours et tutoriels

  4. #4
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    juin 2011
    Messages
    48
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations professionnelles :
    Secteur : Industrie

    Informations forums :
    Inscription : juin 2011
    Messages : 48
    Points : 16
    Points
    16

    Par défaut

    Je n'utilise pas de reader justement lorsque j'ecrit la ligne en base. LA procedure ne renvoi rien. J'utilise ExecuteNonQuery.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
     
            Dim lNomMachine As String = ""
            Dim lEmplacement As String = ""
            Dim lNomFichier As String = ""
            Dim lDonneesFichier As String()
     
            Dim iCptValeur As Integer = 1
            Dim iCptInfoDefaut As Integer = 1  'compteur des informations de défauts
     
            Dim lDateDebut As Date = Date.Now
     
            Dim lDonnees As DataTable = Nothing
            Dim lLigneDonnees As DataRow = Nothing
            Dim lIdtFichier As Integer = 0      'Identifiant associée à la machine
            Dim lIdtFichierPrecedent As Integer = 0
     
            Dim lNumeroVersion As Integer = 4
     
            Dim lMessage As String = ""
     Try
     
                app.AccesBase.RecupererTable(CommandType.StoredProcedure, "MaProcedure", lDonnees)
     
                If lDonnees IsNot Nothing AndAlso lDonnees.Rows.Count = 1 Then
                    lLigneDonnees = lDonnees.Rows(0)
                    lNomMachine ="US"
                    lEmplacement = lLigneDonnees("Chemin").ToString
                    lNomFichier = lLigneDonnees("Fichier").ToString
                    lIdtFichier = CInt(lLigneDonnees("Idt"))
                    lNumeroVersion = CInt(lLigneDonnees("Version"))
     
                    lMessage = "Demande de transfert du fichier " + lIdtFichier.ToString
                    app.AccesBase.Executer(CommandType.StoredProcedure, "PROTracer",  lMessage)
                    lMessage = ""
     
                    If IO.File.Exists(lEmplacement + lNomFichier) Then
     
     
                        on récupère toutes les lignes du fichier
                        lDonneesFichier = IO.File.ReadAllLines(lEmplacement + lNomFichier)
     
                        lMessage = "Début Transfert du fichier " + lIdtFichier.ToString + " - " + lDonneesFichier.Count.ToString + " lignes."
                        app.AccesBase.Executer(CommandType.StoredProcedure, "PROTracer", MethodBase.GetCurrentMethod.Name, lMessage)
                        lMessage = ""
     
                        For Each lLigneFichier As String In lDonneesFichier
                            If lNomMachine = "US" Then
                                app.AccesBase.Executer(CommandType.StoredProcedure, "PROImporter","US, lIdtFichier, lLigneFichier, iCptValeur, lNumeroVersion, iCptInfoDefaut)  --> plante ici 1 fois de temps en temps
                                 iCptValeur += 1
                            End If
                        Next
     
     
                    Else
     
                        lMessage = "Le fichier " + lEmplacement + lNomFichier + " n'existe pas."
                        app.AccesBase.Executer(CommandType.StoredProcedure, "PROTracer", MethodBase.GetCurrentMethod.Name, lMessage, 2)
                        lMessage = ""
                    End If
     
                End If
     
     
            Catch ex As Exception
                TraiterErreur(MethodBase.GetCurrentMethod, ex)
                    End Try

  5. #5
    Rédacteur/Modérateur

    Avatar de François DORIN
    Homme Profil pro
    Consultant informatique
    Inscrit en
    juillet 2016
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : juillet 2016
    Messages : 1 415
    Points : 4 773
    Points
    4 773
    Billets dans le blog
    5

    Par défaut

    Et quel est le code de la fonction AccesBase.Executer ?
    François DORIN
    Consultant informatique : conception, modélisation, développement (C#/.Net et SQL Server)
    Site internet | Profils Viadéo & LinkedIn
    ---------
    Page de cours : fdorin.developpez.com
    ---------
    N'oubliez pas de consulter la FAQ C# ainsi que les cours et tutoriels

  6. #6
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    juin 2011
    Messages
    48
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations professionnelles :
    Secteur : Industrie

    Informations forums :
    Inscription : juin 2011
    Messages : 48
    Points : 16
    Points
    16

    Par défaut

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
      Public Function Executer(ByVal type As CommandType, _
                                     ByVal texteSql As String, _
                                     ByVal tracerLog As Boolean, _
                                     ByVal RecupererParametre As Boolean, _
                                     ByVal ParamArray valeurs As Object()) As Integer
     
                Dim mCommande As SqlCommand = Nothing
     
                Try
     
                    Select Case type
                        Case CommandType.Text
                            'Création d'une nouvelle commande
                            mCommande = CreerRequete(texteSql, tracerLog)
     
                        Case CommandType.StoredProcedure
                            'Création d'une nouvelle commande
                            mCommande = CreerCommande(texteSql, tracerLog, valeurs)
     
                    End Select
     
     
                    'Exécute la commande et récupere le nombre de lignes affectées
                    Executer = mCommande.ExecuteNonQuery()
     
                    If RecupererParametre Then
                        'Recuperation des parametres
                        mParametres = mCommande.Parameters
                    End If
     
                    'Indique la fin de l'execution de la requete
                    'GestionErreur.EnvoyerMessage(Me, MethodBase.GetCurrentMethod, "Execution de la procedure terminée. (" & texteSql & ")")
                    If tracerLog Then
                        RaiseEvent TraceChange(Me, _
                                                 New ApplicationEventArgs(MethodBase.GetCurrentMethod, _
                                                                          Nothing, _
                                                                          "Execution de la procédure terminée. (" & texteSql & ").", _
                                                                          TypeTrace.Debug, _
                                                                          TypeAffichage.Aucun))
                    End If
     
                Catch ex As Exception
     
                    'Leve une exception pour l'appelant
                    Throw New ApplicationErreur("L'execution de la procédure a échouée. (" & texteSql & ")", _
                                                ex, _
                                                TypeTrace.Grave, _
                                                TypeAffichage.Bandeau, _
                                                "")
     
                End Try
     
            End Function

  7. #7
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    juin 2011
    Messages
    48
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations professionnelles :
    Secteur : Industrie

    Informations forums :
    Inscription : juin 2011
    Messages : 48
    Points : 16
    Points
    16

    Par défaut

    Je precise que le message d'erreur dans l'observateur d' evenement me donne le nom de la procedure qui a ce problème :
    L'execution de la procédure a échouée. (PROImporter) ---> System.InvalidOperationException: There is already an open DataReader associated with this Command which must be closed first.

  8. #8
    Rédacteur/Modérateur

    Avatar de François DORIN
    Homme Profil pro
    Consultant informatique
    Inscrit en
    juillet 2016
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : juillet 2016
    Messages : 1 415
    Points : 4 773
    Points
    4 773
    Billets dans le blog
    5

    Par défaut

    Et comment sont définies CreerCommande et CreerRequete ?

    Bref, comment est instancié SqlCommand ? Car le problème vient sans doute de cela... Par exemple, dans le code de la fonction Executer, l'instance de SqlCommand n'est pas libérée (fonction Dispose). En fonction de la manière dont SqlCommand est instanciée, cela peut venir de là.
    François DORIN
    Consultant informatique : conception, modélisation, développement (C#/.Net et SQL Server)
    Site internet | Profils Viadéo & LinkedIn
    ---------
    Page de cours : fdorin.developpez.com
    ---------
    N'oubliez pas de consulter la FAQ C# ainsi que les cours et tutoriels

  9. #9
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    juin 2011
    Messages
    48
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations professionnelles :
    Secteur : Industrie

    Informations forums :
    Inscription : juin 2011
    Messages : 48
    Points : 16
    Points
    16

    Par défaut

    merci pour l'aide rapide.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
      Private Function CreerCommande(ByVal nomProcedure As String, _
                                           ByVal tracerLog As Boolean, _
                                           ByVal ParamArray valeurs As Object()) As SqlCommand
     
                Try
     
                    CreerCommande = New SqlCommand
     
                    'Création d'une nouvelle commande
                    With CreerCommande
                        .Connection = mConnexion
                        .CommandText = nomProcedure
                        .CommandType = CommandType.StoredProcedure
                        .CommandTimeout = mExecutionTimeOut
                        .Parameters.Clear()
                    End With
                    'Recuperation des parametres de la procedure
                    Me.RecupererParametre(CreerCommande, tracerLog)
     
     
                    'Si on a des valeurs
                    If valeurs.Length > 0 Then
     
                        'Met a jour les valeurs des parametres
                        Me.MettreAJourParametre(CreerCommande, tracerLog, valeurs)
                    End If
     
                Catch ex As Exception
     
                    'Leve une exception pour l'appelant
                    Throw New ApplicationErreur("La création de la commande a échouée. (" & nomProcedure & ")", _
                                                ex, _
                                                TypeTrace.Grave, _
                                                TypeAffichage.Bandeau, _
                                                "")
     
                End Try
     
            End Function

  10. #10
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    juin 2011
    Messages
    48
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations professionnelles :
    Secteur : Industrie

    Informations forums :
    Inscription : juin 2011
    Messages : 48
    Points : 16
    Points
    16

    Par défaut

    Pour moi, le sqlCommand devrait etre détruit lorsque je sors de la fonction. A moins qu'avec le trop grand nombre d'appel successif , le sqlcommand ne soit pas encore détruit certaines fois.
    Je ne met pas le code de CreerRequete car il n'est plus utilisé.

  11. #11
    Rédacteur/Modérateur

    Avatar de François DORIN
    Homme Profil pro
    Consultant informatique
    Inscrit en
    juillet 2016
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : juillet 2016
    Messages : 1 415
    Points : 4 773
    Points
    4 773
    Billets dans le blog
    5

    Par défaut

    Bon, une nouvelle instance de SqlCommand est bien créée à chaque fois. Il est donc nécessaire d'appeler la méthode Dispose une fois que l'instance n'est plus nécessaire. Cela permettra de libérer correctement les ressources.

    Je pense que le problème vient d'un trop grand nombre de SqlCommand existant simultanément. Le fait que l'erreur ne se produise que lors de l'import n'est ensuite qu'une question de statistiques (la ligne faisant l'import est appelée de 230 et 30000 fois par rapport aux autres requêtes qui sont appelées juste une seule fois.
    François DORIN
    Consultant informatique : conception, modélisation, développement (C#/.Net et SQL Server)
    Site internet | Profils Viadéo & LinkedIn
    ---------
    Page de cours : fdorin.developpez.com
    ---------
    N'oubliez pas de consulter la FAQ C# ainsi que les cours et tutoriels

  12. #12
    Rédacteur/Modérateur

    Avatar de François DORIN
    Homme Profil pro
    Consultant informatique
    Inscrit en
    juillet 2016
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : juillet 2016
    Messages : 1 415
    Points : 4 773
    Points
    4 773
    Billets dans le blog
    5

    Par défaut

    Citation Envoyé par KyoshiroKensei Voir le message
    Pour moi, le sqlCommand devrait etre détruit lorsque je sors de la fonction. A moins qu'avec le trop grand nombre d'appel successif , le sqlcommand ne soit pas encore détruit certaines fois.
    Je ne met pas le code de CreerRequete car il n'est plus utilisé.
    Erreur !!

    sqlCommand est détruit lorsque le ramasse miette s'exécute. A la sortie de la fonction, sqlCommand devient "récupérable", mais pas forcément "récupéré". Appeler la méthode Dispose assure que les ressources, autres que la mémoire, sont libérées au moment où on appelle la méthode (donc de manière déterministe), et non au moment où le ramasse-miette se met en marche (et ça, dieu seul sait quand cela va arriver !).
    François DORIN
    Consultant informatique : conception, modélisation, développement (C#/.Net et SQL Server)
    Site internet | Profils Viadéo & LinkedIn
    ---------
    Page de cours : fdorin.developpez.com
    ---------
    N'oubliez pas de consulter la FAQ C# ainsi que les cours et tutoriels

  13. #13
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    juin 2011
    Messages
    48
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations professionnelles :
    Secteur : Industrie

    Informations forums :
    Inscription : juin 2011
    Messages : 48
    Points : 16
    Points
    16

    Par défaut

    Merci beaucoup pour votre aide. Je test quelques jours et je vous répond. Il me reste 2 millions de fichier à importer, de quoi tester

  14. #14
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    juin 2011
    Messages
    48
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations professionnelles :
    Secteur : Industrie

    Informations forums :
    Inscription : juin 2011
    Messages : 48
    Points : 16
    Points
    16

    Par défaut

    même plantage à l'instant. A priori, dès que je rencontre un fichier avec plus de 10000 lignes, l'erreur à de grande chance d'arriver.

    Je me doutais bien que garbage collector était en cause.... Je fais le tour de tout mes sqlcommands pour mettre le dispose.

    EDIT: malgré l'ajout des dispose et un ptit GC.Collect() pour tester, je rencontre toujours le même problème.
    Je ne comprends vraiment pas ce message d'erreur car j'ai recherché dans tout mon projet "ExecuteReader", il n'est pas utilisé. Pourquoi j'ai cette erreur ça me rend dingue...

    Voici le stack stace:
    System.InvalidOperationException: There is already an open DataReader associated with this Command which must be closed first.
    at System.Data.SqlClient.SqlInternalConnectionTds.ValidateConnectionForExecute(SqlCommand command)
    at System.Data.SqlClient.SqlConnection.ValidateConnectionForExecute(String method, SqlCommand command)
    at System.Data.SqlClient.SqlCommand.ValidateCommand(String method, Boolean async)
    at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite)
    at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
    at AccesSQL.Executer(CommandType type, String texteSql, Boolean tracerLog, Boolean RecupererParametre, Object[] valeurs)
    --- End of inner exception stack trace ---
    at AccesSQL.Executer(CommandType type, String texteSql, Boolean tracerLog, Boolean RecupererParametre, Object[] valeurs)
    at AccesSQL.Executer(CommandType type, String texteSql, Object[] valeurs)
    at TransfererFichier() in E:Fichier.vb:line 128

  15. #15
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    avril 2007
    Messages
    12 843
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : avril 2007
    Messages : 12 843
    Points : 23 126
    Points
    23 126

    Par défaut

    Le message d'erreur me semble clair, un datareader n'a pas été closed
    Je pense donc que le problème est dans la méthode récupérertable
    (et aussi du fait que tu dois n'utiliser qu'une connexion pour toutes les requêtes)
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  16. #16
    Rédacteur/Modérateur

    Avatar de François DORIN
    Homme Profil pro
    Consultant informatique
    Inscrit en
    juillet 2016
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : juillet 2016
    Messages : 1 415
    Points : 4 773
    Points
    4 773
    Billets dans le blog
    5

    Par défaut

    Citation Envoyé par KyoshiroKensei Voir le message
    même plantage à l'instant. A priori, dès que je rencontre un fichier avec plus de 10000 lignes, l'erreur à de grande chance d'arriver.

    Je me doutais bien que garbage collector était en cause.... Je fais le tour de tout mes sqlcommands pour mettre le dispose.

    EDIT: malgré l'ajout des dispose et un ptit GC.Collect() pour tester, je rencontre toujours le même problème.
    Je ne comprends vraiment pas ce message d'erreur car j'ai recherché dans tout mon projet "ExecuteReader", il n'est pas utilisé. Pourquoi j'ai cette erreur ça me rend dingue...

    Voici le stack stace:
    System.InvalidOperationException: There is already an open DataReader associated with this Command which must be closed first.
    at System.Data.SqlClient.SqlInternalConnectionTds.ValidateConnectionForExecute(SqlCommand command)
    at System.Data.SqlClient.SqlConnection.ValidateConnectionForExecute(String method, SqlCommand command)
    at System.Data.SqlClient.SqlCommand.ValidateCommand(String method, Boolean async)
    at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite)
    at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
    at AccesSQL.Executer(CommandType type, String texteSql, Boolean tracerLog, Boolean RecupererParametre, Object[] valeurs)
    --- End of inner exception stack trace ---
    at AccesSQL.Executer(CommandType type, String texteSql, Boolean tracerLog, Boolean RecupererParametre, Object[] valeurs)
    at AccesSQL.Executer(CommandType type, String texteSql, Object[] valeurs)
    at TransfererFichier() in E:Fichier.vb:line 128
    Alors, tout d'abord, ne jamais, jamais au grand jamais appeler la méthode GC.Collect() manuellement. Bon, j'exagère un peu, mais c'est que dans 99.9% des cas, c'est mal fait et contre productif ! Le ramasse miette se déclenche tout seul et il est inutile de chercher à le déclencher manuellement. J'insiste sur ce fait car en voulant déclencher manuellement le ramasse miette, on peut arriver à faire le contraire : que des objets ne soient plus du tout recyclés !


    Pol63 a raison, il doit y avoir un accès via un DataReader qui se fait quelque part. Que contient la méthode RecupererParametre ?
    François DORIN
    Consultant informatique : conception, modélisation, développement (C#/.Net et SQL Server)
    Site internet | Profils Viadéo & LinkedIn
    ---------
    Page de cours : fdorin.developpez.com
    ---------
    N'oubliez pas de consulter la FAQ C# ainsi que les cours et tutoriels

  17. #17
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    juin 2011
    Messages
    48
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations professionnelles :
    Secteur : Industrie

    Informations forums :
    Inscription : juin 2011
    Messages : 48
    Points : 16
    Points
    16

    Par défaut

    Bonjour,

    Oui pour le GC collect, c'était un ptit test. La connexion est ouverte lors du lancement du service et fermée lors de l'arret de celui ci.
    Le plantage survient à l'exécution d un ExecuteNonQuery. IL n'y a donc pas de reader pour moi.

    Le code demandé ci dessous:


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
     
     Private Sub RecupererParametre(ByRef commande As SqlCommand, ByVal tracerLog As Boolean)
     
                Dim listeParametre As String = ""
     
                Try
     
                    'Si la procedure n'est pas dans le cache
                    If Not mCache.ContainsKey(commande.CommandText) Then
                        Dim tmpCommande As New SqlCommand(commande.CommandText, commande.Connection)
                        tmpCommande.CommandType = CommandType.StoredProcedure
                        'Recuperation des parametres de la procedure
                        SqlCommandBuilder.DeriveParameters(tmpCommande)
                        'Si le cache est dispo
                        If CacheEstDisponible Then
                            'On ajoute les parametres de la procedure
                            mCache.Add(tmpCommande.CommandText, tmpCommande.Parameters)
                        End If
                    End If
     
                    'Si le cache est dispo
                    If CacheEstDisponible Then
                        'Liste des parametres de la procedure
                        Dim oParametres As SqlParameterCollection = Nothing
                        'On recupere les parametres du cache pour la procedure
                        oParametres = CType(mCache(commande.CommandText), SqlParameterCollection)
     
                        'Pour chaque parametre
                        Dim oParametre As SqlParameter
                        For Each oParametre In oParametres
                            'On crée un nouveau parametre pour la commande
                            Dim oNouveauParam As New SqlParameter
                            With oNouveauParam
                                .ParameterName = oParametre.ParameterName
                                .DbType = oParametre.DbType
                                .Size = oParametre.Size
                                .Direction = oParametre.Direction
                            End With
     
                            If tracerLog Then
                                If listeParametre <> "" Then
                                    listeParametre &= ", "
                                End If
                                listeParametre &= oParametre.ParameterName
                            End If
     
                            'On l'ajoute à la commande
                            commande.Parameters.Add(oNouveauParam)
                        Next
                    End If
     
     
                    If tracerLog Then
                        RaiseEvent TraceChange(Me, _
                                                 New ApplicationEventArgs(MethodBase.GetCurrentMethod, _
                                                                          Nothing, _
                                                                          "Récupération des paramètres de la procedure terminée. (" & commande.CommandText & " - " & commande.Parameters.Count & " paramètres - " & listeParametre & ").", _
                                                                          TypeTrace.Debug, _
                                                                          TypeAffichage.Aucun))
                    End If
     
                Catch ex As InvalidOperationException
     
                    'Leve une exception pour l'appelant
                    Throw New ApplicationErreur("La récupération des paramètres de la procédure a échouée. (" & commande.CommandText & " - " & commande.Parameters.Count & " paramètres - " & listeParametre & ")", _
                                                ex, _
                                                TypeTrace.Grave, _
                                                TypeAffichage.Bandeau, _
                                                "")
     
                End Try
     
     
            End Sub
    Et voici le code de recuperertable:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
         Dim mCommande As SqlCommand = Nothing
                Dim mAdapter As SqlDataAdapter = Nothing
     
                Try
                    Select Case type
                        Case CommandType.Text
                            'Création d'une nouvelle commande
                            mCommande = CreerRequete(texteSql, tracerLog)
     
                        Case CommandType.StoredProcedure
                            'Création d'une nouvelle commande
                            mCommande = CreerCommande(texteSql, tracerLog, valeurs)
     
                    End Select
     
                    'Création de l'adaptateur de données
                    mAdapter = New SqlDataAdapter(mCommande)
     
                    'Recuperation des donnees
                    RecupererDonnees = New DataSet
     
                    mAdapter.Fill(RecupererDonnees, nomTable)
     
                    If RecupererParametre Then
                        'Recuperation des parametres
                        mParametres = mCommande.Parameters
                    End If
     
                    'fermeture de la commande afin d'etre sur de le detruire rapidement.
                    mCommande.Dispose()
     
                    'Indique la fin de l'execution de la requete
                    'GestionErreur.EnvoyerMessage(Me, MethodBase.GetCurrentMethod, "Execution de la requête terminée. (" & texteSql & ")")
                    If tracerLog Then
                        RaiseEvent TraceChange(Me, _
                                                 New ApplicationEventArgs(MethodBase.GetCurrentMethod, _
                                                                          Nothing, _
                                                                          "Execution de la requête terminée. (" & texteSql & ").", _
                                                                          TypeTrace.Debug, _
                                                                          TypeAffichage.Aucun))
                    End If
     
                Catch ex As Exception
     
                    'Leve une exception pour l'appelant
                    Throw New ApplicationErreur("L'execution de la requête a échouée. (" & texteSql & ")", _
                                                ex, _
                                                TypeTrace.Grave, _
                                                TypeAffichage.Bandeau, _
                                                "")
     
                Finally
     
                    If Not mAdapter Is Nothing Then
                        mAdapter.Dispose()
                    End If
                    mAdapter = Nothing
     
                End Try

  18. #18
    Rédacteur/Modérateur

    Avatar de François DORIN
    Homme Profil pro
    Consultant informatique
    Inscrit en
    juillet 2016
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : juillet 2016
    Messages : 1 415
    Points : 4 773
    Points
    4 773
    Billets dans le blog
    5

    Par défaut

    2 choses :
    • quel est le code de SqlCommandBuilder.DeriveParameters (et de toutes les fonctions nécessaires pour voir l'interaction avec la base de données) ?
    • l'instance de SqlCommand n'est pas correctement gérée (pas d'appel à la méthode Dispose).
    François DORIN
    Consultant informatique : conception, modélisation, développement (C#/.Net et SQL Server)
    Site internet | Profils Viadéo & LinkedIn
    ---------
    Page de cours : fdorin.developpez.com
    ---------
    N'oubliez pas de consulter la FAQ C# ainsi que les cours et tutoriels

  19. #19
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    juin 2011
    Messages
    48
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations professionnelles :
    Secteur : Industrie

    Informations forums :
    Inscription : juin 2011
    Messages : 48
    Points : 16
    Points
    16

    Par défaut

    - DeriveParameters est une fonction du framework .net dans System.Data.SqlClient.SqlCommandBuilder.
    -> via sql profiler on voit une demande à sql des paramètres d'entrées d'une procédure stockée. Cela est fait uniquement si la procédure n'a jamais été utilisé par le programme appelant. En effet, après la première exécution, les parametres de la procédure sont mis en cache afin d'être réutilisés.

    - RecupererParametre est appelé par la méthode CreerCommande elle meme appelé dans le code fourni. Les méthodes appelant CreerCommande font le dispose de l'objet SQLCommand. Ce ne serait pas suffisant, c'est bien ça?

    Le code de CreerCommande:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
     
            Private Function CreerCommande(ByVal nomProcedure As String, _
                                           ByVal tracerLog As Boolean, _
                                           ByVal ParamArray valeurs As Object()) As SqlCommand
     
                Try
     
                    CreerCommande = New SqlCommand
     
                    'Création d'une nouvelle commande
                    With CreerCommande
                        .Connection = mConnexion
                        .CommandText = nomProcedure
                        .CommandType = CommandType.StoredProcedure
                        .CommandTimeout = mExecutionTimeOut
                        .Parameters.Clear()
                    End With
                    'Recuperation des parametres de la procedure
                    Me.RecupererParametre(CreerCommande, tracerLog)
     
     
                    'Si on a des valeurs
                    If valeurs.Length > 0 Then
     
                        'Met a jour les valeurs des parametres
                        Me.MettreAJourParametre(CreerCommande, tracerLog, valeurs)
                    End If
     
                Catch ex As Exception
     
                    'Leve une exception pour l'appelant
                    Throw New ApplicationErreur("La création de la commande a échouée. (" & nomProcedure & ")", _
                                                ex, _
                                                TypeTrace.Grave, _
                                                TypeAffichage.Bandeau, _
                                                "")
     
                End Try
     
            End Function

  20. #20
    Rédacteur/Modérateur

    Avatar de François DORIN
    Homme Profil pro
    Consultant informatique
    Inscrit en
    juillet 2016
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : juillet 2016
    Messages : 1 415
    Points : 4 773
    Points
    4 773
    Billets dans le blog
    5

    Par défaut

    Citation Envoyé par KyoshiroKensei Voir le message
    - DeriveParameters est une fonction du framework .net dans System.Data.SqlClient.SqlCommandBuilder.
    Mea culpa, j'ai lu trop vite ! Ce qui est bien, c'est que je ne connaissais pas DeriveParameters (je n'en ai jamais eu besoin non plus !). Et comme j'avais lu "DeriveParametres" (en français donc), je ne m'étais pas posé la question de savoir si cela faisait parti du Framework .Net ou pas


    Citation Envoyé par KyoshiroKensei Voir le message
    - RecupererParametre est appelé par la méthode CreerCommande elle meme appelé dans le code fourni. Les méthodes appelant CreerCommande font le dispose de l'objet SQLCommand. Ce ne serait pas suffisant, c'est bien ça?
    Effectivement, ce n'est pas suffisant. Il faut appeler la méthode Dipose dès lors que l'object n'est plus nécessaire. Il en manque donc un dans RecupererParametre, qui instancie un objet SqlCommand si le cache n'existe pas.
    François DORIN
    Consultant informatique : conception, modélisation, développement (C#/.Net et SQL Server)
    Site internet | Profils Viadéo & LinkedIn
    ---------
    Page de cours : fdorin.developpez.com
    ---------
    N'oubliez pas de consulter la FAQ C# ainsi que les cours et tutoriels

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Appels de procedures stockées dans une proc stockée ?
    Par Nadaa dans le forum MS SQL-Server
    Réponses: 12
    Dernier message: 17/07/2008, 11h32
  2. executer une procedure stockées dans une requete SELECT
    Par bleuerouge dans le forum MS SQL-Server
    Réponses: 1
    Dernier message: 08/08/2006, 18h23
  3. Réponses: 2
    Dernier message: 22/06/2006, 12h26
  4. Réponses: 2
    Dernier message: 24/03/2006, 10h55
  5. Réponses: 3
    Dernier message: 21/09/2004, 08h35

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo