Page 1 sur 3
Problème base de donnée MS Access
Publié : sam. 08/mars/2008 19:23
par Atomo
Salut à tous, j'ai fait un programme qui contient une base de donnée Microsoft Access , je peux faire des opérations sans problème dessus (ajout, suppression, requête), cependant certains utilisateurs de mon programme rencontrent des problèmes lors de la fermeture puis réouverture de celui-ci, la base de donnée se vide en partie comme si il y avait un retour arrière.
Pour me connecter à la base à l'ouverture du logiciel j'utilise ce code :
Code : Tout sélectionner
Global db
Global DSN.s = "bdd"
Global Etat_connection.b
Procedure database_connect()
If Etat_connection = #False
If OpenDatabase(db, DSN, "", "17a93b") = 0
MessageRequester("Erreur", "Impossible d'ouvrir la base de donnée", #MB_ICONERROR)
End
Else
Etat_connection = #True
EndIf
EndIf
EndProcedure
Procedure database_disconnect()
If Etat_connection = #True
CloseDatabase(db)
Etat_connection = #False
EndIf
EndProcedure
Enumeration 1
#ODBC_ADD_DSN ; Ajoute une source de données utilisateur.
#ODBC_CONFIG_DSN ; Configure/Modifie une source de données utilisateur existante.
#ODBC_REMOVE_DSN ; Supprime une source de données utilisateur existante.
#ODBC_ADD_SYS_DSN ; Ajoute une source de données système.
#ODBC_CONFIG_SYS_DSN ; Configure/Modifie une source de données système existante.
#ODBC_REMOVE_SYS_DSN ; Supprime une source de données système existante.
#ODBC_REMOVE_DEFAULT_DSN ; Supprime la source de données définies par défaut.
EndEnumeration
#ODBC_DRIVER_MSACCESS = "Microsoft Access Driver (*.mdb)"
Procedure.l MSAccess_AddConnection(name.s, database.s, hwnd.l = #Null)
Protected attrs.s
attrs + "UID=" + ";"
attrs + "PWD=" + ";"
attrs + "DSN=" + name + ";"
attrs + "DBQ=" + database + ";"
attrs + "FIL=" + "MS Access;"
attrs + "Driver=" + "ODBCJT32.DLL;"
attrs + "DefaultDir=" + GetPathPart(database) + ";"
attrs + "Description=" + FormatDate("Créé le %dd-%mm-%yyyy, %hh:%ii:%ss;", Date())
ReplaceString(attrs, ";", #NULL$, 2)
ProcedureReturn SQLConfigDataSource_(hWnd, #ODBC_ADD_DSN, #ODBC_DRIVER_MSACCESS, attrs)
EndProcedure
Procedure.l MSAccess_RemoveConnection(name.s, hwnd.l = #Null)
ProcedureReturn SQLConfigDataSource_(hWnd, #ODBC_REMOVE_DSN, #ODBC_DRIVER_MSACCESS, "DSN="+name)
EndProcedure
UseODBCDatabase()
MSAccess_AddConnection(DSN, GetCurrentDirectory()+"bdd.mdb")
Et celui-ci à la fermeture :
Auriez-vous une idée du problème ? Merci de bien vouloir m'aider.
Publié : sam. 08/mars/2008 19:28
par lionel_om
Ca dépend pe etre aussi comment est configurée ta base : "COMMIT".
Avec des accès concurrents comme ça, faut peut-être valider certaines transactions.
Regarde "rollback" et "commit", dont "auto commit". Le problème vient peut-être de là...
Lio

Publié : sam. 08/mars/2008 19:39
par Atomo
Tu peux télécharger la base de donnée ici :
http://rapidshare.com/files/98024907/bdd.mdb.html
Le mot de passe de la base est : 17a93b
Publié : sam. 08/mars/2008 21:15
par Ollivier
hWnd = 0
C'est normal, ça?

Publié : sam. 08/mars/2008 21:58
par Atomo
Le code n'est pas de moi je sais pas

Publié : dim. 09/mars/2008 13:11
par lionel_om
Moi j'utilise ce code pour les me connecter à une BDD sous Access :
Y'a qq fonctions bonus, c'est cadeau !
Code : Tout sélectionner
;- Types de donnees des rows
Enumeration 0
#ODBC_UNKNOW
#ODBC_NUMERIC
#ODBC_STRING
#ODBC_FLOAT
EndEnumeration
;- Types de donnees de la BD
Global Dim DatabaseType.s(4)
DatabaseType(#ODBC_UNKNOW) = "Unknown"
DatabaseType(#ODBC_NUMERIC) = "Numeric"
DatabaseType(#ODBC_STRING) = "String"
DatabaseType(#ODBC_FLOAT) = "Float"
Global hasBD.b, DSN.s
#Database = 1
#BD_NAME$ = ; DataBase Name here !!!! "divx.mdb"
DSN = "pbtest"
Enumeration 1
#ODBC_ADD_DSN ; Add a new user Data source.
#ODBC_CONFIG_DSN ; Configure (modify) an existing user Data source.
#ODBC_REMOVE_DSN ; Remove an existing user Data source.
#ODBC_ADD_SYS_DSN ; Add a new system Data source.
#ODBC_CONFIG_SYS_DSN ; Modify an existing system Data source.
#ODBC_REMOVE_SYS_DSN ; Remove an existing system Data source.
#ODBC_REMOVE_DEFAULT_DSN ; Remove the default data source specification section from the system information.
EndEnumeration
#ODBC_DRIVER_MSACCESS = "Microsoft Access Driver (*.mdb)"
Procedure.l MSAccess_AddConnection(name.s, database.s, hwnd.l = #Null)
Protected attrs.s
attrs + "UID=" + ";"
attrs + "PWD=" + ";"
attrs + "DSN=" + name + ";"
attrs + "DBQ=" + database + ";"
attrs + "FIL=" + "MS Access;"
attrs + "Driver=" + "ODBCJT32.DLL;"
attrs + "DefaultDir=" + GetPathPart(database) + ";"
attrs + "Description=" + FormatDate("Créé le %dd-%mm-%yyyy, %hh:%ii:%ss;", Date())
ReplaceString(attrs, ";", #Null$, 2)
ProcedureReturn SQLConfigDataSource_(hwnd, #ODBC_ADD_DSN, #ODBC_DRIVER_MSACCESS, attrs)
EndProcedure
Procedure.l MSAccess_RemoveConnection(name.s, hwnd.l = #Null)
ProcedureReturn SQLConfigDataSource_(hwnd, #ODBC_REMOVE_DSN, #ODBC_DRIVER_MSACCESS, "DSN="+name)
EndProcedure
;- Connexion a la BD
Procedure BD_Connect(user$, pass$)
If UseODBCDatabase()=#Null
MessageRequester("Error", "Impossible d'initialiser les drivers BD", #MB_ICONERROR)
hasBD = #False
ProcedureReturn #False
EndIf
If MSAccess_AddConnection(DSN, #BD_NAME$) = 0
MessageRequester("Error", "Impossible de créer la connexion à la BD", #MB_ICONERROR)
hasBD = #False
ProcedureReturn #False
EndIf
;If OpenDatabase(#Database, #ODBC_DNS$, user$, pass$)=0 ; DSN
If OpenDatabase(#Database, DSN, user$, pass$)=0
MessageRequester("Error", "Impossible d'ouvrir la BD", #MB_ICONERROR)
hasBD = #False
ProcedureReturn #False
EndIf
hasBD = #True
ProcedureReturn #True
EndProcedure
Procedure BD_Close()
CloseDatabase(#Database)
MSAccess_RemoveConnection(DSN.s)
hasBD = #False
EndProcedure
;- Recupere un champs apres requete
Procedure FindIndiceField(champ$)
Protected k.b
For k=0 To DatabaseColumns(#Database)-1
If DatabaseColumnName(#Database, k) = champ$
ProcedureReturn k
EndIf
Next k
For k=0 To DatabaseColumns(#Database)-1
If UCase(DatabaseColumnName(#Database, k)) = UCase(champ$)
ProcedureReturn k
EndIf
Next k
Debug ">> Erreur FindIndiceField <<"
Debug champ$
EndProcedure
Procedure.s GetStrField(champ$)
Protected ind.b, s$
ind = FindIndiceField(champ$)
s$ = GetDatabaseString(#Database, ind)
ReplaceString(s$, Chr(34), "'", 2)
ProcedureReturn s$
EndProcedure
Procedure.l GetNumField(champ$)
Protected ind.b
ind = FindIndiceField(champ$)
ProcedureReturn GetDatabaseLong(#Database, ind)
EndProcedure
Procedure.f GetFloatField(champ$)
Protected ind.b
ind = FindIndiceField(champ$)
ProcedureReturn GetDatabaseFloat(#Database, ind)
EndProcedure
;- Index nouvelle ligne (Auto-Increment)
Procedure.l GetNewLine(table$, champ$)
If DatabaseQuery(#Database, "SELECT MAX("+champ$+") as max FROM " + table$)
If NextDatabaseRow(#Database)
ProcedureReturn(GetNumField("max")+1)
Else
ProcedureReturn(1)
EndIf
Else
Debug " -> Erreur dans la recherche du MAX"
ProcedureReturn(0)
EndIf
EndProcedure
;- Max from table
Procedure.l GetMaxTable(table$, champ$)
If DatabaseQuery(#Database, "SELECT MAX("+champ$+") as max FROM " + table$)
If NextDatabaseRow(#Database)
ProcedureReturn(GetNumField("max"))
Else
ProcedureReturn(0)
EndIf
Else
Debug " -> Erreur dans la recherche du MAX"
ProcedureReturn(0)
EndIf
EndProcedure
;- Get Index of a Row
Procedure.l GetIndexRow(table$, value$, stringField$, numField$)
query$ = "SELECT "+numField$+" FROM " + table$ + " WHERE "+stringField$+" = "+ForUpdate(value$)
;Debug query$
If DatabaseQuery(#Database, query$)
If NextDatabaseRow(#Database)
ProcedureReturn(GetNumField(numField$))
Else
Debug "ERR: GetIndexRow -> Pas de ligne sélectionné"
ProcedureReturn(0)
EndIf
Else
Debug "ERR: GetIndexRow -> Erreur dans la requête"
ProcedureReturn(0)
EndIf
EndProcedure
Lio

Publié : dim. 09/mars/2008 15:24
par Atomo
Merci pour ton code.
Au niveau des connexions et déconnexions, il vaut mieux faire ça à chaque requête ou bien connexion en début de programme et déconnexion à la fermeture de celui-ci ?
Publié : dim. 09/mars/2008 16:24
par lionel_om
Perso je préfère garder la cnx ouverte, mais mes tuteurs de mon dernier stage préféraient la fermer et la réouvrir à chaque fois. Je trouve que c'est inutile et que ça baisse les performances pour aucune raison vraiment notable... Donc
it's up to you, à mon avis la cnx permanente est préférable, surtout que ça vérouille le fichier (il n'est pas déplaçable, ni renommable...)
Lio

Publié : jeu. 13/mars/2008 17:35
par djmcg
Merci les amis.
le code de lionel_om va m'être très utile, je cherchais depuis....
Encore merci.
Jean-Marie
Publié : lun. 17/mars/2008 16:20
par djmcg
Bonjour a tous
et aussi a lionel_om,
Mon problème : je n'arrive pas a me connecter a une base de donnée. (qu'est-ce que ca va donnée quand il s'agiras de manipuler des table et des champs

) bon trève de plaisenterie... Jean-Marie.
Etant sérieusement dans la muise, j'ai décider de reprendre le code que tu a posté. De le réécrire point par point pour tentez de comprendre.
Peut-tu m'aider et si oui, j'ai trois questions :
1) DSN = "pbtest" ; est-ce une table ?
2) ForUpdate est une procédure ?
Tu accepterais de la passé.
3)Le tableaux DatabaseType fait'il allusion a des format qui peuvent exister dans la base ou qui existe. Si ces la deuxième possibilité que faire des format Monétaire et Date ?
Merci si tu peux m'aider, bonne soirée.
Jean-Marie
Publié : mer. 19/mars/2008 9:53
par lionel_om
Voilà ce qu'il manquait :
Code : Tout sélectionner
Procedure.s Normalize(s$)
ReplaceString(s$, "'", Chr(34), 2)
ProcedureReturn Trim(s$)
EndProcedure
Procedure.s ForUpdate(s$)
s$ = Normalize(s$)
ProcedureReturn(" '" + s$ + "' ")
EndProcedure
Macro NormalizedGadgetText(gadgetID)
ForUpdate(GetGadgetText(gadgetID))
EndMacro
pbtest, c'est le nom de la BDD, mais surement pas le nom d'une table.
Pour les autres types : PB ne gère que ces types il me semble. En le type date est un Int que tu peux convertir avec les fonctions Date() de PB. Et format monétaire, c'est pas simplement un float ou double ?
Lio
Live from Lapland (Laponie)
Publié : mer. 19/mars/2008 11:29
par djmcg
Merci
Je sèche en tous cas !!
Même avec ton source.
Exemple :
#BD_NAME$ =
DSN =
si DSN contiens le nom de la base, que doit contenir #BD_NAME$, aussi le nom de la base ?
Bon ben je continue a chercher.
Merci encore.
Jean-Marie
PS.: il semble que monétaire est égal a un double.
Date, je vais les remettre en string dans la base et les remettre en date dans PB. Si tu a un avis la dessus. Merci. Mais d'abord me connecter...

Publié : mer. 19/mars/2008 16:52
par djmcg
Me revoila avec mon problème de connection.
J'ai cerné semble t'il le problème que je ne comprend pas.
En voulant utiliser le source qui est sur basic univers, après avoir, la aussi semble t'il résolu tous les problème probablement du a une difference de version PB.
Voici l'erreur que j'obtiens, je cite :
Source de donnée introuvalbe et nom de pilote non spécifié.
Pour que vous puissiez m'aider, faut'il remettre le source ici ?
Volontié mais j'ai peur de trop charger.
A bientôt j'espère.
JM
Publié : mer. 19/mars/2008 19:25
par lionel_om
#BD_NAME$ est le nom du fichier Access.
DNS est le nom de la base de données. Je n'ai pas installé Access sur ce PC, mais il me semble qu'il faut donner un nom à la base de données (comme on fait en SQL ou ORACLE). Si je me trompe, alors dans ce cas laisse "pbtest" car c'est que ce n'est surement pas utile ou alors c'est qu'il faut laisser "pbtest" car l'association PB-Access ne marche qu'avec cette valeur...
Lio
Publié : mer. 19/mars/2008 19:29
par lionel_om
J'ai ce code là aussi sinon, il marche peut-être mieux...
Code : Tout sélectionner
#Database = 1
#ODBC_ADD_DSN = 1 ; Add Data source
#ODBC_CONFIG_DSN = 2 ; Configure (edit) Data source
#ODBC_REMOVE_DSN = 3 ; Remove Data source
#ODBC_DRV_DESC$ = "Microsoft Access Driver (*.mdb)"
#ODBC_DNS$ = "PureBasic_DSN"
#ODBC_DLL_NAME$ = "ODBCCP32.DLL"
#ODBC_STR_CON1$ = "Server=SomeServer; Description=Description For Purebasic MDB-ODBC;DSN=PureBasic_DSN;DBQ="
#ODBC_STR_CON2$ = ";UID=Rings;PWD=Siggi;"
Procedure Alert(title$, msg$, fin.b)
MessageRequester(title$, msg$, #MB_ICONERROR)
If fin
End
EndIf
EndProcedure
;- Preparation des DNS et des Drivers
Procedure IniConnection(strAttributes.s)
Protected lpszDriver.s, MyMemory.l, Lib.l
Lib = OpenLibrary(#PB_Any,#ODBC_DLL_NAME$)
If Lib
strAttributes = #ODBC_STR_CON1$ + strAttributes + #ODBC_STR_CON2$
lpszDriver = #ODBC_DRV_DESC$
MyMemory=AllocateMemory(Len(strAttributes))
CopyMemory(@strAttributes,MyMemory,Len(strAttributes))
For L=1 To Len(strAttributes )
If PeekB(MyMemory +L-1)=Asc(";"):PokeB(MyMemory +L-1,0): EndIf
Next L
If CallFunction(Lib, "SQLConfigDataSource", 0, #ODBC_ADD_DSN, lpszDriver.s, MyMemory )
NewResult=SQLConfigDataSource_(0,#ODBC_ADD_DSN,lpszDriver.s,MyMemory )
FreeMemory(MyMemory)
CloseLibrary(Lib)
ProcedureReturn 1
EndIf
EndIf
ProcedureReturn 0
EndProcedure
;- UnIni BD Connexion
Procedure UnIniConnection()
Result=OpenLibrary(1,#ODBC_DLL_NAME$)
If Result
lpszDriver.s=#ODBC_DRV_DESC$
strAttributes.s = "DSN=" + #ODBC_DNS$
Result = CallFunction(1, "SQLConfigDataSource", 0,#ODBC_REMOVE_DSN,lpszDriver.s,strAttributes )
CloseLibrary(1)
If Result
ProcedureReturn #True
EndIf
hasBD = #False
EndIf
EndProcedure
;- Ini de la BD et création de la connexion
Procedure ALP_BD_Ini(quit.b)
If InitDatabase() = 0
head$ = GetPrefString("TITLE", "ERR_MSG")
msg$ = GetPrefString("ERROR", "ERR_ODBC_INI")
hasBD = #False
Alert(head$, msg$, quit)
ProcedureReturn #False
EndIf
If IniConnection(#ALP_BD_NAME$)=0
head$ = GetPrefString("TITLE", "ERR_MSG")
msg$ = GetPrefString("ERROR", "ERR_ODBC_DRIVERS")
hasBD = #False
Alert(head$, msg$, quit)
ProcedureReturn #False
EndIf
hasBD = #True
ProcedureReturn #True
EndProcedure
;- Connexion a la BD
Procedure ALP_BD_Connect(quit.b, user$, pass$)
If OpenDatabase(#Database, #ODBC_DNS$, user$, pass$)=0
head$ = GetPrefString("TITLE", "ERR_MSG")
msg$ = GetPrefString("ERROR", "ERR_BD_NOT_OPEN")
Alert(head$, msg$, quit)
hasBD = #False
ProcedureReturn #False
EndIf
hasBD = #True
ProcedureReturn #True
EndProcedure
Procedure ALP_BD_Close()
CloseDatabase(#Database)
hasBD = #False
EndProcedure
GetPrefString() est une fonction de lecture dans les fichiers *.pref ou *.ini...
Lio