Database in uso

Ciao a tutti, ho un problemino che non so come risolvere.
Applicazione Desktop, ambiente Windows.
L’applicazione A apre un SQLite Database e richiama l’applicazione B.
L’applicazione B scarica da un sito Internet una nuova versione del database e dovrebbe sostituire quello gi esistente (aperto dall’applicazione A).
Ovviamente il tentativo di cancellarlo d errore perch il file in uso.
Allora faccio in modo che l’applicazione A, prima di richiamare la B, chiuda il database…ma l’errore continua a persistere.
Non so pi cosa fare…qualcuno ha qualche idea?

Grazie a tutti.

Nedi

prova a rendere NIL la propriet che contiene il riferimento al database.

Si, Massimo, ho gi provato, ma niente da fare…quando eseguo f.Delete (dove f il FolderItem che punta al mio database) va in errore 104 (File in use)

cerca di capire se qualche riferimento all’oggetto ritenuto in qualche propriet/variabile. l’unica spiegazione che mi venga in mente.

Ho pensato anch’io la stessa cosa, ma non vedo niente del genere…adesso magari controllo più attentamente, magari mi è sfuggito qualcosa.
Grazie Massimo!

Puoi provare a fare una commit prima della close:

db.commit
db.close

In caso non ne esci, come soluzione estrema, puoi provare a fare una delete con i comandi dos tramite shell, tipo:

dim s as new Shell
dim dq as String = chr(34)
s.Execute("DEL /F " + dq + db.DatabaseFile.NativePath + dq)

Guarda di mettere a Nil anche l’HTTPSocket, io ho notato che tiene un riferimento al file di destinazione alle volte.
Io di solito per essere sicuro faccio cos:
Scarico il file con un altro nome.
A fine download lo rinomino.
In caso di cancel elimino il file con il nome temporaneo, dentro un timer e mettendo a Nil l’HTTPSocket.
( un po’ paranoico ma cos mi funziona sempre)

Ex l’init
Sub init()
Dim db_uri As String = “http://sito/db.db
Dim dbFile As FolderItem = SpecialFolder.ApplicationData.Child(G.dir).Child(“db.tmp”)
Dim http2 As New HTTPSocket
http2.Get(db_uri, dbFile)
Me.HTTP = http2
Me.MY_DB_FILE = dbFile
AddHandler http2.DownloadComplete, AddressOf down_db_ready
AddHandler http2.Error, AddressOf down_db_error
AddHandler http2.ReceiveProgress, AddressOf down_db_progress
End Sub

Se ho un btn cancel o simili o rimozione:
Ci infilo un Xojo.Core.Timer.CallLater(500, AddressOf Self.remove_file).
(Giusto perch non venga eseguito nel thread principale)

Sub Remove_File()
Self.MY_DB_FILE = Nil
Controller.MYDB = Nil
Controller.MYFILE = Nil
Self.HTTP = Nil
Dim dbFile As FolderItem = SpecialFolder.ApplicationData.Child(G.dir).Child(“database.tmp”)
dbFile.Delete()
End Sub

Controlla che siano a Nil tutti i riferimenti compreso l’HTTPSocket.

Michelangelo, chi tiene bloccato il database l’applicazione A: infatti ho provato a lanciare l’applicazione B passandole i parametri che riceve dalla A, e da sola funziona. Tieni presente che l’applicazione B quella che usa l’HTTPSocket, che scarica il file, e che cancella quello originale. Se lanciata da sola tutto funziona regolarmente, mentre quando viene richiamata dall’applicazione A va in errore il tentativo di cancellazione, segno evidente che l’applicazione A che tiene bloccato il database, nonostante la chiusura dello stesso e l’impostazione a Nil della sua variabile. Evidentemente c’ qualcosa che mi sfugge, probabilmente qualcosa che ha a che fare con un eseguibile che ne richiama un altro…

Pietro, ho provato ad eseguire la cancellazione con il comando Shell, come da te suggerito, ma non ci riesce.
Ecco il codice:

[code]
dim sh as new Shell
dim dq as String = chr(34)
sh.Execute("DEL /F " + dq + f.NativePath + dq)

msgbox "Eseguita Shell cancellazione. Verificare.  Errorcode=" + cstr(sh.ErrorCode)
    
if sh.ErrorCode <> 0 Then
  MsgBox "Impossibile cancellare il file DB_Listino" + EndOfLine + "Errore " + CStr(sh.ErrorCode) + EndOfLine + "Procedura interrotta."
  Exit Sub
end if
[/code]

La cosa strana che sh.ErrorCode 0…

Dovresti mettere un punto di interruzione nel programma prima che esegua il comando via shell; a quel punto provare ad eseguire da cmd lo stesso comando che esegue la shell e vedere se il prompt ritorna qualche tipo di messaggio.

Fatto: ed infatti mi d errore
Impossibile rimuovere l’elemento D:\xojo_app\capriati\gestionale_1.7.0\db_listino: Il processo non pu accedere al file ‘D:\xojo_app\capriati\gestionale_1.7.0\db_listino’ perch in uso da un altro processo.

Mi stavo chiedendo se la soluzione seguente potrebbe essere buona:
attualmente l’applicazione A apre il DB, legge un valore da una tabella e lo passa all’applicazione B (che non riesce pi a cancellare il database.
Se faccio in modo che l’applicazione A NON apra il database, ma che sia la B a farlo per prendersi il dato che le serve, secondo te l’applicazione B riuscir a cancellare il DB (previa chiusura, ovviamente)?

Ho provato, ma niente da fare, nonostante l’applicazione A non apra il DB prima di richiamare la B.

Altro approccio: potresti provare ad utilizzare il metodo SQLiteDatabase.Backup, che consente la copia in sovrascrittura da un db ad un altro.

dim dbOld as new SQLiteDatabase //dbAttuale
dbOld.Database = GetFolderItem("......dbOld.sqlite", FolderItem.PathTypeNative)
call dbOld.Connect

dim dbNew as new SQLiteDatabase //dbAggiornato
dbNew.Database = GetFolderItem("......dbNew.sqlite", FolderItem.PathTypeNative)
call dbNew.Connect

dbNew.Backup(dbOld, Nil, -1)

Posso provare, anche se dubito che possa funzionare, visto che il file in uso da un altro processo…non sar in grado di sostituirlo.
Nel frattempo per qualcosa ho scoperto: l’applicazione B viene richiamata dalla A con f.Launch (dove f punta all’eseguibile da richiamare). Il metodo Launch asincrono, per cui l’applicazione A, dopo aver lanciato la B, continua il suo cammino, e subito dopo apre il Database…
Ho provato a sostituire f.Launch con shell (che sincrono, per cui attende la fine della B), per CASPITA!!! continua a non riuscire a cancellare il DB…

Guarda che SQLiteDatabase.Backup non sostituisce il file del db, ma solo i dati, quindi forse ti consentirebbe di aggirare il problema di allocazione del file.

Ah, ok. Più tardi ci provo.
Grazie mille, Pietro!

Mi sbaglier, ma nonostante abbia indicato shell.Mode = 0 (sincrono) sembra che in realt tanto sincrono non sia, se A si ferma all’istruzione dopo la Shell.Execute mentre B ancora attiva…

Grazie Pietro! La tua soluzione di usare il metodo Backup ha funzionato alla grande! Sono riuscito ad aggirare anche il problema del richiamo asincrono dell’altra applicazione, e adesso tutto funziona bene!!

Grazie a tutti!

Bene. Mi fa piacere esserti stato utile.