120 votes

System.Data.SQLite Close() ne libère pas le fichier de base de données

J'ai un problème pour fermer ma base de données avant d'essayer de supprimer le fichier. Le code est juste

 myconnection.Close();    
 File.Delete(filename);

Et l'application Delete lève une exception en indiquant que le fichier est toujours en cours d'utilisation. J'ai réessayé le Delete() dans le débogueur après quelques minutes, ce n'est donc pas un problème de timing.

J'ai le code de la transaction mais il ne s'exécute pas du tout avant l'appel à Close(). Je suis donc presque sûr qu'il ne s'agit pas d'une transaction ouverte. Les commandes sql entre open et close sont juste des selects.

ProcMon montre mon programme et mon antivirus en train d'examiner le fichier de la base de données. Il ne montre pas que mon programme libère le fichier db après le close().

Visual Studio 2010, C#, System.Data.SQLite version 1.0.77.0, Win7

J'ai vu un bug vieux de deux ans exactement comme celui-ci, mais le changelog dit qu'il est corrigé.

Y a-t-il autre chose à vérifier ? Existe-t-il un moyen d'obtenir une liste des commandes ou des transactions en cours ?


Nouveau, code de travail :

 db.Close();
 GC.Collect();   // yes, really release the db

 bool worked = false;
 int tries = 1;
 while ((tries < 4) && (!worked))
 {
    try
    {
       Thread.Sleep(tries * 100);
       File.Delete(filename);
       worked = true;
    }
    catch (IOException e)   // delete only throws this on locking
    {
       tries++;
    }
 }
 if (!worked)
    throw new IOException("Unable to close file" + filename);

0voto

Tony Sullivan Points 1

J'utilisais SQLite 1.0.101.0 avec EF6 et j'avais des problèmes avec le fichier qui était verrouillé après que toutes les connexions et entités aient été éliminées.

La situation s'est aggravée lorsque les mises à jour de l'EF ont bloqué la base de données après leur achèvement. GC.Collect() était le seul moyen de contourner le problème et je commençais à désespérer.

En désespoir de cause, j'ai essayé ClearSQLiteCommandConnectionHelper d'Oliver Wickenden (voir sa réponse du 8 juillet). C'est fantastique. Tous les problèmes de verrouillage ont disparu ! Merci Oliver.

0voto

Muhammed Kadir Points 412

Attendre le Garbage Collector peut ne pas libérer la base de données tout le temps et cela m'est arrivé. Lorsqu'un type d'exception se produit dans la base de données SQLite, par exemple en essayant d'insérer une ligne avec une valeur existante pour la clé primaire, le Garbage Collector conservera le fichier de la base de données jusqu'à ce que vous vous en débarrassiez. Le code suivant attrape l'exception SQLite et annule la commande problématique.

SQLiteCommand insertCommand = connection.CreateCommand();
try {
    // some insert parameters
    insertCommand.ExecuteNonQuery();
} catch (SQLiteException exception) {
    insertCommand.Cancel();
    insertCommand.Dispose();
}

Si vous ne gérez pas les exceptions des commandes problématiques, le collecteur de déchets ne peut rien faire à leur sujet, car il existe des exceptions non gérées concernant ces commandes, qui ne sont donc pas des déchets. Cette méthode de gestion a bien fonctionné pour moi avec l'attente du ramasse-miettes.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X