Nixeus
Messages postés192Date d'inscriptionjeudi 18 janvier 2007StatutMembreDernière intervention19 octobre 2020
-
5 mai 2007 à 11:28
racpp
Messages postés1909Date d'inscriptionvendredi 18 juin 2004StatutModérateurDernière intervention14 novembre 2014
-
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 )
24Karas
Messages postés233Date d'inscriptionjeudi 4 juillet 2002StatutMembreDernière intervention 5 juillet 2008 5 mai 2007 à 13:33
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 ?
Nixeus
Messages postés192Date d'inscriptionjeudi 18 janvier 2007StatutMembreDernière intervention19 octobre 2020 5 mai 2007 à 13:40
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);
}
BruNews
Messages postés21040Date d'inscriptionjeudi 23 janvier 2003StatutModérateurDernière intervention21 août 2019 6 mai 2007 à 00:51
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++
Vous n’avez pas trouvé la réponse que vous recherchez ?
racpp
Messages postés1909Date d'inscriptionvendredi 18 juin 2004StatutModérateurDernière intervention14 novembre 201417 6 mai 2007 à 13:18
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.
Nixeus
Messages postés192Date d'inscriptionjeudi 18 janvier 2007StatutMembreDernière intervention19 octobre 2020 6 mai 2007 à 15:22
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 " " ) ?
BruNews
Messages postés21040Date d'inscriptionjeudi 23 janvier 2003StatutModérateurDernière intervention21 août 2019 7 mai 2007 à 01:31
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.
racpp
Messages postés1909Date d'inscriptionvendredi 18 juin 2004StatutModérateurDernière intervention14 novembre 201417 7 mai 2007 à 01:55
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:
BruNews
Messages postés21040Date d'inscriptionjeudi 23 janvier 2003StatutModérateurDernière intervention21 août 2019 7 mai 2007 à 09:21
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).
Nixeus
Messages postés192Date d'inscriptionjeudi 18 janvier 2007StatutMembreDernière intervention19 octobre 2020 7 mai 2007 à 18:08
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
racpp
Messages postés1909Date d'inscriptionvendredi 18 juin 2004StatutModérateurDernière intervention14 novembre 201417 8 mai 2007 à 02:14
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.