Bonjour,

Je viens de terminer un assez gros programme de facturation.
Sur ma machine, il fonctionne sans problème.
L'installation et le fonctionnement en version autonome (sans VS) aussi.

Il utilise SqLite avec linq to Entities

Dans mon programme, j'ai bien référencé la librairie SqLite avec l'option de copie locale.

En l'installant sur la machine du destinataire, le programme se lance.
La création d'un facturier se passe sans problème (la création se fait en bas niveau, par ADO, via SqLite).

Par contre, impossible de m'y connecter, j'obtiens une erreur précisant que le fournisseur de magasin est invalide ou non installé.

La librairie SqLite est bien installée dans le répertoire d'installation du programme.

Sur ma machine, j'ai donc désinstallé SqLite, et j'obtiens effectivement strictement la même erreur.

Or, je ne suis pas sensé devoir installer SqLite pour faire tourner le programme, puisque l'installation copie la librairie.

J'ai tenté d'installer SqLite sur la machine destinataire (après tout, c'est un moindre mal), mais ça ne fonctionne pas.

J'ai donc tenté quelques essais sur ma machine et j'observe que :

- Si j'installe SqLite SANS cocher la case "utilisation pour visual studio" en fin d'installation, ça ne fonctionne pas. Bref, ça ne fonctionne QUE si j'installe SqLite avec l'option Visual studio.

- Or, cette case à cocher n'apparaît QUE si visual studio est installé sur la machine cible.

Je ne peux quand même pas installer VS sur la machine cible rien que pour pouvoir installer SqLite avec cette option.

Je suis très très très embêté, parce que ça fait 3 mois que je travaille sur ce programme, et qu'au final SqLite m'a mené dans une impasse.

Voici la partie source de la création du facturier (qui fonctionne que SqLite soit installé ou non) :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
        public static bool ConstruireBase(string NomFichier)
        {
            SQLiteConnection SC = null;                                         // Connexion
            bool result;                                                        // résultat de la méthode
            try
            {
                                                // CREER LA BASE
                                                // -------------
                SQLiteConnectionStringBuilder SCSB = new SQLiteConnectionStringBuilder(); // Création d'un objet de création de chaîne de connexion
 
                SCSB.DataSource = NomFichier;                                   // nom de la base à créer (on a déjà vérifié que la base n'existait pas déjà
                SCSB.FailIfMissing = false;                                     // Si la base n'existe pas, alors on la crée automatiquement
                // on peut aussi mettre un mot de passe avec la propriété password
 
                string ChaineConnexion = SCSB.ToString();                       // récupérer la chaîne de connexion construite avec les paramètres précédents
                SC = new SQLiteConnection(ChaineConnexion);                     // Créer la connexion
                SC.Open();                                                      // ouvrir la connexion, puisque la base n'existe pas, la créer
 
                                                // CREER LA TABLE Version
                                                // ----------------------
                string t = "CREATE TABLE Version(";                             // Cette table contiendra un seul record : le numéro de version
                t += "NumVersionBase TEXT NOT NULL PRIMARY KEY";                // Numéro de version servant aux vérifications
                t += ")";
 
                SQLiteCommand Cmd = SC.CreateCommand();                         // Obtenir un objet permettant de faire passer des commandes SQL sur la base SC
                Cmd.CommandText = t;                                            // Affecter la requête SQL sous forme d'un texte non vérifié
                Cmd.ExecuteNonQuery();                                          // exécuter la commande SQL
 
                                                // CREER LA TABLE  Client
                                                // ----------------------
                t = "CREATE TABLE Client(";                                     // On construit la chaîne SQL de construction de la table clients
                t += "NumClient INTEGER NOT NULL PRIMARY KEY";                  // clé primaire = numéro de client
                t += ",AdressePtr INTEGER NOT NULL REFERENCES Adresse(Id)";     // pointeur sur l'adresse du client
                t += ",Titre TEXT NOT NULL ";                                   // Titre (M., Mme, Mlle, Monsieur le Baron, SPRL etc)              
                t += ",Nom TEXT NOT NULL";                                      // Nom
                t += ",Prenom TEXT NOT NULL";                                   // Prénom
                t += ",Details TEXT NOT NULL";                                  // Ligne supplémentaire pour l'expédition (chef personnel, etc).
                t += ",NumTVA TEXT NOT NULL";                                   // Numéro de TVA
                t += ",Tel TEXT NOT NULL";                                      // Téléphone
                t += ",GSM TEXT NOT NULL";                                      // GSM
                t += ",Fax TEXT NOT NULL";                                      // Fax
                t += ",Email TEXT NOT NULL";                                    // email
                t += ",Info TEXT NOT NULL";                                     // informations complémentaires ne faisant pas partie de l'adresse d'expédition
                t += ")";
 
                Cmd.CommandText = t;                                            // Affecter la requête SQL sous forme d'un texte non vérifié
                Cmd.ExecuteNonQuery();                                          // exécuter la commande SQL
 
                                                // CREER LA TABLE Adresse
                                                // ----------------------
                t = "CREATE TABLE Adresse(";                                    // On construit la chaîne SQL de construction de la table
                t += "Id INTEGER NOT NULL PRIMARY KEY";                         // clé primaire
                t += ",Rue TEXT NOT NULL";                                      // rue
                t += ",Numero TEXT NOT NULL";                                   // numéro
                t += ",Boite TEXT NOT NULL";                                    // Boîte
                t += ",Localite TEXT NOT NULL";                                 // Localité
                t += ",CodeP TEXT NOT NULL";                                    // Code postal
                t += ",Pays TEXT NOT NULL";                                     // Pays
                t += ")";
 
                Cmd.CommandText = t;                                            // Affecter la requête SQL sous forme d'un texte non vérifié
                Cmd.ExecuteNonQuery();                                          // exécuter la commande SQL
 
                                            // CREER LA TABLE Entreprise
                                            // -------------------------
                t = "CREATE TABLE Entreprise(";                                 // On construit la chaîne SQL de construction de la table
                t += "Id INTEGER NOT NULL PRIMARY KEY";                         // clé primaire
                t += ",Coordonnees TEXT NOT NULL";                              // coordonnées de l'entreprise
                t += ",Logo BLOB";                                              // Logo de l'entreprise 
                t += ",AffLogo BOOL NOT NULL";                                  // indique si on affiche le logo
                t += ")";
 
                Cmd.CommandText = t;                                            // Affecter la requête SQL sous forme d'un texte non vérifié
                Cmd.ExecuteNonQuery();                                          // exécuter la commande SQL
 
                                                // CREER LA TABLE Facture
                                                // ----------------------
                t = "CREATE TABLE Facture(";
                t += "Id INTEGER NOT NULL PRIMARY KEY";                         // ID de la facture et clé primaire
                t += ",Type INTEGER NOT NULL";                                  // type de facture : 0= facture, 1=note de crédit
                t += ",ClientId INTEGER NOT NULL REFERENCES Client(NumClient)"; // pointeur sur client facturé
                t += ",AdresseClientId INTEGER NOT NULL REFERENCES Adresse(Id)";// pointeur sur adresse du client à la date de facturation
                t += ",DetailsPostaux TEXT NOT NULL";                           // détails postaux sur le destinataire réel (2ème ligne adresse)
                t += ",AdresseTravailId INTEGER NOT NULL REFERENCES Adresse(Id)";   // pointeur sur l'adresse d'exécution du travail
                t += ",ConditionsId INTEGER NOT NULL REFERENCES Condition (Id)";// pointeur sur condition de vente 
                t += ",EntrepriseId INTEGER NOT NULL REFERENCES Entreprise(Id)";// pointeur sur coordonnées d'entreprise
                t += ",Articles BLOB NOT NULL";                                 // Tableau d'articles mis sous forme de texte
                t += ",DateFact TEXT NOT NULL";                                 // Date de facturation
                t += ",DateEchean TEXT NOT NULL";                               // Date d'échéance de payement
                t += ",ModePayement TEXT NOT NULL";                             // Mode de payement
                t += ",DatePayement TEXT NOT NULL";                             // Date effective du payement
                t += ",Acompte REAL NOT NULL";                                  // acompte versé
                t += ",MontantHT REAL NOT NULL";                                // on pourrait se passer des montants (on a les articles -> redondance), 
                t += ",MontantTVA REAL NOT NULL";                               // mais c'est beaucoup plus rapide pour les affichages de listes
                t += ")";
 
                Cmd.CommandText = t;
                Cmd.ExecuteNonQuery();
 
                                                    // CREER LA TABLE Offre
                                                    // --------------------
                t = "CREATE TABLE Offre(";
                t += "Id INTEGER NOT NULL PRIMARY KEY";                         // ID de l'offre et clé primaire
                t += ",ClientId INTEGER NOT NULL REFERENCES Client(NumClient)"; // pointeur sur client
                t += ",DetailsPostaux TEXT NOT NULL";                           // détails postaux sur le destinataire réel (2ème ligne adresse)
                t += ",AdresseTravailId INTEGER NOT NULL REFERENCES Adresse(Id)";   // pointeur sur l'adresse d'exécution du travail
                t += ",ConditionsId INTEGER NOT NULL REFERENCES Condition (Id)";// pointeur sur condition de vente 
                t += ",Articles BLOB NOT NULL";                                 // Tableau d'articles mis sous forme de texte
                t += ",DateOffre TEXT NOT NULL";                                // Date de facturation
                t += ",DateValide TEXT NOT NULL";                               // Date de fin de validité
                t += ",MontantHT REAL NOT NULL";                                // montant HT (accélère les listes)
                t += ")";
 
                Cmd.CommandText = t;
                Cmd.ExecuteNonQuery();
 
                                                // CREER LA TABLE Article
                                                // ----------------------
                t = "CREATE TABLE Article(";
                t += "Id INTEGER NOT NULL PRIMARY KEY";                         // Id de l'article = clé primaire
                t += ",Description TEXT NOT NULL";                              // descriptif de l'article
                t += ",PrixUnit REAL NOT NULL";                                 // Prix unitaire de l'article (éviter les null parce que single ou float ne sont pas nullables dans C#, ce qui impose un cast)
                t += ",DureeRappel INTEGER NOT NULL";                           // Durée en jours du rappel automatique
 
                t += ")";
 
                Cmd.CommandText = t;
                Cmd.ExecuteNonQuery();
 
                                                // CREER LA TABLE Agenda
                                                // ---------------------
                t = "CREATE TABLE Agenda(";
                t += "Id INTEGER NOT NULL PRIMARY KEY";
                t += ",ClientId INTEGER NOT NULL REFERENCES Client(NumClient)"; // pointeur sur client facturé
                t += ",FactId INTEGER REFERENCES Facture(Id)";                  // référence vers la facture qui a forcé l'événement
                t += ",DateRappel TEXT NOT NULL";                               // Date de rappel
                t += ",Descriptif TEXT NOT NULL";                               // Descriptif de l'opération
                t += ")";
 
                Cmd.CommandText = t;
                Cmd.ExecuteNonQuery();
 
                                                // CREER LA TABLE Condition
                                                // ------------------------
                t = "CREATE TABLE Condition(";
                t += "Id INTEGER NOT NULL PRIMARY KEY";                         // Id des conditions
                t += ",Intitule TEXT NOT NULL";                                 // intitulé
                t += ",Descriptif TEXT NOT NULL";                               // descriptif
                t += ",TailleFonte INTEGER NOT NULL";                           // Taille de la fonte
                t += ")";
 
                Cmd.CommandText = t;
                Cmd.ExecuteNonQuery();
 
 
                                // INSERER LE RECORD DE NUMERO DE VERSION DANS LA TABLE Version
                                // ------------------------------------------------------------
                Cmd.CommandText = "INSERT INTO Version VALUES('"+VersionBase+"');";
                Cmd.ExecuteNonQuery();
 
 
                result = true;                                                  // opération réussie
 
 
 
                // Exemples de syntaxe :
                //SQLCmd.CommandText = "INSERT INTO Employes (Nom, Prenom, Salaire) VALUES ('John', 'Doe', 2100);";
                //Console.WriteLine(SQLCmd.ExecuteNonQuery()); // Cela nous permettra de voir combien d'entrées auront été affectées
                //SQLCmd.CommandText = "INSERT INTO Employes (Nom, Prenom, Salaire) VALUES ('Sam', 'Linston', 3600);";
                //Console.WriteLine(SQLCmd.ExecuteNonQuery()); // Idem.
            }
 
            catch (Exception e)
            {
                e.Message.SendMessErreur();                                     // message d'erreur
                result = false;                                                 // Echec de l'opération
            }
            if (SC != null) SC.Close();                                         // si base ouverte, la fermer
            return result;                                                      // retourner résultat
        }

Et voici la partie "connexion", qui plante si SqLite n'est pas installé sur la machine avec l'option "Visual studio" précisée :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
        public static FactEntities OuvrirDataBase(string FileName)
        {
            FactEntities result = null;                             // Valeur de retour
            string Vers = "";                                       // Version lue dans la table
 
            if (File.Exists(FileName))                              // si le fichier existe
            {
                if (FileName.ToLower().EndsWith(".fctlt"))          // et si l'extension est valide 
                {
                    EntityConnectionStringBuilder ecsb = new EntityConnectionStringBuilder();
 
                    try
                    {
                        // Créer un constructeur automatique de chaîne de connexion
 
                        // Indique le serveur de bdd utilisé (SQLite = API ne nécessitant pas de serveur)
                        ecsb.Provider = "System.Data.SQLite";
 
                        // Indiquer les chemins d'accès au modèle (copié depuis app.config)
                        ecsb.Metadata = "res://*/FactModele.csdl|res://*/FactModele.ssdl|res://*/FactModele.msl";
 
                        // Donner le nom du provider
                        ecsb.ProviderConnectionString = string.Format("data source={0}", FileName);
 
                        // ouvrir la base en utilisant la chaîne de connexion construite
                        result = new FactEntities(ecsb.ConnectionString);
 
                        // Lire la table Version et récupérer le premier (et unique) record
                        Vers = result.Version.First().NumVersionBase;
 
                        // autre méthode pour lire la version :
                        //var query = from v in result.Version
                        //            select v;
                        //var Vers = query.First().NumVersionBase;
                    }
                    catch (Exception ex)                            // si échec à l'ouverture
                    {
                        MessageBox.Show(ex.Message + "\n" + ex.InnerException.ToString());
                        MessageBox.Show(ecsb.ConnectionString);
 
                        result = null;                              // annuler résultat
                    }
                }
 
            }
            if (result == null)                                     // si échec, message d'erreur
                Methodes.SendMessErreur("Impossible de connecter au facturier:\n" + FileName);
 
            else                                                    // La table semble avoir la structure correcte, reste la version à vérifier
            {
                if (Vers != VersionBase)                            // Si les versions ne correspondent pas
                {
                    Methodes.SendMessErreur("Le facturier n'est pas compatible avec cette version de FactuLite\n\n"
                        + "Version exigée    : "+VersionBase + "\n" + "Version facturier : "+Vers);  // Envoyer message d'erreur
                    result = null;                                  // et annuler le résultat
                }
            }
            return result;
        }
Le message obtenu est :

Soit le fournisseur de magasins spécifié est introuvable, soit il n'est pas valide.
System.argument.Exception: Le fournisseur de données .net framework demandé est introuvable. Il n'est peut-être pas installé.
A System.data.common.dbproviderFactories.GetFactory(string provider invariantname)
A System.Data.EntityClient.EntityConnection.GetFactory(string providerString)

Un sauveur providentiel a-t-il la solution miracle pour me sortir de ce mauvais pas?

Merci 1000 fois d'avance



Claude

PS : Je peux fournir les sources et/ou l'exécutable sans problème, le projet est de toutes façons destiné à devenir open-source.