ADO, select sur un champ vide, plante mon appli [Résolu]

Nixeus 183 Messages postés jeudi 18 janvier 2007Date d'inscription 5 juin 2018 Dernière intervention - 5 mai 2007 à 11:28 - Dernière réponse : racpp 1910 Messages postés vendredi 18 juin 2004Date d'inscription 14 novembre 2014 Dernière intervention
- 8 mai 2007 à 02:14
Bonjour a tous !

J'utilise ADO en mfc, et je viens de remarquer que lorsqu'une requete SELECT "pointe" sur un champ vide (non renseigné), cela part en exception au niveau du traitement de mon recordset ( que j'ai mis dans un try catch )

Ca viendrais aparamment du mon cast en t_variant vers un CString.

Je souhaitais savoir si il y a un moyen d'éviter se plantage en c++, ou mieux, directement dans la base de donnée ( ACCESS 2003 )

Merci a tous et bonne journée
Afficher la suite 

Votre réponse

19 réponses

Meilleure réponse
BruNews 21054 Messages postés jeudi 23 janvier 2003Date d'inscription 7 novembre 2014 Dernière intervention - 7 mai 2007 à 22:13
3
Merci
Mais c'est quoi ça ???
J'ai publié des sources ADO, tu pourrais au moins aller prendre exemple.

#define isNotNull(var) (int) (var.vt != VT_NULL)


while(!prs->EndOfFile) {
  // EXEMPLE
  var = prs->Fields->GetItem((long)2)->Value; // 3eme CHAMP
  isNotNull(var) {


  }
  else {


  }
  prs->MoveNext();
}

ciao...
BruNews, MVP VC++

Merci BruNews 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 123 internautes ce mois-ci

Commenter la réponse de BruNews
24Karas 233 Messages postés jeudi 4 juillet 2002Date d'inscription 5 juillet 2008 Dernière intervention - 5 mai 2007 à 13:33
0
Merci
si tu pouvais coller la partie du code qui plante ça serait utile ...
 Tu peux pas tester le retour de ta requete et ne pas effectuer le cast si aucun resultat ?

++
Commenter la réponse de 24Karas
Nixeus 183 Messages postés jeudi 18 janvier 2007Date d'inscription 5 juin 2018 Dernière intervention - 5 mai 2007 à 13:40
0
Merci
Voici mon code, ba en fait, l'interpretation de ma requete est déja dans un try catch !

 m_strRequete="SELECT STATUT FROM UTILISATEUR WHERE ID_CARTE=3128";
 _RecordsetPtr m_pRecordSet=m_pDialog->m_MaBase.ExecuteSql(m_strRequete); // J'execute ma requete, je stocke le recordset.


 ///////////////////////////////////////////////////////////////////////////////////////////
 //////// JE TRAITE MON RECORDSET AFIN DE SAVOIR LE STATUT DE L'UTILISATEUR ////////////////
 ///////////////////////////////////////////////////////////////////////////////////////////


 TESTHR(m_pRecordSet.CreateInstance(__uuidof(Recordset)));//On crée un recordset vide:


 try
 {
  _variant_t var;// variable pour récupérer des données du recordset
  m_pRecordSet->PutRefActiveConnection( m_pDialog->m_MaBase.GetPtrConnection()); // Type de connection
  // GetPtrConnection me sert à récupérer le pointeur sur ma connection
  m_pRecordSet->Open((LPCTSTR)m_strRequete, vtMissing, adOpenDynamic,adLockBatchOptimistic, -1); // Requete SQL
  m_pRecordSet->MoveFirst(); // Initialisation du recordset
  
  ///////////////////////////////////////////////////////////////////////////////////
  /////   Je récupère le statut de l'utilisateur et le stocke dans m_nStatut   //////
  ///////////////////////////////////////////////////////////////////////////////////


  while (!m_pRecordSet->EndOfFile) // Tant que la fin du recordset n'est pas atteinte
  {
   var=m_pRecordSet->Fields->GetItem((long)0)->Value;               // Récupération de la valeure du recordset
   CString strStatut=(LPCTSTR)_bstr_t(var);                                   // On CASTE la valeur vers un CString
   m_pRecordSet->MoveNext();                                                     // lecture de l'index suivant du recordset.


   if (strStatut=="M") // Le statut de l'utilisateur est "Maintenance"
    m_nStatut=0;
   
   if (strStatut=="P")// Le statut de l'utilisateur est "Professeur"
    m_nStatut=1;
   
   if (strStatut=="E")// Le statut de l'utilisateur est "Eleve"
    m_nStatut=2;


  }


 }
 catch(_com_error) // Si erreur durant l'interpretation du recordset
 {
  MessageBox(0,"Erreur au niveau du recordset, impossible de connaitre le statut","ERREUR",MB_OK);
 }
Commenter la réponse de Nixeus
BruNews 21054 Messages postés jeudi 23 janvier 2003Date d'inscription 7 novembre 2014 Dernière intervention - 6 mai 2007 à 00:51
0
Merci
m_pRecordSet->Open((LPCTSTR)m_strRequete, vtMissing, adOpenDynamic,adLockBatchOptimistic, -1); // Requete SQL
m_pRecordSet->MoveFirst();  NON, badaboum si recordset est vide.
Le recordset est toujours à l'ouverture sur le 1er enreg s'il existe. 

CString strStatut=(LPCTSTR)_bstr_t(var); NON NON

#define isNotNull(var) (int) (var.vt != VT_NULL)
CString strStatut;
if(isNotNull(var)) strStatut=(LPCTSTR)_bstr_t(var);
else strStatut = ""; // PAR EXEMPLE

ciao...
BruNews, MVP VC++
Commenter la réponse de BruNews
racpp 1910 Messages postés vendredi 18 juin 2004Date d'inscription 14 novembre 2014 Dernière intervention - 6 mai 2007 à 13:18
0
Merci
Salut,
Comme signalé par BruNews, l'appel de certaines méthodes est interdit si le recordset est vide. Pour savoir si le recordset est vide ou non on fait comme ceci:
ADO_LONGPTR count= m_pRecordSet->RecordCount;
if(count)
{
    // travailler avec le recordset
}
else
{
// faire autre chose
}

Pour avoir une description de l'erreur de l'exception dans le messagebox tu peux faire:
 catch(_com_error &erreur)
 {
  MessageBox(0,(LPCSTR)erreur.Description(),"ERREUR",MB_OK);
// ajouter code ici
 }
Il est préférable d'ajouter du code à ce catch pour  éviter le plantage du programme.
Commenter la réponse de racpp
Nixeus 183 Messages postés jeudi 18 janvier 2007Date d'inscription 5 juin 2018 Dernière intervention - 6 mai 2007 à 15:22
0
Merci
Merci a tous pour vos réponses !
Je vais donc tout d'abord enlever mon "MoveFirst"

Pour le :

#define isNotNull(var) (int) (var.vt != VT_NULL)
CString strStatut;
if(isNotNull(var)) strStatut=(LPCTSTR)_bstr_t(var);
else strStatut = ""; // PAR EXEMPLE

L'idée est géniale, mais mes variable ne sont jamais les meme ( strStatut) dc, je pense que je vais essayer avec

ADO_LONGPTR count= m_pRecordSet->RecordCount;
if(count)
{
    // travailler avec le recordset
}
else
{
// faire autre chose
}

Merci a tous, je vais tester cela, et espère que cela ira !
Sinon, pas moyen d'en Acces de forcer a mettre les champ vide a une valeure ( NULL, ou 0, ou " " ) ?
Commenter la réponse de Nixeus
BruNews 21054 Messages postés jeudi 23 janvier 2003Date d'inscription 7 novembre 2014 Dernière intervention - 6 mai 2007 à 20:43
0
Merci
Attention que lire RecordCount pourrait s'avérer couteux.
Un recordset vide est signalé par BOF && EOF positionnés.

Bien entendu Access prend des valeurs par défaut sur les champs.

ciao...
BruNews, MVP VC++
Commenter la réponse de BruNews
Nixeus 183 Messages postés jeudi 18 janvier 2007Date d'inscription 5 juin 2018 Dernière intervention - 6 mai 2007 à 20:47
0
Merci
A, donc je pourrais faire un teste avec BOF && EOF avant de traiter mon recordset?
Commenter la réponse de Nixeus
BruNews 21054 Messages postés jeudi 23 janvier 2003Date d'inscription 7 novembre 2014 Dernière intervention - 6 mai 2007 à 20:49
0
Merci
c'est ce que tu fais dans:
while (!m_pRecordSet->EndOfFile)

Il te suffit donc d'un test BOF avant la boucle.

ciao...
BruNews, MVP VC++
Commenter la réponse de BruNews
racpp 1910 Messages postés vendredi 18 juin 2004Date d'inscription 14 novembre 2014 Dernière intervention - 7 mai 2007 à 01:19
0
Merci
Brunews > J'aimerais bien savoir pourquoi lire RecordCount pourrait être couteux. Je l'utilise très souvent sans jamais rien remarquer. Merci.
Commenter la réponse de racpp
BruNews 21054 Messages postés jeudi 23 janvier 2003Date d'inscription 7 novembre 2014 Dernière intervention - 7 mai 2007 à 01:31
0
Merci
RecordCount n'est pas rempli dès l'ouverture, il est obtenu par MoveLast et MoveFirst (c'est là le couteux en fait) interne si le recordset n'a pas deja été balayé en totalité. Ce n'est pas propre à ADO, idem avec ODBC ou toute autre voie d'accès et aussi je pense quelle que soit le SGDB fournisseur.

MSDN dit ceci (entre autre):
If the Recordset object supports approximate positioning or bookmarks—that is, Supports (adApproxPosition) or Supports (adBookmark), respectively, return True—this value will be the exact number of records in the Recordset, regardless of whether it has been fully populated. If the Recordset object does not support approximate positioning, this property may be a significant drain on resources because all records will have to be retrieved and counted to return an accurate RecordCount value.

ciao...
BruNews, MVP VC++
Commenter la réponse de BruNews
racpp 1910 Messages postés vendredi 18 juin 2004Date d'inscription 14 novembre 2014 Dernière intervention - 7 mai 2007 à 01:55
0
Merci
Merci pour les précisions. Il parait que je ne suis pas encore tombé sur ce genre de cas car j'obtiens  le RecordCount exact sans jamais passer par MoveLast() et MoveFirst(). Je fais comme ceci par exemple:

_RecordsetPtr   prs=0;
prs.CreateInstance (__uuidof (Recordset));
prs->CursorLocation = adUseClient;
prs->Open("SELECT * FROM table1;" , pdb.GetInterfacePtr(), adOpenDynamic, adLockOptimistic, adCmdText);
ADO_LONGPTR count= prs->RecordCount;

Ca a toujours marché avec des bases Access, MS SQL et MySQL.
Il y'a surement des détails que j'ignore mais ça ne m'a jamais posé de problème.
Commenter la réponse de racpp
BruNews 21054 Messages postés jeudi 23 janvier 2003Date d'inscription 7 novembre 2014 Dernière intervention - 7 mai 2007 à 09:21
0
Merci
Non non, me suis mal expliqué.
C'est EN INTERNE que ça se fait le balayage à la demande de RecordCount s'il n'a pas deja été rempli. Du temps de DAO il fallait le faire explicitement (hors OpenTable mais revenait au même).

ciao...
BruNews, MVP VC++
Commenter la réponse de BruNews
Nixeus 183 Messages postés jeudi 18 janvier 2007Date d'inscription 5 juin 2018 Dernière intervention - 7 mai 2007 à 10:28
0
Merci
Merci pour vos précision, alors je vais déja faire fon test de BOF avant ma boucle why !
Commenter la réponse de Nixeus
Nixeus 183 Messages postés jeudi 18 janvier 2007Date d'inscription 5 juin 2018 Dernière intervention - 7 mai 2007 à 18:08
0
Merci
Ok, je viens de tester, mais le problème est qu'avec une requete sur plusieurs tables, si je n'ai qu'un seul champ "vide", comment faire pour ne pas que cela plante, car aparamment avec le BOF je ne vois pas. Je donne un exemple concret de mon code :

 m_strRequete="SELECT UTILISATEUR.NOM,UTILISATEUR.PRéNOM,UTILISATEUR.NOM_CLASSE,UTILISATEUR.EST_PASSé,CARTEBLOQUEE, ADMINISTRATION.TARIF_REPAS_ELEVE FROM UTILISATEUR, ADMINISTRATION WHERE UTILISATEUR.ID_CARTE="+m_strMessageRecu;
  _RecordsetPtr m_pRecordSet=m_pDialog->m_MaBase.ExecuteSql(m_strRequete); // J'execute ma requete


  TESTHR(m_pRecordSet.CreateInstance(__uuidof(Recordset)));//On crée un recordset vide:


  try
  { 
   _variant_t var;// variable pour récupérer des données du recordset
   m_pRecordSet->PutRefActiveConnection( m_pGestionBd->GetPtrConnection()); // Type de connection
   m_pRecordSet->Open((LPCTSTR)m_strRequete, vtMissing, adOpenDynamic,adLockBatchOptimistic, -1); // Requete SQL
  
  /////////////////////////////////////////////////////////////////////////////////////
  ///////     Je récupère les champs nécéssaires aux vérifs et les stockes   ///////
  /////////////////////////////////////////////////////////////////////////////////////
 
   var=m_pRecordSet->Fields->GetItem((long)0)->Value; // Récupération du NOM
   m_strNom = (LPCTSTR)_bstr_t(var);
   var=m_pRecordSet->Fields->GetItem((long)1)->Value; // Récupération du PRENOM
   m_strPrenom = (LPCTSTR)_bstr_t(var);
   var=m_pRecordSet->Fields->GetItem((long)2)->Value; // Récupération de la CLASSE
   m_strClasse= (LPCTSTR)_bstr_t(var);
   var=m_pRecordSet->Fields->GetItem((long)3)->Value; // Savoir si l'élève a déja mangé aujourd'hui
   m_nEstPasse=long(var);
   var=m_pRecordSet->Fields->GetItem((long)4)->Value; // Savoir si carte bloquée
   m_nEstBloque=long(var);
   var=m_pRecordSet->Fields->GetItem((long)5)->Value; // Récupération du TARIF REPAS ELEVE
   m_nTarifRepasProfesseur=long(var);
  
   
  }


  catch(_com_error) // Si erreur durant l'interpretation du recordset
  {
   MessageBox(0,"Erreur au niveau du recordset pour récupérer NOM,PRENOM,CLASSE,DEJA MANGER,TARIF","ERREUR",MB_OK);
  }

Dans cette exemple le champ "classe" est vide, et la, badaboum, ca tombe dans le try catch
Commenter la réponse de Nixeus
BruNews 21054 Messages postés jeudi 23 janvier 2003Date d'inscription 7 novembre 2014 Dernière intervention - 7 mai 2007 à 20:39
0
Merci
Pour un champ j'ai répondu plus haut, aucun rapport avec BOF ou EOF, suffit de tester le champ var.vt si est NULL.

ciao...
BruNews, MVP VC++
Commenter la réponse de BruNews
Nixeus 183 Messages postés jeudi 18 janvier 2007Date d'inscription 5 juin 2018 Dernière intervention - 7 mai 2007 à 20:57
0
Merci
Oui brunews, donc je devrais faire un truc du genre?

for (i=0  ,  i< m_pRecordSet->enfOfFile  ,  i++)

{
      if (m_pRecordSet->Fields->GetItem((long)i)->Value != NULL)
      {
            // Je traite mon recordset

      }
}
Commenter la réponse de Nixeus
Nixeus 183 Messages postés jeudi 18 janvier 2007Date d'inscription 5 juin 2018 Dernière intervention - 7 mai 2007 à 22:47
0
Merci
Desole !
Merci pour ton aide!
Bonne soirée.
Commenter la réponse de Nixeus
racpp 1910 Messages postés vendredi 18 juin 2004Date d'inscription 14 novembre 2014 Dernière intervention - 8 mai 2007 à 02:14
0
Merci
Merci BruNews pour les explications sur RecordCount. C'est ce genre de détails que j'ignorais. J'avais du mal à imaginer que les SGBD sophistiqués agiraient ainsi. Pourtant, j'étais une fois très étonné par la vitesse d'exécution de 96 requettes SQL consécutives (dans une boucle) suivies chacune de la récupération du RecordCount. Le but était de faire des statistiques sur le nombre d'élèves appartenant à une vingtaine de tranches d'age, selon leurs niveaux, leur sexe etc,  et ce pour plus de 3000 élèves d'un établissement. L'affichage des statistique est immédiat. Je pense donc que ce problème sera plutôt perceptible avec les grosses bases de données car personnellement je n'ai jamais eu l'occasion de le remarquer.
Commenter la réponse de racpp

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.