Newsgroup: it.comp.appl.access
Titolo: Function as ADODB.Recordset

Un saluto a tutti,
è ormai qualche anno che non scrivo più nulla di serio in vba a mi sento 
piuttosto arrugginito, quindi spero che qualcuno possa aiutarmi a capire 
questo:
database MSSQL2000 sp4
access 2000
progetto ADP da trasformare in ADE
aggiungo un modulo
creo una funzione che ritorna un ADODB.Recordset
al suo interno definisco un nuovo ADODB.Recordset_TMP
carico nel recordset_TMP i dati filtrati secondo alcuni valori passati 
come argomenti della funzione
carico il recordset_TMP nella funzione valorizzandola col risultato 
funzione=recordset_TMP.CLONE
chiudo ed elimino il recordset_TMP
esco dalla funzione
Ora mi è venuto questo dubbio:
se la funzione altro non è che il recordset_TMP clonato,
dopo averla utilizzata come origine dati, come faccio per eliminarla?
In un recordset normale mi aspetto un CLOSE ed un NOTHING ma essendo una 
funzione non credo che sia possibile.
Vorrei capire dove sbaglio.
Grazie
-- 
Claudio(BS)
NB. Protezione antispam
Per rispondere aggiungere claudio

 Grazie
Ciao!
*Se* ho capito bene:
private sub FunzioneLocale
    dim rsLocale as ADODB.Recordset
    IstanziaRecordSet rsLocale
    rslocale.Close
   set rslocale=nothing
end sub
public function IstanziaRecordSet(ByRef rsEsterno as ADODB.Recordset)
    set rsEsterno=openRecordset(...)
end function
HTH
Popi

 Popi
Forse allora non serve fare il clone, ok grazie del suggerimento, provo 
a vedere se cosě riesco ad ottenere qualcosa.
Buon fine settimana e grazie ancora.
Cla

 wrote:

Claudio... a prescindere dalla risposta corretta che ti è stata
data... che sfrutta il ByRef, ma non mi pare rispondere alla tua
domanda.... potresti chiarirmi il tuo dubbio con la funzione di cui
parli.... perchè io sono uso a scrivere Classi che restituiscono
OGGETTI e, nella logica OOP è assurdo semplificare la questione che
hai posto con
l'uso del ByRef, pursempre valido ma decisamente riduttivo come
filosofia di costruzione.
@Alex

 filosofia di costruzione.
Ciao Alex,
Quando fai così mi fai *paura* .... perché mi viene il dubbio di non
aver capito una beneamata mazza!!! :)
La sua domanda era relativa a come distruggere un oggetto dichiarato
ed istanziato da una funzione, mentre tu parli di classi e, per quel
poco che ne so (e passami la terminologia "inadeguata"), una classe
prevede meccanismi di "costruzione" e "distruzione" degli oggetti
gestiti.
Cioè (sempre se ho capito bene):
Dim MioOggetto as MiaClassePrivata
serve per istanziare la classe
set MioOggetto = new MiaClassePrivata
MioOggetto.Proprietà1=""
MioOggetto.Proprietà2=0
MioOggetto.EseguiMetodo
crea l'oggetto, ne imposta le proprietà ed esegue metodi specifici,
mentre
set MioOggetto = Nothing
distrugge l'oggetto (l'istanza della classe).
*SE* ho capito bene lo scenario prospettato da Claudio è molto più
light, dato che deve solo creare un oggetto (cioè istanziare la classe
già esistente ADODB) senza definirne una nuova che la richiami.
In soldoni: dove sbaglio?
Roberto


Non sbagli nulla... ma non capsico dove sia il problema nell'usare una
Function che restituisce un'oggetto...!
Public Function GetRS(param1 as ..., param2 as ...) As ADODB.Recordset
    Dim rs As Adodb.Recordset
    Set rs=......
    Faccio tutte le mie pippe....
    Set GetRS=rs
    rs.Close
    Set rs=nothing
End Function
Come la uso...?
Da qualsiasi parte del codice dichiaro un'oggetto magari senza
approfittare del Casting dei dati:
Dim rs as ADODB.Recordset...
Set rs=GetRS(.....)
alla fine chiudo e distruggo rs...
Questo il motivo per il quale non capisco la domanda...!
@Alex

 Questo il motivo per il quale non capisco la domanda...!
Questo il motivo per il quale non capivo la risposta, ma ora ne ho
(abbiamo) imparata un'altra!
Thanks!
Popi

 Popi
Ciao
@Alex


Ah ... allora intanto faccio due prove io.
Usando DAO il codice qua sotto va in errore 3240 (Oggetto non valido o
non impostato.) sulla debug.print.
Public Sub aaa()
    Dim rsesterno As DAO.Recordset
    Set rsesterno = aaars("SELECT * FROM Costruttori;")
    Debug.Print rsesterno.Fields(0), rsesterno.Fields(1)
    rsesterno.Close
    Set rsesterno = Nothing
End Sub
Private Function aaars(ByRef stringasql As String) As DAO.Recordset
    Dim rsinterno As DAO.Recordset
    Set rsinterno = CurrentDb.OpenRecordset(stringasql)
    Set aaars = rsinterno
    rsinterno.Close
    Set rsinterno = Nothing
End Function
Dato, però, che si parlava di ADODB (che fin'ora non ho mai usato),
provo anche il codice sotto ... che segnala errore 3704 (L'operazione
non è consentita se l'oggetto è chiuso.) sempre sulla debug.print.
Public Sub aaado()
    Dim rsesterno As ADODB.Recordset
    Set rsesterno = aadors("SELECT * FROM Costruttori;")
    Debug.Print rsesterno.Fields(0), rsesterno.Fields(1)
    rsesterno.Close
    Set rsesterno = Nothing
End Sub
Private Function aadors(ByRef stringasql As String) As ADODB.Recordset
    Dim rsinterno As ADODB.Recordset
    rsinterno.Open stringasql, CurrentProject.Connection,
adOpenStatic, adLockOptimistic
    Set aadors = rsinterno
    rsinterno.Close
    Set rsinterno = Nothing
End Function
E se ho sbagliato qualche cosa ... stasera a casa mi aspetta il
secchio da 20 lt che uso per pulire il camino!!! :)))
Popi

Popi - TheBadHabits ha scritto:

Ciao a tutti e grazie per l'interesse,
premetto, come dicevo, che sono digiuno da qualche tempo di 
programmazione vba, e mentre scrivevo questa funzione mi è venuto il 
dubbio che io, da profano, stia facendo qualche cosa di sbagliato, ed ho 
chiesto.
La funzione si può riassumere come segue:
Function fnMIORS(stFILTRO As String) As ADODB.Recordset
     Dim cnDb As ADODB.Connection
     Dim rsTemp As ADODB.Recordset
     Set cnDb = CurrentProject.Connection
     Set rsTemp = cnDb.Execute("SELECT...ecc...WHERE...'" & 
Trim(stFILTRO) & "'", adOpenForwardOnly)
...
     Set fnMIORS = rsTemp.Clone
...
     rsTemp.Close
     Set rsTemp = Nothing
     Set cnDb = Nothing
End Function
L'intenzione sarebbe quella creare una funzione che mi restituisca un 
recordset da passare come tabella/query con filtro, all'origine dati di 
una casella di riepilogo contenuta in un sottoreport. NB.non sono 
affatto sicuro che si possa fare, è una prova ;)
Il mio dubbio è legato al fatto che in questa funzione creo e cancello 
il recordset temporaneo, e fin qui ok, ma prima di essere eliminato esso 
viene clonato e passato come risultato, e quindi *forse* non viene più 
chiuso, valorizzato ...boh.
Qualcosa non quadra, e dato che sentirsi ignoranti credo sia cosa 
fastidiosa per tutti, vorrei "illuminarmi" :)
Grazie
Claudio(BS)

Rispondo quì sia per Claudio che per Popi
Public Function RST() As DAO.Recordset
    Dim rs As DAO.Recordset
    Set rs = DBEngine(0)(0).OpenRecordset("T1")
    Set RST = rs.Clone
    rs.Close
    Set rs = Nothing
End Function
Questa funziona regolarmente e non restituisce alcun errore...!
;-)
Risponde alla domanda di Claudio ed ai dubbi di Popi quello che ho
risposto ...?
Fatemi sapere.
@Alex

 Questa funziona regolarmente e non restituisce alcun errore...!
Ecco, lo sapevo ... stasera mi faccio lo shampoo con il secchio del
camino: a differenza tua non usavo il metodo clone.
Direttamente dall'help del metodo clone.
L'utilizzo del metodo Close sull'oggetto originale o su quello
duplicato non influisce sull'altro oggetto. Se, ad esempio, si
utilizza il metodo Close sull'oggetto Recordset originale, non viene
chiuso l'oggetto duplicato.
Popi

@Alex ha scritto:

Porta pazienza Alex e scusami, ma temo di non aver ancora capito :(
Il fatto è che la tua funzione è simile alla mia a parte DAO, ed infatti 
anche la mia non dava errori, ma non mi è chiaro, poi, come fare a 
chiudere il collegamento al server per il risultato clonato.
Spiego:
Da quello che ho capito, e probabilmente a questo punto ho capito male, 
quando apro un recordset per una connessione del progetto, questo si 
collega al server sql e permette di utilizzare le query restituendo dati 
in forma tabellare, quindi con una connessione, modificando la stringa 
SQL e facendo requery posso gestire N situazioni.
Poi, quando non servono più i dati del recordset, basta eliminarlo e 
resta solo la connessione del progetto.
Quindi la base di partenza è:
1) connessione progetto (vuota)
2) connessione progetto + connessione recordset
Il dubbio che mi rimane è:
se inserisco il recordset in una funzione che restituisce il recordset 
clonato (non il recordset stesso perché uscendo dalla funzione poi 
darebbe errore), come faccio a chiudere la connessione del risultato?
Situazione di partenza:
1) connessione progetto
chiamo la funzione ed ottengo:
2) chiamata di funzione
3) connessione progetto + connessione recordset A + connessione recordset B
uscendo dalla funzione:
4) elimino la connessione recordset A e restituisco la connessione 
recordset B
Dopo il risultato dovrei rimanere con la situazione di partenza ed 
invece ho:
5) connessione progetto
6) connessione progetto + connessione recordset B
quindi al punto 4 uscendo dalla funzione ho ancora una connessione di 
troppo che al punto 6 non dovrebbe esistere e che di conseguenza non so 
come gestire.
Dubbio: chiamando ricorsivamente la funzione, non rischio di avere molte 
connessioni inutili? Tante connessioni = memoria sprecata.
Ora SO che sbaglio qualcosa...ma cosa?
Grazie

> Rispondo quė sia per Claudio che per Popi

Ecco il punto da dove sono partiti tutti i miei dubbi ... NON viene 
chiuso, quindi resta aperto ed essendo definito come una funzione temo 
che non sia pių possibile chiuderlo. :(

 che non sia più possibile chiuderlo. :(
Non direi.
Riprendendo l'esempio di Alex. la "Set RST = rs.Clone" fa ritornare
alla funzione il recordset clonato.
Tu, nel tuo codice, avrai una "Set rsLocale = RST(...)" in cui,
quindi, il tuo rsLocale conterrà il clone ritornato.
Dovrai, al termine delle tue elaborazioni, farla seguire da
"rsLocale.Close" e "Set rsLocale = Nothing" per chiudere il recordset
e distruggere l'oggetto.
*MUMBLE* .... qualcuno mi corregga ma .... è un po' come usare
CurrentDb o fare "Set MioDb = CurrentDb" e poi giocare con MioDb,
giusto?
HTH
Popi


Si io la interpreto esattamente come dici in quanto è semplicemente un
Casting all'oggetto...
Con access è presto detto fare una prova... basta andare a vedere il
FILE LDB.... se viene cancellato o meno...!
CANCELLATO=SI connessione chiusa
CANCELLATO=NO connessione aperta
@Alex

 Popi
Ecco l'altra cosa *strana* che avevo gi� notato durante le varie prove.
Non sono affatto obbligato a dichiarare un oggetto recordset per 
chiamare la funzione, posso benissimo collegarla ad una variabile long 
per restituire il numero dei records, ed in quel caso mi ritorna un 
valore ed io non ho niente per chiudere la connessione.
E' palese che sono completamente fuori strada, almeno concettualmente, 
ma non capisco da dove parte l'inghippo.
mmm...per�...per�...
domani mattina provo cos�
lnX = fnRS(stFILTRO).RecordCount
fnRS(stFILTRO).Close
non l'avevo ancora provato!!!
resta da vedere dove/come gestire l'istruzione
SET fnRS(stFILTRO)=nothing
Grazie e buona serata
Claudio(BS)

 Claudio(BS)
Ovvio che funziona.... l'oggetto è un RECORDSET... e come tale
supporta metodi e properties...!!!
Sono che così richiami la Funzione 3 volte e tecnicamente mi pare una
grossissima....................
L'unica prova che devi fare è quella che ti ho detto io....!
@Alex

 L'unica prova che devi fare � quella che ti ho detto io....!
In effetti anche a me "puzzava" :)
Claudio(BS)