52 messaggi dal 22 luglio 2007
Buongiorno a tutti...
Ho il seguente problema, probabilmente perche' il mio cervello e' arrivato.

In asp scrivevo:
Set DBConn = Server.CreateObject("ADODB.Connection") 
DBConn.Open MM_Connection1_STRING
myQuery = "SELECT * FROM TABELLA WHERE Chiave LIKE '" & Parametro & "'"    
Set rs1=DBConn.Execute(myQuery)
if Not(Rs1.Eof) then
   Record=Rs1.getrows()
   TotalRecords=UBound(Record,2)+1
else    
   Response.Write("<br><br>Attenzione!<br><br>Nessun dato trovato in archivio")
   Record = ""
   TotalRecords = 0
end if

E poi mi gestivo l'array da codice. In asp.net non mi ritrovo piu'.
Sono due giorni che ci sbatto la testa e non ne esco.
Una mano?

Grazie
11.886 messaggi dal 09 febbraio 2002
Contributi
Luca.1967 ha scritto:
In asp.net non mi ritrovo piu'.


Ciao, casomai posta il codice che hai scritto, così possiamo valutare cosa mancava per arrivare alla soluzione. Pochi giorni fa un altro utente ha inviato una richiesta simile alla tua, magari ti può essere d'aiuto.
http://forum.aspitalia.com/forum/post/387072/Contare-Record-Tabella.aspx

Luca.1967 ha scritto:

Sono due giorni che ci sbatto la testa e non ne esco.
Lo so, non è semplice fare il salto da ASP classico as Asp.Net. Alla fine, se ancheriesci a "convertire" il codice in Asp.Net, è probabile che non avrai sfruttato le nuove funzionalità che in Asp classico non avevi. Il DataBinding, ad esempio, ti fa risparmiare un bel po' di tempo quando devi visualizzare i dati all'utente e ti aiuta anche a separare la presentazione dei dati all'utente dal codice necessario all'ottenimento degli stessi.
Anziché procedere a tentativi, affidati ad un libro che ti farà apprendere in maniera metodica il funzionamento di Asp.Net. Ci sono tante nuove cose da imparare e se decidi di investire un po' del tuo tempo nell'apprendimento della tecnologia, ben presto ti accorgerai di essere in grado di sviluppare molto più velocemente di quanto non ti fosse possibile con l'Asp classico.

ciao

Enjoy learning and just keep making
52 messaggi dal 22 luglio 2007
Scusa per il ritardo...
Spiego meglio quello che voglio fare, perche' e l'ambiente.

Il tutto adesso funziona cosi':

Ho due tabelle la tabella "Categorie" e la tabella "Dettagli". Ovviamente il join sarebbe di tipo uno a molti.
Quello che faccio ora e':

Apro la connessione
Apro ciclo While 1
Tramite OledbDatareader ("DR1") leggo un record dalla tabella "Categorie"
Visualizzo il campo "Categorie.Descrizione"
Apro ciclo While 2
Tramite un nuovo Oledbdatareader ("DR2") leggo un record dalla tabella Dettagli correlato alla categoria appena letta
Visualizzo il campo "Dettagli.DescrizioneDettaglio"
Chiudo Ciclo While 2
Chiudo DR2
Chiudo Ciclo While 1
Chiudo DR1
Chiudo la connessione

E tutto funziona bene.
Il problema si verifica soprattutto con connessioni troppo lente (o non so con cosa).
A volte non chiude i Datareader ed il sito va in errore

Ho pensato quindi che se riuscissi a caricare tutti i record in memoria, almeno quelli delle categorie, e lavorare da codice forse potrei ridurre i tempi di accesso al db e risolvere cosi' il problema, anche se non sembra essere quello il problema.

Sto su piattaforma server Windows, con framework 3.5, su Aruba.

Se serve posto un po' di codice (dovro' abbreviare alcune parti) ma non c'e' molto di diverso da cio' che ho scritto.

Il mio problema a questo punto e': come faccio a riportare in asp .net quelle semplicissime righe asp?
Sono andato a vedere quel link alla discussione precedente ma non e' che ci abbia capito moltissimo :(
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao,
penso che si possa risolvere il problema inviando un solo comando al database: una JOIN tra Categorie e Dettagli.

Il sistema che hai proposto non è il migliore in termini di efficienza perché ti costringe ad inviare tanti comandi al database. Un comando iniziale per ottenere le categorie e poi tanti altri per recuperare il dettaglio di ciascuna categoria. Giusto a titolo informativo, questo è noto come il problema SELECT N+1, di cui puoi leggere qui.

In più c'è un'altra questione: non è possibile tenere aperti 2 DataReader contemporaneamente sullo stesso oggetto Connection, otterresti un'eccezione (<- non è sempre vero ma ora è irrilevante).


Quindi, puoi risolvere entrambi questi problemi con una JOIN. Ecco un esempio di query che potrebbe fare al caso tuo:

SELECT Categorie.IDCategoria, Categorie.Descrizione, Dettagli.DescrizioneDettaglio FROM Categorie LEFT JOIN Dettagli ON Categorie.IDCategoria=Dettagli.IDCategoria
Il risultato che otterresti da una query del genere è una cosa tipo questa:

IDCategoria | Descrizione | DescrizioneDettaglio
1 | Frutta | Ciliegie
1 | Frutta | Pesche
1 | Frutta | Albicocche
2 | Pasta | Spaghetti
2 | Pasta | Tagliatelle
3 | Dolci | Tiramisù


Riuscirai a risolvere il problema leggendo i dati da quest'unico insieme.

Luca.1967 ha scritto:

Sono andato a vedere quel link alla discussione precedente ma non e' che ci abbia capito moltissimo :(
Fa niente, provo ad usare gli oggetti OleDbConnection e OleDbDataReader che già conosci. I commenti dovrebbero spiegare cosa fa ciascuna riga di codice.

'Creo la connessione
Using conn As New OleDbConnection("TuaConnectionString")
    'la apro
    conn.Open()

    'definisco la mia query: è una JOIN tra categorie e dettagli
    Dim query As String = "SELECT Categorie.IDCategoria, Categorie.Descrizione, Dettagli.DescrizioneDettaglio FROM Categorie LEFT JOIN Dettagli ON Categorie.IDCategoria=Dettagli.IDCategoria"
    'creo l'oggetto che invierà la query al database
    Using comando As New OleDbCommand(query, conn)

        'eseguo il comando, mi restituisce un datareader
        Using reader = comando.ExecuteReader()

            'mi creo una variabile che contiene l'id dell'ultima categoria da cui sono passato
            'all'inizio sarà 0
            Dim categoriaLetta As Integer = 0
            'inizio il ciclo while per leggere i records dal datareader
            While reader.Read()

                'se la categoria corrente è diversa dall'ultima che ho letto...
                If categoriaLetta <> reader("IDCategoria") Then
                    '...ne stampo la descrizione...
                    Response.Write(reader("Descrizione"))
                    '...e aggiorno la variabile categoriaLetta con l'ID della categoria corrente
                    categoriaLetta = reader("IDCategoria")
                End If

                'infine stampo la descrizione del dettaglio.
                Response.Write("<br /> - " & reader("DescrizioneDettaglio"))

            End While
        End Using
    End Using
End Using
Ricorda di racchiudere sempre le istanze di connessioni e datareader in un blocco Using! Se anche si dovesse verificare un'eccezione, almeno questo costrutto fa il Dispose sull'oggetto, impedendo che resti aperto anche in caso di errore.

ciao
Modificato da BrightSoul il 06 febbraio 2012 21.22 -

Enjoy learning and just keep making
52 messaggi dal 22 luglio 2007
Ciao, rieccomi.
Allora... Il tuo suggerimento e' perfetto e lo uploadero' (come non mi piacciono questi termini) stasera. In locale funziona che e' una meraviglia.

Solo una cosa non capisco.
Per evitare che rimanga appeso qualcosa, in caso di errore, io faccio cosi':
IDCategoria=0
Try
   cmd1.CommandText = SQL_Query
   cmd1.Connection = CommonCode.ConnessioneTLCLMC
   cmd1.Connection.Open()
   DataReader = cmd1.ExecuteReader
   While DataReader.Read()
      If IDcategoria <> DataReader("IDcategoria") Then
         Response.Write("<tr>")
         Response.Write("<td colspan='2' align='left'>")
         Response.Write(DataReader("Area"))
         Response.Write("</td>")
         Response.Write("</tr>")
         IDCategoria = DataReader("IDCategoria")
      End If
      Response.Write("<tr>")
      Response.Write("<td align='left' width='10'>")
      Response.Write("</td>")
      Response.Write("</tr>")
      Response.Write("<tr>")
      Response.Write("<td align='left' >")
      Response.Write(DataReader("Dettaglio"))
      Response.Write("</td>")
      Response.Write("</tr>")
   End While
   Response.Write("</table>")
   DataReader.Close()
Catch ex As Exception
   Call CommonCode.LogErrore(parametri vari, ex.ToString)
   Response.Redirect("~" & "/GestioneErrore.aspx")
Finally
   cmd1.Connection.Close()
End Try

La domanda e':
qual'e' la differenza tra l'utilizzo di try ed il costrutto Using?
Se io ponessi un cmd1.dispose dopo la chiusura della connessione sarebbe meglio?

Grazie
11.886 messaggi dal 09 febbraio 2002
Contributi
bene :)

Luca.1967 ha scritto:

lo uploadero' (come non mi piacciono questi termini) stasera

noo, non lo uploadare... "pubblicalo"!

Luca.1967 ha scritto:

Per evitare che rimanga appeso qualcosa, in caso di errore, io faccio cosi':

ok, in linea teorica va bene perché avvolgi tutto in un blocco Try...Catch...Finally e fai il lavoro di "pulizia" nel Finally, ma il codice non è completo.

Luca.1967 ha scritto:

Se io ponessi un cmd1.dispose dopo la chiusura della connessione sarebbe meglio?

Sì, e non solo sul cmd1 andrebbe chiamato.
Chiamare il .Close sulla Connessione o sul DataReader non basta, devi anche chiamare il loro metodo .Dispose() che dà istruzione al Garbage Collector di liberare l'area di memoria precedentemente occupata da quelle istanze.
In realtà il Close() è superfluo perché se con un reflector guardi l'implementazione del metodo Dispose() ti accorgi che esso stesso invoca Close().

Il blocco Using serve per snellire un po' il codice e per aiutarti a "tenere pulito" quando hai a che fare con classi che implementano IDisposable, cioè quasi tutte quelle che usi più comunemente dal namespace System.Data.OleDb.
OleDbConnection, OleDbDataReader, OleDbCommand: tutte queste dovrebbero essere inserite in un proprio blocco Using.
Se lo fai, non devi più ricordarti di chiamare il Dispose perché ci penserà il compilatore a generarti la chiamata nella porzione Finally di un blocco Try...Finally creato da lui.

Se guardi il codice compilato trovi conferma di questo. Del blocco Using, dopo la compilazione, non resta traccia.

Se scrivi questo:
Using conn As New SqlConnection("connString")
  conn.Open()
End Using


Ti verrà compilato come se avessi scritto:
Try
    conn.Open()
Finally
    If Not conn Is Nothing Then CType(conn, IDisposable).Dispose()
End Try


ciao
Modificato da BrightSoul il 07 febbraio 2012 20.57 -

Enjoy learning and just keep making
52 messaggi dal 22 luglio 2007
Perfetto.
Una risposta esaustiva e chiarissima.

Solo una domanda ancora... Come avrai visto dal codice, utilizzando il try/catch/finally intercetto l'errore e lo invio ad una sub che poi scrivera' un log ed eseguo un reindirizzamento ad una pagina che informa l'utente dell'errore e rimanda in homepage. Con il blocco Using ho modo di intercettarlo lo stesso e di rinviare ad una pagina ben precisa?

Ho "pubblicato"

:)

Ciao.

Luca
11.886 messaggi dal 09 febbraio 2002
Contributi
ciao,

Luca.1967 ha scritto:
Con il blocco Using ho modo di intercettarlo lo stesso e di rinviare ad una pagina ben precisa?


No, devi comunque creare un blocco Try...Catch al suo interno perché il blocco Using, di per sé, non cattura le eccezioni (infatti è solo un Try...Finally, manca il Catch).

Detta così sembra che non ci siano sufficienti motivi per preferire il blocco Using ma, in realtà, il suo scopo è differente da un Try...Catch.

Lo Using risponde alla specifica necessità di liberare le risorse al termine del loro uso, anche se si dovesse verificare un errore di qualsiasi natura.

Il Try...Catch invece risponde alla necessità di eseguire del codice alternativo, che tenti di sistemare la situazione quando si verifica un'eccezione prevedibile.

Che vuol dire "prevedibile"? Ad esempio, se invoco conn.Open() mi aspetto di ricevere una DbException se il database per un qualche motivo non fosse raggiungibile. Quindi il Try...Catch andrebbe messo attorno a questa specifica istruzione allo scopo di provare a recupare una situazione problematica. Per esempio, potrei lasciar passare un secondo e riprovare di nuovo a chiamare conn.Open(). Per "recuperare" non intendo reindirizzare l'utente ad una pagina di errore, ma proprio provare a ristabilire il normale corso dell'esecuzione di pagina.
Poi, beh, se dopo ripetuti tentativi non dovessi riuscire a risolvere il problema, allora lascio che l'eccezione si propaghi. Anzi, magari ne sollevo una io stesso incapsulando quella originale dentro la proprietà InnerException.

Luca.1967 ha scritto:

utilizzando il try/catch/finally intercetto l'errore e lo invio ad una sub che poi scrivera' un log ed eseguo un reindirizzamento ad una pagina che informa l'utente dell'errore e rimanda in homepage

Questo certamente puoi farlo ma secondo me il logging non è tra gli scopi di un blocco Try...Catch. Anche perché, pensaci, in vari punti della tua applicazione devi fare il copia-incolla dello stesso pezzo di codice che ti invoca il CommonCode.LogErrore.
E se ti dimentichi di mettere il Try...Catch in un punto che non pensavi ti potesse sollevare un eccezione? Non verrebbe loggata. Una OutOfMemoryException può capitare ovunque.

Loggare gli errori è un cross-cutting concern funzionalità trasversale che interessa tutte le parti del tuo codice e che perciò dovresti centralizzare in modo da occupartene solo una volta e poi mai più.

Ad esempio, per reindirizzare gli utenti quando si verifica un errore, Asp.net ti mette a disposizione l'elemento <customErrors> del web.config. Qui trovi un esempio, ti è sufficiente indicare il percorso ad una pagina html (preferibilmente) che l'utente vedrà quando si verifica un errore non gestito.
http://msdn.microsoft.com/it-it/library/h0hfz6fc%28v=vs.80%29.aspx

Invece, per il logging dell'errore esistono altre possibilità. Una eccellente, ad esempio, è impiegare ELMAH, una libreria che si occupa proprio di questo.

In alternativa, se hai già in piedi il tuo sistema di logging e vuoi continuare ad usare quello, puoi aggiungere un metodo Application_Error al tuo global.asax e ti verrà chiamato ogni volta che si verifica un errore. Qui trovi un articolo che ne parla. All'interno del metodo avrai accesso a tutti i dettagli dell'eccezione e potrai decidere di loggarla usando il tuo CommonCode.LogErrore.
http://www.aspitalia.com/script/376/Intercettare-Errori-Pagine-ASP.NET-Global.asax.aspx

ciao!
Modificato da BrightSoul il 08 febbraio 2012 20.20 -

Enjoy learning and just keep making

Torna al forum | Feed RSS

ASPItalia.com non è responsabile per il contenuto dei messaggi presenti su questo servizio, non avendo nessun controllo sui messaggi postati nei propri forum, che rappresentano l'espressione del pensiero degli autori.