IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 Delphi Discussion :

Utiliser les Blob dans une BDD MySQL via Delphi


Sujet :

Delphi

  1. #1
    Membre à l'essai
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Octobre 2017
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2017
    Messages : 16
    Points : 15
    Points
    15
    Par défaut Utiliser les Blob dans une BDD MySQL via Delphi
    Bonjour à tous,

    Je viens vers vous car les informations que je trouve sur le net à ce sujet sont floues voir fausses...

    Je suis débutant en Delphi et en MySQL et je dois stocker des images dans ma BDD.
    On m'a conseillé d'utiliser le format de données appelé "Blob".
    J'ai donc créé la BDD et jusque là, pas de souci.

    Seulement, je dois développer un gestionnaire de BDD en Delphi et j'ai donc besoin de gérer les Blobs.
    Pour cela, j'ai utilisé une méthode trouvé sur le net à base de "Stream" :

    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
    function TGestBDD_FDS.AjoutImage(pNom, pAdresse: string): boolean;
    var
      lStream: TStream;
      lJpg: TJpegImage;
    begin
      Result := False;
      try
        Result := ExecuteRequete(['INSERT INTO ' + TABLE_IMAGE,
                                 ' (' + FIELD_IMAGE_NOM + ')' +
                                 ' VALUES (' + QuotedStr(pNom) + ')']);
      finally
            FCnx.Close;
      end;
     
      lJpg := TJpegImage.Create;
      lJpg.LoadFromFile(pAdresse);
      try
        if ExecuteRequete(['SELECT * FROM ' + TABLE_IMAGE,
                           'WHERE (' + FIELD_IMAGE_NOM + ' = ' + QuotedStr(pNom) + ')']) then
        begin
          FQry.Edit;
          lStream := FQry.CreateBlobStream(FQry.FieldByName(FIELD_IMAGE_IMAGE), bmWrite);
          try
            lJpg.SaveToStream(lStream);
            FQry.ExecSQL;
          finally
            lStream.Free;
          end;
        end;
      finally
        lJpg.Free;
      end;
    end;
    Avec la fonction "ExecuteRequete" ci dessous :
    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
    function TGestBDD.ExecuteRequete(pLignes: array of string): Boolean;
    var
       i : Shortint;
    begin
         ConnectMySQL;
     
         // fermeture de la requête
         FQry.Close;
     
         // initialisation du SQL
         FQry.SQL.Clear;
     
         // remplissage de la requête
         for i := 0 to (Length(pLignes) - 1) do FQry.SQL.Add(pLignes[i]);
     
         try
            // si la requête est un select ou show
            if (Pos('SELECT', FQry.SQL[0]) > 0) or
               (Pos('SHOW'  , FQry.SQL[0]) > 0) then
            begin
                 // ouverture de la requête
                 FQry.Open;
                 // on se place sur le premier enregistrement
                 FQry.First;
            end
            // sinon exécution de la requête
            else FQry.ExecSQL;
     
            Result := True;
         except
               on E: Exception do
               begin
                    MessageBox(Application.Handle, PChar(E.Message + #13 + #13 + FQry.SQL.Text),
                               PChar('Erreur SQL'), MB_ICONERROR);
                    FQry.SQL.SaveToFile('SQL.txt');
                    Result := False;
               end;
         end;
    end;
    Seulement, j'ai l'impression que mon Blob ne s'est pas sauvegardé car j'ai toujours la valeur "Null" associé à mon champ LongBlob.
    Mes connaissances en Delphi étant limitées, il m'est compliqué de débuger seul ce problème..

    Merci beaucoup pour vos futures réponses et désolé pour cette question de débutant.
    Bien cordialement,
    William Durand.

  2. #2
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 043
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 043
    Points : 40 957
    Points
    40 957
    Billets dans le blog
    62
    Par défaut
    Bonjour et bienvenue,

    Je dois stocker des images dans ma BDD, on m'a conseillé d'utiliser le format de données appelé "Blob".
    c'est, généralement, une des deux solutions l'autre étant de stocker le nom complet de l'image
    Pour cela, j'ai utilisé une méthode trouvé sur le net à base de "Stream" :
    jusque là c'est la bonne voie, le code par contre , pourquoi faire une modification en trois temps, un insert pour la colonne Nom, puis Select pour finir par Update alors que un seul Insert est nécessaire ?

    Citation Envoyé par durand.william Voir le message
    Je viens vers vous car les informations que je trouve sur le net à ce sujet sont floues voir fausses...
    Avez vous consulté cette FAQ https://delphi.developpez.com/faq/?p...p-de-type-Blob ?

    vous y remarquerez l'utilisation de requête paramétrée qui aide grandement. Reste à savoir avec quels composants de connexion vous faites ceci, car il peut y avoir quelques petites minimes différences d'écriture du code
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  3. #3
    Membre à l'essai
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Octobre 2017
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2017
    Messages : 16
    Points : 15
    Points
    15
    Par défaut
    Bonjour et merci pour votre réponse.

    J'ai tester la méthode présente dans le lien que vous m'aviez posté et malheureusement j'ai eu l'erreur suivante :
    "Erreur lors de l'insertion de l'image dans la base de données : [Microsoft][Gestionnaire de pilotes ODBC] Source de données introuvable et nom de pilote non spécifié"

    Je passe par le pilotes suivant : "MySQL ODBC 3.51 Driver"

    Est-ce dû au driver qui serai trop vieux ou pas adapté à la gestion des BLOB ?


    Sinon, j'ai du mal avec la fonction "CreateBlobStream" :
    Cette fonction nécessite un champ TField et un mode ; pour le mode, ça va mais pour le champ je suis bloqué.
    Voilà ce que j'ai trouver sur le net (source : https://stackoverflow.com/questions/...google_rich_qa):

    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
    var
      Stream: TBlobStream;
      Jpg: TJpegImage;
    begin
      Jpg := TJpegImage.Create;
      try
        Jpg.Assign(Image1.Picture.Graphic);
        // Assign other query parameters here
        Stream := Qry.CreateBlobStream(Qry.FieldByName('BLOBVAL'), bmWrite);
        try
          Jpg.SaveToStream(Stream);
          Qry.ExecSQL;
        finally
          Stream.Free;
        end;
      finally
        Jpg.Free;
      end;
    end;
    (Je modifié ce code dans mon programme afin d'avoir les mêmes noms de variable.)
    Et voilà l'erreur que j'obtiens :
    "Le projet gestion_bdd_fds.exe a déclenché la classe d'exception EDatabaseError avec le message 'Champ 'image' non trouvé'.

    Je suis contiens que l'objet TDatabase nommé "FQry" dans mon code doit contenir le champ 'image' avec de faire fonctionner la fonction "FieldByName('image')".
    Mais à part en faisant une sélection au préalable, je ne vois pas comment faire...

    Avez-vous des suggestions à ce sujet ?

    Merci par avance.
    Bien cordialement,
    William D.

  4. #4
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 043
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 043
    Points : 40 957
    Points
    40 957
    Billets dans le blog
    62
    Par défaut
    Re,
    commençons par le commencement :
    1. Delphi , quelle version ?
    2. Quel composants entre en jeux avec la BDD : Firedac, ADO, BDE, DBExpress, autre ?

    Ok, pour vous connecter à la BDD vous passez par ODBC mais ça me dit pas avec quel composant Txxxxx

    Ensuite la structure de la Table, parce que ce n'est pas la peine de proposer un bout de code avec des colonnes qui un moment se nomme d'une manière puis change !
    je ne peux absolument pas répondre à ce message
    "Le projet gestion_bdd_fds.exe a déclenché la classe d'exception EDatabaseError avec le message 'Champ 'image' non trouvé'.
    si ce n'est de dire qu'il n'existe pas de colonne nommée "Image" dans la table mais cela peut être du à tout autre chose comme une déclaration de champs déjà existante etc...

    l'objet TDatabase ? ça c'est la connexion normalement "FQry" est plutôt un TQuery, ou autre (d'où ma demande #2)
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  5. #5
    Membre à l'essai
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Octobre 2017
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2017
    Messages : 16
    Points : 15
    Points
    15
    Par défaut
    Alors, je vais tenté de répondre de manière exhaustive :

    Delphi , quelle version ?
    J'utilise Delphi 2010.

    Quel composants entre en jeux avec la BDD : Firedac, ADO, BDE, DBExpress, autre ?
    Je pense utiliser ADO vu que mon objet FQry est déclaré en tant que TADOQuery;

    Ma table est la suivante :
    IMAGE :
    id (INT(10), PrimaryKey, NotNull, Unsigned, AutoIncrement)
    nom (VARCHAR(45), NotNull, Unique)
    image (BLOB)

    Je viens de corriger (au mieux) mon code.
    Cette fois il n'y a pas d'erreur mais le BLOB n'est pas chargé en mémoire dans ma table MySQL.
    Mon code complet est le suivant :
    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
    function TGestBDD_FDS.AjoutImage(pNom, pAdresse: string): boolean;
    var
      lStream: TStream;
      lJpg: TJpegImage;
    begin
      Result := False;
     
      ConnectMySQL;
      FQry.Close;
      FQry.SQL.Clear;
      FQry.SQL.Add('SELECT * FROM IMAGE WHERE (nom = ' + QuotedStr(pNom) + ')');
      FQry.Open;
      FQry.First;
      FQry.Edit;
     
      lJpg := TJpegImage.Create;
      try
        lJpg.LoadFromFile(pAdresse);
        lStream := FQry.CreateBlobStream(FQry.FieldByName('image'), bmWrite);
        try
          lJpg.SaveToStream(lStream);
          FQry.ExecSQL;
        finally
          lStream.Free;
        end;
      finally
        lJpg.Free;
      end;
    end;
    Et là il ne se passe rien dans la BDD...
    C'est à dire que le champ 'image' de la ligne sélectionnée reste null.
    J'ai essayé d'effectuer la commande "FQry.Post;" à la place de "FQry.ExecSQL;" à la ligne 22 et là, Delphi m'indique que je ne suis pas en mode édition ou insertion.
    Et ce, malgré la présence de "FQry.Edit;"...

    Avez-vous besoin d'informations supplémentaires ?
    Sinon, voyez-vous quel sont les éléments que j'ai mal géré ?
    Bien cordialement,
    WD.

  6. #6
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 043
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 043
    Points : 40 957
    Points
    40 957
    Billets dans le blog
    62
    Par défaut
    Re,

    Oui, c'est bien ADO, bien que ADO ne soit pas ma tasse de thé ! la FAQ que je vous ai indiqué est justement avec ADO.

    Votre erreur : avant tout le execsql de la ligne 22 de votre code

    modification de votre code
    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
     
    function TGestBDD_FDS.AjoutImage(pNom, pAdresse: string): boolean;
    var
      lStream: TStream;
      lJpg: TJpegImage;
    begin
      Result := False;
       ConnectMySQL;
      if fileExists(pAdresse) then 
      With fqry do 
        begin 
         Close; 
         SQL.Text:='INSERT INTO MaTable(Nom,image) Values(:PNom,:PFichier)'; 
         ParamCheck := True; 
         Parameters.ParamByName('PNom').Value := pnom; 
         Parameters.ParamByName('PFichier').LoadFromFile(pAdresse, ftBlob); 
       try 
        ExecSQL; 
        Result:=True;
      Except on E:Exception do 
        begin 
          Showmessage('Erreur lors de l''insertion de l''image dans la base de données : ' +  
           E.Message); 
        end; 
      end;  
    end;
    Dans votre code, ce qui pêche. Fqry est une requête SELECT or au lieu de faire un UPDATE vous réitérez ce SELECT ligne 22 cela ne peut pas fonctionner.
    Si vous utilisez un ensemble requête FQry pour ensuite vouloir modifier (Insertion, mise à jour ou suppression) vous devez passer ensuite par des commandes

    Comme je l'ai déjà écrit je ne connais pas/n'utilise pas ADO, je ne sais pas comment est traité une requête SELECT avec d'autres set de composants (i.e. ZEOSDBO, la requête serait associée à un composant UPDATESQL qui contiendrait les instructions UPDATE, INSERT, DELETE et même REFRESH au besooin)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
      // si Fqry est considéré comme une table 
      // insertion dans la table 
      FQry.Close;
      FQry.SQL.Text:='SELECT Image FROM Matable WHERE 1=0'; // autrement dit ensemble vide 
      FQry.Insert;
      FQry.FieldByName('Nom').asString:=Pnom;
      (FieldByName('Image') as TBlobField).LoadFromFile(pAdresse, ftBlob);  
      FQry.Post;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
      //si  Fqry est considéré comme une table 
      // modification  
      FQry.Close;
      FQry.SQL.Text:='SELECT Image FROM Matable WHERE nom= :pNom'; // je préfère passer par une requête paramétrée (évite l'injection de SQL) 
      FQry.ParamCheck := True; 
      FQry.Parameters.ParamByName('PNom').Value := pnom; 
      FQry.Open;  // pas besoin de faire FQry.First, on est déjà sur la 1°ligne après le open 
      FQry.Edit;
      (FieldByName('Image') as TBlobField).LoadFromFile(pAdresse, ftBlob);  
      FQry.Post;
    NB. si un "ADO" utilisateur peut confirmer mes deux derniers codes ?
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  7. #7
    Membre à l'essai
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Octobre 2017
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2017
    Messages : 16
    Points : 15
    Points
    15
    Par défaut
    Re-bonjour,

    J'ai enfin trouvé la solution :
    le driver ODBC pour MySQL ne prenait pas en charge les BLOBs (c'était la version 3.51).

    Après mise à jour du driver, j'ai pu utiliser la solution que vous m'aviez proposer dès le début.
    C'est à dire :

    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
    function TGestBDD_FDS.AjoutImage(pNom, pAdresse: string): boolean;
    var
      lStream: TStream;
      lBitmap: TBitmap;
    begin
      Result := False;
     
      ConnectMySQL;
     
      try
        lBitmap := TBitmap.Create;
        if fileExists(pAdresse) then lBitmap.LoadFromFile(pAdresse);
        With FQry do
        begin
          Close;
          SQL.Clear;
          SQL.add('insert into '+TABLE_IMAGE+'('+FIELD_IMAGE_NOM+','+FIELD_IMAGE_IMAGE+')');
          SQL.Add('Values(:PNom,:PFichier)');
          ParamCheck := True;
          Parameters.ParamByName('PNom').Value := pNom;
          Parameters.ParamByName('PFichier').Assign(lBitmap);
          try
            ExecSQL;
          Except on E:Exception do
            begin
              Showmessage('Erreur lors de l''insertion de l''image dans la base de données : ' +
              E.Message);
            end;
          end;
        end;
      finally
        lBitmap.free;
        FCnx.Close;
      end;
    end;
    Tout fonctionne parfaitement maintenant !
    Je vous remercie grandement car je sais à quel point aider quelqu'un qui n'a pas les bases peut s’avérer être fastidieux...

    Passez une bonne journée.
    Bien cordialement,
    William Durand.

    PS : la version du code ci-dessus n'est pas définitive, il reste des éléments à améliorer.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 5
    Dernier message: 06/02/2008, 16h01
  2. [MySQL] Envoyer les données d'un CSV dans une BDD Mysql
    Par guyfoot dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 24/09/2007, 07h13
  3. inserer des photos dans une bdd mysql
    Par oceane751 dans le forum Requêtes
    Réponses: 3
    Dernier message: 20/05/2006, 20h06
  4. A quoi servent les index dans une BDD ?
    Par Melvine dans le forum Décisions SGBD
    Réponses: 3
    Dernier message: 25/10/2005, 12h14
  5. Changements de colonnes dans une BDD MySQL
    Par arnaud_verlaine dans le forum Requêtes
    Réponses: 8
    Dernier message: 07/08/2003, 11h33

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo