OOP, templates et macros dans mql5, subtilités et utilisations - page 28

 
Maxim Kuznetsov:

Je me souviens que dans SQLite, les types de champs sont facultatifs et qu'il n'est pas nécessaire de s'embêter à spécifier et à couler les types. C'est "Lite" pour une raison.

vous pouvez diviser une longue requête en 3-4-5 requêtes :-)

BEGIN TRANSACTION

INSERT INTO myTable VALUES (...); --- тут можно получить PrimaryKey

UPDATE myTable .... ; --- обновить по Primary

UPDATE myTable ...  ; --- ещё...

COMMIT ; --- это если все запросы удачны.. иначе ROLLBACK

c'est de l'ancienne mémoire, donc vous devez vérifier dans l'aide

j'aimerais avoir un code de requête reproductible, cela prendra beaucoup de temps à googler, j'ai travaillé avec une base de données occasionnellement - j'ai un problème, je l'ai googlé, je l'ai résolu - mais j'aimerais voir une requête de base de données qui a échoué.

 
Vladimir Simakov:

Votre problème particulier devrait être résolu comme suit :

string MakeRequest(string md5txt){
   static ENUM_STATISTICS intIndex[]={STAT_CONPROFITMAX_TRADES,
                                      STAT_MAX_CONPROFIT_TRADES,
                                      STAT_CONLOSSMAX_TRADES,
                                      STAT_MAX_CONLOSS_TRADES,
                                      STAT_DEALS,
                                      STAT_TRADES,
                                      STAT_PROFIT_TRADES,
                                      STAT_LOSS_TRADES,
                                      STAT_SHORT_TRADES,
                                      STAT_LONG_TRADES,
                                      STAT_PROFIT_SHORTTRADES,
                                      STAT_PROFIT_LONGTRADES,
                                      STAT_PROFITTRADES_AVGCON,
                                      STAT_LOSSTRADES_AVGCON};
   string ret="INSERT INTO \"TesterStatistics\" + StringFormat(" set md5= %d ,md5txt),
   for (int i=0,ii=0;i<=STAT_LOSSTRADES_AVGCON;++i){
      ret+=",";
      if (i==intIndex[ii]){
         ret+=StringFormat("%s = %d,",EnumToString((ENUM_STATISTICS)i),(int)TesterStatistics((ENUM_STATISTICS)i) ));
         ++ii;}
      else ret+=StringFormat("%s =%G",EnumToString((ENUM_STATISTICS),i),TesterStatistics((ENUM_STATISTICS)i));}
   return ret;}
   
DatabaseExecute(handleDB, MakeRequest("md5txt"));

une petite correction, avec plus de parenthèses à corriger :-)
l'idée principale n'est pas d'utiliser UPDATE x VALUES (), mais UPDATE x SET nom1=valeur1,nom2=valeur2. Pour que la requête fonctionne correctement si la structure de la base de données est modifiée et ne dépende pas de l'ordre des champs

 

il y a approximativement le code suivant (je lis les champs de texte de la base de données et je veux les convertir en enum)

class MyClass
{
public:
   enum A            {Aq, Aw, Ae, Ar, At, Ay};
   enum B            {Bq, Bw, Be};
   enum C            {Cq, Cw, Ce, Cr};

   static bool       txtToEnumA(const string txt, A &result);
   static bool       txtToEnumB(const string txt, B &result);
   static bool       txtToEnumC(const string txt, C &result);
};
//+------------------------------------------------------------------+
static bool MyClass::txtToEnumA(const string txt, A &result)
{
   for(int i = 0; i <= (int)A::Ay; i++)
   {
      if(StringCompare(EnumToString((A)i), txt) == 0)
      {
         result = (MyClass::A)i;
         return(true);
      }
   }
   return(false);
}
//+------------------------------------------------------------------+
static bool MyClass::txtToEnumB(const string txt, B &result)
{
   for(int i = 0; i <= (int)B::Be; i++)
   {
      if(StringCompare(EnumToString((B)i), txt) == 0)
      {
         result = (MyClass::B)i;
         return(true);
      }
   }
   return(false);
}
//+------------------------------------------------------------------+
static bool MyClass::txtToEnumC(const string txt, C &result)
{
   for(int i = 0; i <= (int)C::Cr; i++)
   {
      if(StringCompare(EnumToString((A)i), txt) == 0)
      {
         result = (MyClass::C)i;
         return(true);
      }
   }
   return(false);
}
//+------------------------------------------------------------------+
void OnStart()
{
   MyClass::A a;
   MyClass::B b;
   MyClass::C c;
   string txt[] = {"Aq", "Bw", "No"};

   if(MyClass::txtToEnumA(txt[0], a)) Print(txt[0], " in A = ", EnumToString(a));
   else Print("Error, ", txt[0], " not in A");

   if(MyClass::txtToEnumB(txt[1], b)) Print(txt[1], " in B = ", EnumToString(b));
   else Print("Error, ", txt[1], " not in B");

   if(MyClass::txtToEnumC(txt[2], c)) Print(txt[2], " in C = ", EnumToString(c));
   else Print("Error, ", txt[2], " not in C");
}
//+------------------------------------------------------------------+

2020.09.01 18:59:02.593 tst (EURUSD,M5) Aq dans A = Aq

2020.09.01 18:59:02.593 tst (EURUSD,M5) Bw in B = Bw

2020.09.01 18:59:02.593 tst (EURUSD,M5) Erreur, Non pas dans C

Tout fonctionne, mais la question porte à nouveau sur le code optimal :

s'il y a un moyen d'écrire à la place de txtToEnumA() , txtToEnumB(), txtToEnumC()

une méthode de modèle (modèle)

Le problème est le nombre différent d'éléments dans l'enum.

 

Et s'il y a un enum :

enum A            {Aq=10, Aw=9, Ae=8, Ar=7, At=6, Ay=5};

?

 
Dmitry Fedoseev:

Et s'il y a un enum :

?

la numérotation des éléments de l'enum n'est pas une question, on ne voit pas bien à quoi cela servirait

Je n'ai que 4 énumérations, non numérotées.

le problème est que je peux vouloir ajouter de nouveaux éléments à l'énumération - dans mon code, je vais ajouter de nouveaux éléments PAS les plus extérieurs - le code fonctionnera - je n'aime pas la lourdeur de ce code


mais nous ne parlons pas d'un code universel pour toutes les occasions, nous avons besoin des tâches actuelles dans un modèle.


SZY : je ne peux pas me passer de l'énumération - c'est pratique, je peux lire les données aussi bien dans la source que dans la base de données, et dans la base de données, je veux peut-être corriger certains champs manuellement..... en général, tout me convient

 
Igor Makanu:

la numérotation des éléments de l'énumération n'est pas un problème, on ne sait pas ce que cela va donner

Je n'ai que 4 énumérations, non numérotées.

le problème est que je peux vouloir ajouter de nouveaux éléments aux listes - dans mon code, je n'ajouterai pas de nouveaux éléments à ceux qui sont le plus à l'extérieur - le code fonctionnera - je n'aime pas la lourdeur du code.


mais nous ne parlons pas d'un code universel pour toutes les occasions, nous avons besoin des tâches actuelles dans un modèle.


SZY : je ne peux pas me passer de l'énumération - c'est pratique, je peux lire les données aussi bien dans la source que dans la base de données, et dans la base de données, je veux peut-être corriger certains champs manuellement..... tout me convient parfaitement

créer un tableau global et le remplir de paires { EnumToString(x) , x }

struct StringID {

   string str;

   int id;

};

StringID IDS[];

et les modèles seront inutiles.
 
Maxim Kuznetsov:

créer un tableau global et le remplir de paires { EnumToString(x) , x }

struct StringID {

   string str;

   int id;

};

StringID IDS[];

et vous n'aurez pas besoin de modèles.

Votre façon de faire n'est pas très différente de la mienne - elle est aussi très lourde, et s'il y a des changements dans le code, vous devrez aussi modifier les tableaux.

 

a résolu mon souhait de cette façon :

class MyClass
{
public:
   enum A            {Aq, Aw, Ae, Ar, At, Ay};
   enum B            {Bq, Bw, Be};
   enum C            {Cq, Cw, Ce, Cr};
   template<typename T>
   static bool       txtToEnum(const T LastElement, const string txt, T &result);
};
//+------------------------------------------------------------------+
template<typename T>
static bool MyClass::txtToEnum(const T LastElement, const string txt, T &result)
{
   for(int i = 0; i <= (int)LastElement; i++)
   {
      if(StringCompare(EnumToString((T)i), txt) == 0)
      {
         result = (T)i;
         return(true);
      }
   }
   return(false);
}
//+------------------------------------------------------------------+
void OnStart()
{
   MyClass::A a;
   MyClass::B b;
   MyClass::C c;
   string txt[] = {"Aq", "Bw", "No"};

   if(MyClass::txtToEnum(MyClass::Ay, txt[0], a)) Print(txt[0], " in A = ", EnumToString(a));
   else Print("Error, ", txt[0], " not in A");

   if(MyClass::txtToEnum(MyClass::Be, txt[1], b)) Print(txt[1], " in B = ", EnumToString(b));
   else Print("Error, ", txt[1], " not in B");

   if(MyClass::txtToEnum(MyClass::Cr, txt[2], c)) Print(txt[2], " in C = ", EnumToString(c));
   else Print("Error, ", txt[2], " not in C");

}
//+------------------------------------------------------------------+

2020.09.01 22:08:47.417 tst (EURUSD,M5) Aq dans A = Aq

2020.09.01 22:08:47.417 tst (EURUSD,M5) Bw in B = Bw

2020.09.01 22:08:47.417 tst (EURUSD,M5) Erreur, Non pas dans C



J'ai besoin de plus de définitions pour ne pas entrer dans LastElement, mais dans l'ensemble ce code est plus compact.

 
Combien faut-il pour écrire toutes sortes de choses ?