Problème base de donnée MS Access

Vous débutez et vous avez besoin d'aide ? N'hésitez pas à poser vos questions
Atomo
Messages : 207
Inscription : lun. 17/sept./2007 12:27

Problème base de donnée MS Access

Message 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 :

Code : Tout sélectionner

MSAccess_RemoveConnection(DSN)
Auriez-vous une idée du problème ? Merci de bien vouloir m'aider.
lionel_om
Messages : 1500
Inscription : jeu. 25/mars/2004 11:23
Localisation : Sophia Antipolis (Nice)
Contact :

Message 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 :wink:
Webmestre de Basic-univers
Participez à son extension: ajouter vos programmes et partagez vos codes !
Atomo
Messages : 207
Inscription : lun. 17/sept./2007 12:27

Message 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
Ollivier
Messages : 4197
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Message par Ollivier »

hWnd = 0

C'est normal, ça? :D
Atomo
Messages : 207
Inscription : lun. 17/sept./2007 12:27

Message par Atomo »

Le code n'est pas de moi je sais pas :P
lionel_om
Messages : 1500
Inscription : jeu. 25/mars/2004 11:23
Localisation : Sophia Antipolis (Nice)
Contact :

Message par lionel_om »

Moi j'utilise ce code pour les me connecter à une BDD sous Access :
Y'a qq fonctions bonus, c'est cadeau ! :D

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 :)
Webmestre de Basic-univers
Participez à son extension: ajouter vos programmes et partagez vos codes !
Atomo
Messages : 207
Inscription : lun. 17/sept./2007 12:27

Message 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 ?
lionel_om
Messages : 1500
Inscription : jeu. 25/mars/2004 11:23
Localisation : Sophia Antipolis (Nice)
Contact :

Message 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 :wink:
Webmestre de Basic-univers
Participez à son extension: ajouter vos programmes et partagez vos codes !
djmcg
Messages : 139
Inscription : sam. 28/août/2004 6:37

Message par djmcg »

Merci les amis.

le code de lionel_om va m'être très utile, je cherchais depuis....

Encore merci.

Jean-Marie
djmcg
Messages : 139
Inscription : sam. 28/août/2004 6:37

Message 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 :lol: ) 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
lionel_om
Messages : 1500
Inscription : jeu. 25/mars/2004 11:23
Localisation : Sophia Antipolis (Nice)
Contact :

Message 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 :wink:
Live from Lapland (Laponie)
Webmestre de Basic-univers
Participez à son extension: ajouter vos programmes et partagez vos codes !
djmcg
Messages : 139
Inscription : sam. 28/août/2004 6:37

Message 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... :oops:
djmcg
Messages : 139
Inscription : sam. 28/août/2004 6:37

Message 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
lionel_om
Messages : 1500
Inscription : jeu. 25/mars/2004 11:23
Localisation : Sophia Antipolis (Nice)
Contact :

Message 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
Webmestre de Basic-univers
Participez à son extension: ajouter vos programmes et partagez vos codes !
lionel_om
Messages : 1500
Inscription : jeu. 25/mars/2004 11:23
Localisation : Sophia Antipolis (Nice)
Contact :

Message 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
Webmestre de Basic-univers
Participez à son extension: ajouter vos programmes et partagez vos codes !
Répondre