Accès à une base de données dans une mfc.

Traitée Accès à une base de données dans une mfc.

  • dimanche 12 février 2012 13:38
     
     
    Bonjour, 

    Je suis en train de coder une ihm pour un gardien.

    Cette ihm permet de filmer l'entrée d'un parking, et aussi modifier la liste des personnes autorisée a entrées. Cette liste de personne est stockée dans une base de données MySQL.
    Grâce a l'ihm, je peut donc, ajouter une personne, modifier son profil, ou supprimer la personne. Donc, quand j'ajoute, ou supprime ou modifie, je modifie donc les champs de la base de données.

    Mais, le problème est que je ne sais pas comment faire, j'ai donc plusieurs questions a vous poser:

    1) Comment faire pour se connecter a la base de données ?
    2) Une fois connecté, comment faire pour modifier la base de données (ajouter, modifier ou supprimer) ?


    Merci d'avance pour votre aide.

Toutes les réponses

  • dimanche 12 février 2012 23:29
    Auteur de réponse
     
     Traitée

    En quel langage sera écrite l'appli ?

    Si c'est en C++, voici un exemple de code en anglais, pour se connecter à une base MySQL depuis une appli C++/MFC :

    http://www.codeproject.com/Articles/34646/Accessing-MySQL-data-base-using-MySQL-C-API

    C# peut être un meilleur choix que C++ cependant : C# est bien adapté aux application qui utilisent des bases de données, et plus facile à utiliser que C++.

  • lundi 13 février 2012 14:00
     
     

    L'appli sera écrite en C++.

  • mercredi 15 février 2012 07:42
     
     
     

    Bonjour, Tifil,

    Est-ce que vous avez pu avancer en utilisant l’exemple de Pierre ? Merci de tenir la communauté informée sur la suite de vos démarches.

    Cordialement,

    Cipri


    Suivez MSDN sur Twitter   Suivez MSDN sur Facebook


    Ciprian DUDUIALA, MSFT  
    •Nous vous prions de considérer que dans le cadre de ce forum on n’offre pas de support technique et aucune garantie de la part de Microsoft ne peut être offerte.

  • mercredi 15 février 2012 17:23
     
     

    Désolé, j'ai eu un petit souci d'ordinateur.

    Sinon, a propos du lien, je l'ai regardé, mais je n'ai pas vraiment pu avancer.

  • jeudi 16 février 2012 08:23
     
     Traitée

    Bonjour,

    Pouvez-vous svp nous expliquer quelles sont les difficultés que vous rencontrez avec l’article indiqué par Pierre ? Vous pouvez aussi consulter les articles suivants pour voir comment créer, se connecter et obtenir des infos d’une base de données  MySql en Visual C++ :

    http://www.caspercomsci.com/pages/visualcplussource.htm#12

    http://www.nitecon.com/tutorials-articles/develop/cpp/c-mysql-beginner-tutorial/

    http://lstigile.wordpress.com/2009/05/19/using-libmysqld-with-microsoft-visual-c-2008-express/

    http://dev.mysql.com/doc/refman/5.1/en/connector-cpp-apps-windows-visual-studio.html

    http://www.functionx.com/mysqlnet/vcnet/Lesson02.htm

    http://www.functionx.com/mysqlnet/vcnet/Lesson04.htm

    Les liens sont en anglais, mais vous pouvez utiliser Microsoft Translator pour les traduire.

    Cordialement,

    Cipri


    Suivez MSDN sur Twitter   Suivez MSDN sur Facebook


    Ciprian DUDUIALA, MSFT  
    •Nous vous prions de considérer que dans le cadre de ce forum on n’offre pas de support technique et aucune garantie de la part de Microsoft ne peut être offerte.

  • mardi 21 février 2012 14:19
     
      A du code

    J'ai regardé ces liens, et je me suis servis de bout de code pour pouvoir me connecter.

    En fait, ce que je veut, c'est quand j'appuis sur un bouton, que je me connecte a la base de données.

    Quand, je double clique sur le bouton, pour aller à sa méthode, je rajoute dans cette méthode ce code-ci:

    void CparkingDlg::OnBnClickedEdition()
    {
    
    	EditionDlg dlg;
    	dlg.DoModal();
    	conn = mysql_init(NULL);
    	if (mysql_real_connect(conn, host, username, password, database, 0, NULL, 0) != NULL)
    	{
    	MessageBox("Connexions réussie");
    	
    	}
    	if(mysql_real_connect(conn, host, username, password, database, 0, NULL, 0) == NULL)
    	{
    		MessageBox("Connexion échouée");
    		
    	}
    	
    
    }


    Je rajoute bien sur ceci aussi, <mysql.h>

    Et dans, les propriétés du projet, je rajoute aussi le dossier include pour MySql.

    J'ai bien les #define, pour les champs host, username,password et database.

    Quad je compile, tout marche, sauf qu'il ne se connecte pas a la base de données, il me metdonc le message box pour connexion échouée.


    • Modifié tifil mardi 21 février 2012 14:20
    • Modifié tifil mardi 21 février 2012 16:08
    •  
  • mardi 21 février 2012 17:33
    Modérateur
     
      A du code

    Avez-vous déjà appelé la fonction mysql_init() avant l'appel à mysql_real_connect ?

    Cf. la doc http://dev.mysql.com/doc/refman/5.0/fr/mysql-real-connect.html

    Votre code est particulièrement inélégant et dangereux :-t

    if (mysql_real_connect(conn, host, username, password, database, 0, NULL, 0) != NULL)
    	{
    	MessageBox("Connexions réussie");
    	
    	}
    	else
    	{
    		MessageBox("Connexion échouée");
    	}


    Paul Bacelar, Ex - MVP VC++

  • mardi 21 février 2012 18:49
     
      A du code

    J'ai vérifié, et non je ne l'ai pas utilisée ailleurs dans le code.

    J'ai donc aussi modifié le code comme vous me l'avez montré, effectivement c'est plus élégant.

    Et sans savoir pourquoi, ça marche maintenant, il m'affiche bien la message box comme quoi  la connection a réussie.

    Mais par contre, dans autre fenêtre, j'ai des champs ou je rentre donc les différents textes a saisir, queje veut stocker dans ma base de données. Je créer doncune variable pour chacun des champs. Et quand j'appuis sur le bouton ok de cette fenêtre, ça stocke donc ces valeurs dans la base de données.

    Voici le code:

    void AjouterDlg::OnBnClickedOk()
    {
    	char query[100];
    
    	UpdateData (TRUE); 
    	sprintf (query, "INSERT INTO 'cadres'('id', 'nom', 'prenom', 'hierarchie') VALUES('1',nom, prenom,hierarchie)");
    
    	OnOK();
    }

    Pour les values, je met le nom des variables que j'ai mis pour les différents champs.

    Mais, quand je compile, et que j'arrive a la fenêtre, et que je saisies les valeurs, et que j'appuis sur ok, ça ne se tocke pas dans la base de données.

  • mercredi 22 février 2012 13:15
    Modérateur
     
     

    le variable locale query une chaine de caractère et c'est tout.

    Pour faire une requête d'insertion, il faut utiliser les fonctions fournis par la librairie d'accès à MySQL choisis, genre mysql_query() or mysql_real_query()..

    http://dev.mysql.com/doc/refman/5.0/en/c-api-function-overview.html

    De plus, utiliser le "nom" des variables dans une chaine de requêtage n'a aucun sens.

    Je ne connais pas ces bibliothèques mais je pense qu'elles disposent d'un mécanisme de passage de paramètre plus évolué que la concaténation de valeur dans une chaine.

    Sinon, il fait remplacer le nom de la variable par sa valeur, avec les séquences d'échappement adéquates (utilisation de " ' et autre\ ).


    Paul Bacelar, Ex - MVP VC++

  • mercredi 22 février 2012 13:29
     
     

    Donc à la place de sprintf(query ...), j'utilise une fonction du genre mysql_query() ?

    Mais, dans les paramètres, je dois bien passer la requête Sql, le insert into, alors que dans cette fonction : mysql_query ou autre, je ne peut pas.

    Et mysql_query ou autres, sert a éxécuter la requête, tandis qu'avec mon sprintf, je m'en servait pour créer la requête.

    Donc, je ne comprends pas très bien.

    Car quand je compile et test ceci, il me trouve une exception au moment ou je clique sur ok, une fois les valeurs saisies.
    • Modifié tifil mercredi 22 février 2012 14:05
    •  
  • mercredi 22 février 2012 14:19
    Modérateur
     
      A du code

    Voici un tutoriel pour utiliser l'API C de MySql (dont l'insertion de données dans la base)

    http://zetcode.com/tutorials/mysqlcapitutorial/

    Il faut utiliser mysql_query pour demander à MySql d'exécuter la requête SQL.

    Il faut donc construire la requête SQL dans une chaine de caractère.

    Il vous faut donc une variable chaine pour stocker cette requête, par exemple votre variable "query", mais alors en beaucoup beaucoup plus gand. ;-)

    Dans la reqête, la variable de type char[], doit figurer les valeurs des variables et nom leur nom.

    donc

    sprintf (query, "INSERT INTO 'cadres'('id', 'nom', 'prenom', 'hierarchie') VALUES('1','%s', '%s','%s')",nom, prenom, hierarchie);

     (en espérant que nom, prenom, hierarchie n'ont pas de caractères à problème, sinon j'espère que cette bibliothèque offre les primitives nécessaire à l'escaping des valeurs)


    Paul Bacelar, Ex - MVP VC++


  • mercredi 22 février 2012 14:38
     
      A du code

    J'ai donc rajouté a la fin de mon sprintf, les variables crées. Mais, quand je rentre mes valeurs, et que j'appuis sur ok, ça ne se stocke pas dans la table.

    J'ai donc essayé avec le tuto que vous m'avez donné, j'ai utilisé cette ligne ci:

    mysql_query(conn, "INSERT INTO cadres VALUES('Leo Tolstoy')");

    Mais, même avec cette ligne, ça ne marche pas.

  • jeudi 23 février 2012 09:51
    Modérateur
     
     

    Primo, toujours vérifier les valeur de retour, au moins avec la macro VERIFY, mysql_query n'est pas une exception.

    Secundo, votre requête SQL est fausse si la table "cadre" contient plus d'une colonne, et je crois que c'est le cas.

    Faire du MySql ne vous libère pas de faire des requêtes SQL valides.

    Tertio, dans le tutoriel, il appel mysql_close, cela peut avoir une incidence sur le "commit" des transactions.


    Paul Bacelar, Ex - MVP VC++

  • jeudi 23 février 2012 11:02
     
      A du code

    En gros, je cherche juste à passer une variable(dont je saisie la valeur dans la fenêtre, via le champ de texte)  dans le VALUES au lieu de mettre directement sa valeur dans le code.

    Voici ma requête:

    mysql_query(conn, "INSERT INTO cadres(id,nom, prenom, hierarchie) VALUES(1,nom,prenom,hierarchie)");

    Donc, nom, prenom, hierarchie, doivent prendre comme valeur, la valeur saisie sur la fenêtre.

  • jeudi 23 février 2012 11:53
    Modérateur
     
      A du code

    sprintf (query, "INSERT INTO 'cadres'('id', 'nom', 'prenom', 'hierarchie') VALUES('1','%s', '%s','%s')",nom, prenom, hierarchie);

     

    mysql_query(conn, query);

    Paul Bacelar, Ex - MVP VC++

  • jeudi 23 février 2012 12:48
     
     

    J'avais déja essayé cette ligne, je l'ai donc réessayée, mais hélas, ça ne rajoute rien dans la base de données. 

  • jeudi 23 février 2012 14:33
    Modérateur
     
      A du code

    Oups, j'ai copié-collé votre code sans le vérifier.

    sprintf (query, "INSERT INTO cadres (id, nom, prenom, hierarchie) VALUES('1','%s', '%s','%s')",nom, prenom, hierarchie);

    mysql_query(conn, query);


    Si cela ne marche pas, mettez me résultat de l'affiche de la variable query dans une application client de MySQL pour vérifier la syntaxe SQL de la requête.

    Paul Bacelar, Ex - MVP VC++

  • jeudi 23 février 2012 17:20
     
      A du code

    Merci beaucoup, maintenant ça marche, c'était vraiment une simple chose a changer. Encore merci :)

    J'ai une autre question, maintenant je dois créer une méthode pour supprimer un champ de la table. Pour ce faire, je vais untiliser la requête sql delete from.

    Voici ma requête:

    void SupprimerDlg::OnBnClickedButton1Suppr()
    {
    
    	char query2[255];
    	UpdateData (TRUE);
    
    	sprintf (query2, "DELETE FROM cadres(id, nom, prenom, hierarchie) WHERE nom='nom_suppr'",nom_suppr);
    
    	mysql_query(conn2,query2);
    
    	OnOK();
    	mysql_close(conn2);
    
    }

    En effet, sur cette fenêtre, je rentre le nom de la personne, et je supprime son profil, donc c'est en fonction du nom de la personne que je rentre.

    Je déclare bien aussi conn2, via le Mysql *conn2., et nom_suppr étant la variable du champs.

    J'ai essayé la même méthode que pour ajouter, c'est à dire que je rajoute le nom de la variable du champ a la fin, mais hélas pas de résultats positifs.

    Donc, une nouvelle aide serait la bienvenue :)



    • Modifié tifil jeudi 23 février 2012 17:24
    •  
  • jeudi 23 février 2012 17:37
    Modérateur
     
      A du code

    Comme je vous l'ai déjà indiqué, il ne faut pas mettre le nom de la variable dans la requête, mais sa valeur.

    void SupprimerDlg::OnBnClickedButton1Suppr()
    {
    
    	char query2[255];
    	UpdateData (TRUE);
    
    	sprintf (query2, "DELETE FROM cadres(id, nom, prenom, hierarchie) WHERE nom='%s'",nom_suppr);
    
    	mysql_query(conn2,query2);
    
    	OnOK();
    	mysql_close(conn2);
    
    }

    Comme je vous l'ai déjà indiqué :

    > Je ne connais pas ces bibliothèques mais je pense qu'elles disposent d'un mécanisme de passage de paramètre plus évolué que la concaténation de valeur dans une chaine.

    Pourquoi cette remarque, c'est que votre code est très fragile à des entrés "mal formaté", et une vraie passoire sécuritaire car vulnérable à une attaque par SQL Injection.

    Pour l'illustrer, si nom_suppr contient la valeur entre accolade : {';DELETE TABLE user;}

    L'utilisateur aura réussi à supprimer la table user de votre base sans avoir rien d'autre à faire que de taper cette chaîne dans votre formulaire.

    Maintenant que vous maîtriser un peu mieux MySQL via le C++, potassez son API pour trouver une API/des fonctions plus "safe".


    Paul Bacelar, Ex - MVP VC++

  • jeudi 23 février 2012 19:11
     
     

    J'ai changé pour le %s, et hélas, ça n'efface pas dans la table.

    Et a propos, de la sécurité du code, vous avez tout à fait raison, je vais voir pour éviter le genre de problème que vous avez citez, où l'on rajoute ce que vous avez dit et ça efface la table.

  • jeudi 23 février 2012 19:21
    Modérateur
     
     

    Re, mais sans les typo. ;-)

    >Si cela ne marche pas, mettez le résultat de l'affichage de la variable "query(2)" dans une application client de MySQL pour vérifier la syntaxe SQL de la requête.

    >Primo, toujours vérifier les valeur de retour, au moins avec la macro VERIFY, mysql_query n'est pas une exception


    Paul Bacelar, Ex - MVP VC++

  • jeudi 23 février 2012 19:57
     
     

    J'affiche donc dans un message box, la valeur de query2, et voici ce que ça me dit:

    DELETE FROM cadres WHERE prenom="

  • vendredi 24 février 2012 10:53
    Modérateur
     
     

    J'affiche donc dans un message box, la valeur de query2, et voici ce que ça me dit:

    DELETE FROM cadres WHERE prenom="

    =" ??

    Votre requête nes pas valide en terme SQL.

    =''

    Cela serait plus correct et vous devez supprimer tout les enregistrements dans cadre ayant un prénom ''. '' est déférent de null.

    Prenez cette chaîne et copiez la dans un client MySQL, il devrait vous donnez les erreurs de syntaxe.

    S'il n'y en a pas, exécutez la requête SQL dans le client, il vous donnera le nombre de ligne supprimer.

    S'il y en a 0, c'est que votre requête est fausse sémantiquement.


    Paul Bacelar, Ex - MVP VC++

  • vendredi 24 février 2012 15:01
     
      A du code

    J'ai donc mis ma requête dans un client mysql (phpmyadmin), et quand il me trouve effectivement une erreur.

    Pour que la requête soit valide, il faut que je mette celle-ci:

    DELETE FROM cadres WHERE prenom='claude'

    claude étant un prénom que j'ai mis au hasard. Si je rajoute ma variable à la fin, il me trouve bien évidemment une erreur.

    Donc, comment faire pour qu'il me dise précisément où est l'erreur ?

  • vendredi 24 février 2012 16:16
    Modérateur
     
     

    nom ou prenom ???

    Le client MySQL vous indique le type d'erreur.

    Votre requête est incorrecte, mais, pour moi, le problème est dans la valeur de votre variable "nom_suppr" ou "prenom_supp".

    Et là, cela plus rien à voir avec MySQL mais plus avec votre code et les MFC.

    Les valeurs de ces variables sont-elles correctes juste avant l'initialisation de la variable query/query2 ?


    Paul Bacelar, Ex - MVP VC++

  • vendredi 24 février 2012 16:27
     
      A du code

    Je pense aussi que ça a avoir avec la variable, car quand je met dans ma requête prenom=%d sans les ' et non pas %s, il m'affiche comme valeur pour query2 ceci : 1632147832

    Et sinon, pour la variable query2, je l'initialise ainsi : 

    char query2[255];

    Et pour la variable nom_suppr, je ne l'initialise pas, je la déclare juste en tant que CString nom_suppr;

    • Modifié tifil vendredi 24 février 2012 16:36
    •  
  • vendredi 24 février 2012 17:21
    Modérateur
     
     

    Je pense que votre méconnaissance du type CString et l'utilisation d'API C (pas C++) est le coeur de votre problème.

    Regardez du coté de la méthode GetBuffer de la classe CString pour avoir un char* sur ma valeur de la chaîne de caractère stockée dans un CString.


    Paul Bacelar, Ex - MVP VC++

  • vendredi 24 février 2012 18:10
     
      A du code

    J'ai utilisé la méthode getbuffer, voici ma ligne de code:

    LPTSTR pString = nom_suppr.GetBuffer(0);
    MessageBox(pString);

    Mais ça n'affiche rien, mais si sa affiche quelque chose, que dois-je en faire ???

  • lundi 27 février 2012 08:01
    Modérateur
     
     

    Alors votre problème est juste un problème de transfert des données dans les contrôles Windows vers vos variables C++.

    Vérifiez votre mapping DDX/DDV.

    Cela n'a plus rien à voir avec l'accès aux données.


    Paul Bacelar, Ex - MVP VC++

  • lundi 27 février 2012 08:46
     
      A du code

    Je ne vois du tout l'erreur que j'ai.

    Voici la partie du code qui concernce les DDX/DDV:

    void SupprimerDlg::DoDataExchange(CDataExchange* pDX)
    {
    	CDialog::DoDataExchange(pDX);
    	DDX_Text(pDX, IDC_EDIT1_SUPPR, nom_suppr);
    }
    
    

    Dans le fichier header, la déclaration est bien faite:

    virtual void DoDataExchange(CDataExchange* pDX); 

  • lundi 27 février 2012 10:30
    Modérateur
     
     

    Vérifiez que c'est bien "IDC_EDIT1_SUPPR".

    Faites un nouveau sujet SVP.


    Paul Bacelar, Ex - MVP VC++

  • lundi 27 février 2012 13:21
     
     

    J'ai vérifié et il s'agit bien de IDC_EDIT1_SUPPR

    Ok, je vais donc recréer un autre sujet.