none
VB2017 - Problema con una classe RRS feed

  • Domanda

  • Buongiorno a tutti,

    ho una function all’interno di una classe che riceve un numero di ordine e mi valorizza “n” campi.  Il ritorno della function è un data reader

    Tutto bene all’interno di essa, ma quando la richiamo mi dice

    System.InvalidOperationException: 'Tentativo non valido di chiamare CheckDataIsReady con reader chiuso.'

    Il codice di chiamata è :

    Dim reader As SqlDataReader
    
    Dim objcerco_odv As New cerco_odv
    
    reader = objcerco_odv.valorizzo_campi_odv(txtNrOdv.Text)
    tipo_odv = (reader.Item(0).ToString)	‘QUI ERRORE
    


    La function è la seguente :

    Public Function valorizzo_campi_odv(ByVal nr_odv As Long) As SqlDataReader
    
       Dim stringa_sql As String
            Dim cmd As New SqlCommand
            Dim reader As SqlDataReader
    
    stringa_sql = "SELECT des_tipo_odv, dt_odv, Agente_acq, Agente_seg, nome_cliente, desc_canale, desc_gav, desc_uv, ordine_acq, importo_netto, sconto, importo_netto_oth FROM tb_odv_testa "
            stringa_sql = stringa_sql + "Where nr_odv =" & nr_ordine
    
            Try
                objCnn.ConnectionString = My.Settings.Cnn_DB
                objCnn.Open()
                cmd = New SqlCommand(stringa_sql, objCnn)
    
                reader = cmd.ExecuteReader
                While reader.Read()
          
                    record_odv = reader		‘
                    articolo = (record_odv.Item(1).ToString)	‘QUI IL VALORE C’E’ 
                End While
    
                'reader.Close()
                'cmd.Dispose()
            Catch ex As Exception
                MessageBox.Show(ex.Message.ToString)
            End Try
    
            objCnn.Close()
            Return record_odv	
    
        End Function
    

    Perché il datareader è chiuso ? Sembra che non ritorni dalla function

    Grazie a tutti

    mercoledì 8 aprile 2020 15:56

Risposte

  • Il DataReader è chiuso perché hai chiuso la connessione, ed il DataReader vuole la connessione aperta.

    Come alternativa puoi dire al DataReader di chiudere la connessione quando chiuderai il DataReader stesso, e lo puoi fare passando il valore System.Data.CommandBehavior.CloseConnection come argomento del metodo Read

    In questo modo, puoi lasciare aperta la connessione nel tuo metodo di classe, quando avrai finito con il DataReader, ne chiami il metodo Close e questo chiuderà automaticamente la connessione.

    P.s., certo, ci sarebbe da discutere un po' su quel metodo di classe.

    mercoledì 8 aprile 2020 16:52

Tutte le risposte

  • Il DataReader è chiuso perché hai chiuso la connessione, ed il DataReader vuole la connessione aperta.

    Come alternativa puoi dire al DataReader di chiudere la connessione quando chiuderai il DataReader stesso, e lo puoi fare passando il valore System.Data.CommandBehavior.CloseConnection come argomento del metodo Read

    In questo modo, puoi lasciare aperta la connessione nel tuo metodo di classe, quando avrai finito con il DataReader, ne chiami il metodo Close e questo chiuderà automaticamente la connessione.

    P.s., certo, ci sarebbe da discutere un po' su quel metodo di classe.

    mercoledì 8 aprile 2020 16:52
  • Ciao, innanzitutto grazie.

    Togliendo la close adesso mi da l'errore

    Tentativo non valido di lettura in assenza di dati.'

    Sembra che fuori dal ciclo della read il datareader non sia più utilizzabile.

    Sul metodo di classe, sicuramente c'è da discutere, anzi se in questi giorni di quarantena hai tempo e voglia di suggerimenti, accetto più che volentieri  :-)

    giovedì 9 aprile 2020 10:37
  • Secondo me non hai ben chiaro come funziona il DataReader.

    Dalla query SQL che invii, posso supporre che hai una sola riga di ritorno, visto che usi una clausola Where su un numero d'ordine.

    Fai quindi un ciclo usando come condizione il valore restituito dal metodo Read del DataReader. Normalmente un ciclo si fa quando ci si aspetta, o comunque c'è la possibilità, di avere più righe.

    In ogni caso, ogni volta che chiami il metodo Read, per sua natura il DataReader si sposta alla riga successiva, considerando che la riga iniziale è un segnaposto e non contiene dati.

    Quindi, ammettiamo che una query restituisca (non credo sia il tuo caso) 3 righe, e le chiamiamo Riga1, Riga2, Riga3 (non usiamo l'indice in base 0 per non confonderci).

    Appena ottenuto il DataReader, lui si posiziona sulla riga 0, che è un segnaposto. Chiami il metodo Read una volta, questo metodo di restituisce True e il DataReader si posiziona su Riga1, leggi tutti i tuoi dati.

    Chiami di nuovo Read, restituisce True e il DR si posiziona su Riga2, ed anche ora puoi leggere i tuoi dati.

    Chiami ancora Read, restituisce True e DR si posiziona su Riga3....

    Ora, chiami Read, restituisce False (perché le righe sono finite) e il DR si posiziona su un segnaposto che è una riga vuota (per semplificare eh). Tu esci dal ciclo e fai restituire alla tua funzione, il DataReader, che è ancora fermo sulla posizione finale. Se a questo punto tenti di leggere di nuovo i dati dal DataReader, questo ti solleva l'eccezione che hai ricevuto tu, proprio perché è posizionato alla fine.

    Naturalmente, questo processo vale anche se la riga restituita è una sola, come penso che succeda a te.

    Ti anticipo la domanda... no, non puoi riposizionare il DataReader alla riga 0.

    Puoi quindi, a tua scelta...

    Usare un dataset

    Andare a leggere tutti i dati che ti servono nel ciclo, memorizzarli in tante istanze di una classe fatta come serve a te, chiudere il DataReader e dimenticarlo li, e far restituire alla tua funzione una lista di oggetti di tipo "tuaclasse"

    giovedì 9 aprile 2020 11:23
  • Spiegazione perfetta, grazie . Credo che farò un dataset, la seconda soluzione che mi proponi sarebbe perfetta ma non so proprio come fare . Come memorizzare in istanze ?

    Grazie mille per l'aiuto

    giovedì 9 aprile 2020 13:14
  • Se non hai idea di come creare istanze di una tua classe, è grave :)

    E' grave nel senso che non sfruttare la potenza delle classi, in un ambiente *basato* sugli oggetti, è come comprare una macchina e non saper usare il cambio. Cammini ugualmente, ma se usi solo la prima marcia, tanto in la non vai.

    Io ho iniziato con VB6, con un ambiente *orientato* ad oggetti, e visto che ero hobbista e qualcosa riuscivo a farla, non ho mai approfondito il discorso di classi, ed oggetti da queste istanziati; quando poi l'ho fatto, mi si è aperto un mondo. In ambiente Net, è praticamente d'obbligo, quindi avanti e studia :)

    Visto che si cambierebbe del tutto argomento, se ti dovesse servire, apri un nuovo thread, e troverai sicuramente qualcuno che ti aiuta a capire e sfruttare la potenzialità di classi e oggetti.

    giovedì 9 aprile 2020 14:12
  • Sono d'accordo, il problema è proprio quello di essere hobbista fai da te , no Alpitur ,  figurati che normalmente programmo per As400 … ed anche io non ho approfondito il discorso classi . E' proprio un concetto diverso da approcciare rispetto al mondo As. Mi metterò a studiare .

    Grazie per i consigli, sei stato molto utile

    Buona Pasqua

    giovedì 9 aprile 2020 15:21