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

QxOrm Discussion :

Script de création de base de données compatible SQLite


Sujet :

QxOrm

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    151
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 151
    Points : 49
    Points
    49
    Par défaut Script de création de base de données compatible SQLite
    Bonjour à tous,

    J'ai modifié le script de création de la base de donnée de façon à ce qu'il soit compatible avec SQLite.

    Voici ce qu'il y avait avant:
    (au passage, il y a une erreur dans le fetch, il est indiqué le champ "id=" au lieu de "name="):

    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
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    void updateDatabaseVersion()
    {
      try
      {
        int domainVersion = qApp->property("DomainVersion").toInt();
    
        // On se connecte avec un utilisateur de la base de données qui a les droits de modifications du schéma
        QSqlDatabase db = qx::QxSqlDatabase::getSingleton()->getDatabaseCloned();
        db.setUserName("MyAdminLogin");
        db.setPassword("MyAdminPassword");
    
        // On s'assure que la session démarre une transaction et lève une exception à la moindre erreur
        qx::QxSession session(db, true, true);
    
        // On "fetch" la version de la base de données avec un verrou pour éviter les modifications concurrentes !
        // Si plusieurs utilisateurs lancent l'application en même temps et qu'une mise à jour
        // est nécessaire, le premier fera la mise à jour, et les autres seront en attente
        DatabaseVersion dbVersion;
        session.fetchByQuery(qx_query("WHERE id='MyAppName' FOR UPDATE"), dbVersion);
    
        // Pour les autres utilisateurs, une fois le verrou levé, on vérifie si la mise à jour est toujours nécessaire
        if (dbVersion.version >= domainVersion) { return; }
    
        // On exécute chaque instruction SQL avec la variable "query"
        QSqlQuery query(db);
    
        // On récupère toutes les classes persistantes C++ enregistrées dans le contexte QxOrm
        qx::QxCollection<QString, qx::IxClass *> * pAllClasses = qx::QxClassX::getAllClasses();
        if (! pAllClasses) { qAssert(false); return; }
    
        // on récupère la liste des tables existantes dans la base (fonction de Qt)
        QStringList tables = db.tables();
    
        for (long k = 0; k < pAllClasses->count(); k++)
        {
          qx::IxClass * pClass = pAllClasses->getByIndex(k);
          if (! pClass) { continue; }
    
          // Filtre les classes non persistantes
          if (pClass->isKindOf("qx::service::IxParameter") || pClass->isKindOf("qx::service::IxService")) { continue; }
    
          // Filtre les classes à jour : si la version de pClass est <= à la version enregistrée dans la base, la mise à jour n'est pas nécessaire
          if (pClass->getVersion() <= dbVersion.version) { continue; }
    
          // On crée la table si elle n'existe pas, et on définit son propriétaire
          if (! tables.contains(pClass->getName()))
          {
            query.exec("CREATE TABLE " + pClass->getName() + " ( ) WITH (OIDS = FALSE);"
                       "ALTER TABLE " + pClass->getName() + " OWNER TO \"MyAdminLogin\";");
            session += query.lastError();
          }
    
          // On ajoute les colonnes à la table si elles n'existent pas
          qx::IxDataMemberX * pDataMemberX = pClass->getDataMemberX();
          for (long l = 0; (pDataMemberX && (l < pDataMemberX->count_WithDaoStrategy())); l++)
          {
            qx::IxDataMember * p = pDataMemberX->get_WithDaoStrategy(l);
            if (! p || (p->getVersion() <= dbVersion.version)) { continue; }
    
            query.exec("ALTER TABLE " + pClass->getName() + " ADD COLUMN " + p->getName() + " " + p->getSqlType() + ";");
            session += query.lastError();
    
            if (p->getIsPrimaryKey()) // PRIMARY KEY
            {
              query.exec("ALTER TABLE " + pClass->getName() + " ADD PRIMARY KEY (" + p->getName() + ");");
              session += query.lastError();
            }
    
            if (p->getAllPropertyBagKeys().contains("INDEX")) // INDEX
            {
              query.exec("CREATE INDEX " + pClass->getName() + "_" + p->getName() + "_idx" + 
                         " ON " + pClass->getName() + " USING " + p->getPropertyBag("INDEX").toString() + " (" + p->getName() + ");");
              session += query.lastError();
            }
    
            if (p->getNotNull()) // NOT NULL
            {
              query.exec("ALTER TABLE " + pClass->getName() + " ALTER COLUMN " + p->getName() + " SET NOT NULL;");
              session += query.lastError();
            }
    
            if (p->getAutoIncrement()) // AUTO INCREMENT
            {
              query.exec("CREATE SEQUENCE " + pClass->getName() + "_" + p->getName() + "_seq" + "; "
                         "ALTER TABLE " + pClass->getName() + "_" + p->getName() + "_seq" + " OWNER TO \"MyAdminLogin\"; "
                         "ALTER TABLE " + pClass->getName() + " ALTER COLUMN " + p->getName() + " " +
                         "SET DEFAULT nextval('" + pClass->getName() + "_" + p->getName() + "_seq" + "'::regclass);");
              session += query.lastError();
            }
    
            if (p->getDescription() != "") // DESCRIPTION
            {
              // $$ceci est un texte ne nécessitant pas de caractères d'échappement dans postgres grace aux doubles dolars$$
              query.exec("COMMENT ON COLUMN " + pClass->getName() + "." + p->getName() + " IS $$" + p->getDescription() + "$$ ;");
              session += query.lastError();
            }
          }
        }
    
        // On enregistre la version courante de la base de données
        dbVersion.version = domainVersion;
        session.save(dbVersion);
    
        // Fin du block "try" : la session est détruite => commit ou rollback automatique
        // De plus, un commit ou rollback sur la transaction lève automatiquement le verrou posé précédemment
      }
      catch (const qx::dao::sql_error & err)
      {
        QSqlError sqlError = err.get();
        qDebug() << sqlError.databaseText();
        qDebug() << sqlError.driverText();
        qDebug() << sqlError.number();
        qDebug() << sqlError.type();
      }
    }
    Et voici une version compatible avec SQLite:

    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
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    void updateDatabaseVersion()
    {
        try {
            int domainVersion = qApp->property( "DomainVersion" ).toInt();
     
            // We connect to the database with an user that has rights for the database creation
            QSqlDatabase db = qx::QxSqlDatabase::getSingleton()->getDatabaseCloned();
            db.setUserName( "root" );
            db.setPassword( "" );
            const bool isSQLite = db.driverName().contains( "SQLITE" );
     
            // Create a transaction that will throw exception on errors
            qx::QxSession session( db, true, true );
     
            // Fetch database version that will lock concurrent access (when multiple users starts the application at the same time)
            DatabaseVersion dbVersion;
            try
            {
                session.fetchByQuery( qx_query( QString( "WHERE name='") + kAppName + ( isSQLite ? "'" : QString("' FOR UPDATE") ) ), dbVersion );
                // For other users, when the locking will be over, we check if the update is still needed
                if ( dbVersion.version >= domainVersion ) { return; }
            }
            catch ( const qx::dao::sql_error & )
            {
                dbVersion.name = kAppName;
                dbVersion.version = -1;                 // Create tables
            }
     
            // Execute each query with this object
            QSqlQuery query( db );
     
            // On récupère toutes les classes persistantes C++ enregistrées dans le contexte QxOrm
            qx::QxCollection<QString, qx::IxClass *> * pAllClasses = qx::QxClassX::getAllClasses();
            if ( !pAllClasses ) { qAssert(false); return; }
     
            // Get database tables
            QStringList tables = db.tables();
     
            for ( long k = 0; k < pAllClasses->count(); k++ )
            {
                qx::IxClass * pClass = pAllClasses->getByIndex( k );
                if ( !pClass ) { continue; }
     
                // Filter non persistant classes
                if ( pClass->isKindOf( "qx::service::IxParameter" ) || pClass->isKindOf( "qx::service::IxService" ) ) { continue; }
     
                if (pClass->getVersion() <= dbVersion.version) { continue; }
     
                // We create tables if not already existing, and we define its owner
                if ( !tables.contains( pClass->getName() ) )
                {
                    // Create attribute query query section
                    QString attributes;
                    qx::IxDataMemberX * pDataMemberX = pClass->getDataMemberX();
                    for ( long l = 0; (pDataMemberX && (l < pDataMemberX->count_WithDaoStrategy())); l++ )
                    {
                        qx::IxDataMember * p = pDataMemberX->get_WithDaoStrategy(l);
                        attributes += p->getName() + " " + p->getSqlType();
                        if (p->getNotNull()) // NOT NULL
                        {
                            attributes += " NOT NULL";
                        }
                        if (p->getIsPrimaryKey()) // PRIMARY KEY
                        {
                            attributes += " PRIMARY KEY";
                        }
                        if (p->getAutoIncrement()) // AUTO INCREMENT
                        {
                            attributes += " AUTOINCREMENT";
                        }
                        if ( l < pDataMemberX->count_WithDaoStrategy() - 1 )
                        {
                            attributes += ", ";
                        }
                    }
     
                    attributes = QString( " (" ) + attributes + ")";
                    if ( !isSQLite )
                    {
                        attributes += "  WITH ( OIDS = FALSE )";
                    }
                    query.exec( "CREATE TABLE " + pClass->getName() + attributes + ";"
                                "ALTER TABLE " + pClass->getName() + " OWNER TO \"root\";" );
                    session += query.lastError();
     
                    // Create sequences & index
                    for ( long l = 0; (pDataMemberX && ( l < pDataMemberX->count_WithDaoStrategy() ) ); l++ )
                    {
                        qx::IxDataMember * p = pDataMemberX->get_WithDaoStrategy(l);
     
                        if ( p->getAllPropertyBagKeys().contains( "INDEX" ) ) // INDEX
                        {
                            query.exec( "CREATE INDEX " + pClass->getName() + "_" + p->getName() + "_idx" + 
                                        " ON " + pClass->getName() + " USING " + p->getPropertyBag("INDEX").toString() + " (" + p->getName() + ");" );
                            session += query.lastError();
                        }
     
                        if (p->getAutoIncrement() && !isSQLite ) // AUTO INCREMENT
                        {
                            query.exec("CREATE SEQUENCE " + pClass->getName() + "_" + p->getName() + "_seq" + "; "
                                        "ALTER TABLE " + pClass->getName() + "_" + p->getName() + "_seq" + " OWNER TO \"root\"; "
                                        "ALTER TABLE " + pClass->getName() + " ALTER COLUMN " + p->getName() + " " +
                                        "SET DEFAULT nextval('" + pClass->getName() + "_" + p->getName() + "_seq" + "'::regclass);");
                            session += query.lastError();
                        }
     
                    }
                }
                else
                {
                    // We add columns to table if they don't exists
                    qx::IxDataMemberX * pDataMemberX = pClass->getDataMemberX();
                    for ( long l = 0; (pDataMemberX && (l < pDataMemberX->count_WithDaoStrategy())); l++ )
                    {
                        qx::IxDataMember * p = pDataMemberX->get_WithDaoStrategy(l);
                        if (! p || (p->getVersion() <= dbVersion.version)) { continue; }
     
                        query.exec( "ALTER TABLE " + pClass->getName() + " ADD COLUMN " + p->getName() + " " + p->getSqlType() + ";" );
                        session += query.lastError();
     
                        if ( p->getIsPrimaryKey() ) // PRIMARY KEY
                        {
                            query.exec( "ALTER TABLE " + pClass->getName() + " ADD PRIMARY KEY (" + p->getName() + ");" );
                            session += query.lastError();
                        }
     
                        if ( p->getAllPropertyBagKeys().contains("INDEX") ) // INDEX
                        {
                            query.exec("CREATE INDEX " + pClass->getName() + "_" + p->getName() + "_idx" + 
                                        " ON " + pClass->getName() + " USING " + p->getPropertyBag("INDEX").toString() + " (" + p->getName() + ");");
                            session += query.lastError();
                        }
     
                        if (p->getNotNull()) // NOT NULL
                        {
                            query.exec("ALTER TABLE " + pClass->getName() + " ALTER COLUMN " + p->getName() + " SET NOT NULL;");
                            session += query.lastError();
                        }
     
                        if (p->getAutoIncrement()  && !isSQLite ) // AUTO INCREMENT
                        {
                            query.exec("CREATE SEQUENCE " + pClass->getName() + "_" + p->getName() + "_seq" + "; "
                                        "ALTER TABLE " + pClass->getName() + "_" + p->getName() + "_seq" + " OWNER TO \"root\"; "
                                        "ALTER TABLE " + pClass->getName() + " ALTER COLUMN " + p->getName() + " " +
                                        "SET DEFAULT nextval('" + pClass->getName() + "_" + p->getName() + "_seq" + "'::regclass);");
                            session += query.lastError();
                        }
     
                        if (p->getDescription() != "") // DESCRIPTION
                        {
                            query.exec("COMMENT ON COLUMN " + pClass->getName() + "." + p->getName() + " IS $$" + p->getDescription() + "$$ ;");
                            session += query.lastError();
                        }
                    }
                }
            }
     
            // Update database version
            dbVersion.version = domainVersion;
            try
            {
                session.save( dbVersion );
            }
            catch (const qx::dao::sql_error & err)
            {
                session.insert( dbVersion );
            }
            // End of "try" : Session is destroyed => automatic commit or rollback
            // commit or rollback will unlock locked table (not for SQLite)
        }
        catch (const qx::dao::sql_error & err)
        {
            QSqlError sqlError = err.get();
            qDebug() << sqlError.databaseText();
            qDebug() << sqlError.driverText();
            qDebug() << sqlError.number();
            qDebug() << sqlError.type();
        }
    }

    Si vous avez des suggestions, je suis preneur... J'ai simplement rendu le script fonctionnel avec SQLite, mais je ne connais pas très bien SQL donc je ne sais pas si c'est optimal.


    En gros, voici ce qui ne passait pas:
    - SELECT .... FOR UPDATE -> passe pas sous SQLite, j'ai l'impression que le locking n'est pas supporté par SQLite.

    - query.exec("CREATE TABLE " + pClass->getName() + " ( ) WITH (OIDS = FALSE);" -> la création de table sans champs ne passe pas... Le WITH (OIDS = FALSE) non plus.

    - CREATE SEQUENCE -> non supporté à priori. Tout semble être automatique au niveau des séquences (à vérifier).

  2. #2
    Expert confirmé

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    481
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 481
    Points : 4 238
    Points
    4 238
    Par défaut


    Dans la FAQ, il s'agit d'un code fourni par dodobibi qui travaille avec une base de données PostgreSQL.
    L'objectif étant qu'à partir de ce code, tu puisses le retravailler, l'adapter à tes besoins, l'améliorer, etc... Ce que tu as fais pour l'adapter à une base SQLite, ce qui est très bien

    Les notions de "FOR UPDATE", "WITH (OIDS = FALSE)" et "SEQUENCE" sont spécifiques à PostgreSQL, donc tu peux les enlever de ton code si tu souhaites le rendre plus simple et plus lisible.

    Tu trouveras un autre exemple de génération de script ici :
    http://www.qxorm.com/qxorm_fr/resour...ql_schema.html
    Il montre surtout comment parcourir la liste des classes ainsi que les propriétés de chaque classe en utilisant le moteur d’introspection de QxOrm.

    Pour aller plus loin, tu peux lire la dernière remarque de la FAQ :
    Remarque : le code précédent (tout comme la fonction qx::QxClassX::dumpSqlSchema()) peut être modifié pour s'adapter aux besoins spécifiques d'une application.
    Par exemple, il pourrait être intéressant de créer par défaut une seconde table (en plus de la table DatabaseVersion) pour enregistrer la liste des classes persistantes enregistrées dans le contexte QxOrm : ainsi, au lieu d'utiliser la fonction proposée par Qt "db.tables()", il serait possible de récupérer toutes les tables mappées sur des classes persistantes avec des informations supplémentaires (numéro de version pour chaque table, nombre de colonnes enregistrées dans le contexte QxOrm, description de chaque table, etc.).
    Ce n'est pas du tout nécessaire pour démarrer un projet, mais c'est juste une idée pour essayer d'améliorer un peu plus la génération du schéma SQL.
    Le site de la bibliothèque QxOrm : bibliothèque C++ de gestion de données (Mapping Objet Relationnel ou ORM) basée sur les frameworks Qt et boost.
    QxEntityEditor : éditeur graphique pour la bibliothèque QxOrm (application multi-plateforme pour gérer graphiquement le modèle d'entités).

    Tutoriel : installer un environnement de développement avec QxOrm sous Windows.
    Tutoriel qxBlog : gestion de blogs en C++/Qt.
    Tutoriel qxClientServer : création d'un serveur d'applications en C++/Qt.

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    151
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 151
    Points : 49
    Points
    49
    Par défaut
    Mmmh... Je suis bien embêté: il me manque les "extra tables" qui vont avec mes relations...

    J'essaie d'extraire la section qui fait ça sur cette page:
    http://www.qxorm.com/qxorm_fr/resour...ql_schema.html

    Mais ça ne fonctionne pas: je n'ai pas accès à isValid_SqlRelation...

  4. #4
    Expert confirmé

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    481
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 481
    Points : 4 238
    Points
    4 238
    Par défaut
    Mais ça ne fonctionne pas: je n'ai pas accès à isValid_SqlRelation...
    Le code se trouve dans le fichier ./QxOrm/src/QxRegister/QxClassX.cpp.
    Tu peux en faire un copier-coller si tu veux :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    bool QxClassX::isValid_SqlRelation(IxDataMember * p)
    {
       bool bIsValid = (p && p->getDao() && p->hasSqlRelation());
       if (bIsValid) { p->getSqlRelation()->init(); }
       return bIsValid;
    }
     
    bool QxClassX::isValid_DataMember(IxDataMember * p)
    {
       return (p && p->getDao() && ! p->hasSqlRelation());
    }
    il me manque les "extra tables" qui vont avec mes relations
    Les "extra-tables" concernent uniquement les relations de type "many-to-many".
    Pour connaitre le type de relation que tu es en train de traiter, tu peux utiliser "p->getSqlRelation()->getDescription()" qui te renvoie :
    * relation one-to-one
    * relation one-to-many
    * relation many-to-one
    * relation many-to-many
    Le site de la bibliothèque QxOrm : bibliothèque C++ de gestion de données (Mapping Objet Relationnel ou ORM) basée sur les frameworks Qt et boost.
    QxEntityEditor : éditeur graphique pour la bibliothèque QxOrm (application multi-plateforme pour gérer graphiquement le modèle d'entités).

    Tutoriel : installer un environnement de développement avec QxOrm sous Windows.
    Tutoriel qxBlog : gestion de blogs en C++/Qt.
    Tutoriel qxClientServer : création d'un serveur d'applications en C++/Qt.

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    151
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 151
    Points : 49
    Points
    49
    Par défaut
    Oui, effectivement, c'est ce que j'ai fait...

    J'ai un peu du mal à savoir ce qu'il faut faire pour les extra-tables:
    Voici ce que j'ai fait:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
                    // Insert all relations to SQL schema
                    for (long l = 0; (pDataMemberX && ( l < pDataMemberX->count_WithDaoStrategy() ) ); l++)
                    {
                        QString sql;
                        qx::IxDataMember * p = pDataMemberX->get_WithDaoStrategy( l );
                        qx::QxSqlRelationParams params( 0, 0, (& sql), NULL, NULL, NULL );
                        if ( p->hasSqlRelation() && p->getVersion() >= dbVersion.version )
                        {
                            p->getSqlRelation()->init();
                            p->getSqlRelation()->createExtraTable( params );
                        }
                    }

    Mais ça me renvoie ceci:
    ASSERT: "m_builder" in file /home/djar/_DEV/3rdParties/QxOrm/include/QxDao/QxSqlRelationParams.h, line 78

    Voici mes soucis/remarques:
    - Pour l'assert qui ne passe pas, il faudrait passer à params un objet, mais je ne sais pas où l'obtenir...
    - Je ne comprend pas bien à quoi sert le &sql passé en paramètre du constructeur de params.
    - Je pense qu'il faudrait passer l'objet query que j'ai construit à partir de l'instance de base de donnée que je manipule (cf. code de updateDatabaseVersion() ).
    - J'utilise également une session, je ne sais pas trop comment la prendre en compte...

  6. #6
    Expert confirmé

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    481
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 481
    Points : 4 238
    Points
    4 238
    Par défaut
    J'avoue que les relations ne sont pas la partie la plus simple de la bibliothèque QxOrm

    En fait, si tu reprends le code de ce lien : http://www.qxorm.com/qxorm_fr/resour...ql_schema.html, toutes tes relations devraient être créées comme il faut, sauf les relations de type many-to-many, car il va manquer l'extra-table.
    Si tu regardes bien le code, tu verras un TODO => c'est que je n'ai pas eu le temps de le faire encore.

    En fait, je pense qu'il manque des accesseurs à la classe qx::IxSqlRelation => avec des accesseurs (par exemple getExtraTable(), etc.), tout serait bcp plus simple pour générer le schéma SQL et on n'aurait plus besoin d'utiliser qx::QxSqlRelationParams, classe qui a une autre utilité à la base.
    Je vais essayer de rendre ça plus simple dans la prochaine version (QxOrm 1.2.2)...

    En attendant la prochaine version, voici une solution simple que tu peux mettre en place pour gérer tes relations many-to-many : tu peux utiliser la notion de property bag qui permet d'ajouter des méta-informations au paramétrage effectué dans la fonction qx::register_class<T>().
    Si je reprends l'exemple du tutoriel qxBlog, la classe category qui contient une relation many-to-many, je peux ajouter quelque chose comme ça :
    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
    #include "../include/precompiled.h"
    #include "../include/category.h"
    #include "../include/blog.h"
    #include <QxMemLeak.h>
     
    QX_REGISTER_CPP_QX_BLOG(category)
     
    namespace qx {
    template <> void register_class(QxClass<category> & t)
    {
       t.id(& category::m_id, "category_id");
     
       t.data(& category::m_name, "name");
       t.data(& category::m_desc, "description");
     
       IxSqlRelation * pRelation = NULL;
       pRelation = t.relationManyToMany(& category::m_blogX, "list_blog", "category_blog", "category_id", "blog_id");
       pRelation->getDataMember()->setPropertyBag("CREATE_EXTRA_TABLE", "CREATE TABLE category_blog (blog_id INTEGER NOT NULL, category_id INTEGER NOT NULL)");
    }}
    Maintenant que tu as créé cette méta-information, tu peux l'utiliser au moment de la génération de ton schéma SQL (dans ta fonction void updateDatabaseVersion()), comme ceci par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    QString sExtraTable = p->getPropertyBag("CREATE_EXTRA_TABLE").toString();
    if (! sExtraTable.isEmpty())
    {
       /* ici je connais l'extra-table à créer en BDD */
    }
    Voilà c'est la solution la plus simple que je vois pour le moment, en attendant une prochaine version avec les accesseurs nécessaires.
    Le site de la bibliothèque QxOrm : bibliothèque C++ de gestion de données (Mapping Objet Relationnel ou ORM) basée sur les frameworks Qt et boost.
    QxEntityEditor : éditeur graphique pour la bibliothèque QxOrm (application multi-plateforme pour gérer graphiquement le modèle d'entités).

    Tutoriel : installer un environnement de développement avec QxOrm sous Windows.
    Tutoriel qxBlog : gestion de blogs en C++/Qt.
    Tutoriel qxClientServer : création d'un serveur d'applications en C++/Qt.

  7. #7
    Membre du Club
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    151
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 151
    Points : 49
    Points
    49
    Par défaut
    Ok, je vais suivre tes conseils !

    Ce serait super si tu planifies quelque chose pour régler ça dans la 1.2.2
    Le must, dans une future version, serait de faire une fonction qui génère la base de donnée ... Je pense que ce serait une bonne fonctionnalité dont tout le monde aura besoin.

    Quoiqu'il en soit,
    merci !

  8. #8
    Expert confirmé

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    481
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 481
    Points : 4 238
    Points
    4 238
    Par défaut
    Le must, dans une future version, serait de faire une fonction qui génère la base de donnée ... Je pense que ce serait une bonne fonctionnalité dont tout le monde aura besoin.
    Le problème est que la génération d'un schéma SQL est spécifique pour chaque base de données, c'est pourquoi je préfère donner tous les outils nécessaires et des exemples de code pour générer son propre schéma SQL (ça permet également d'apprendre à utiliser le moteur d'introspection de la bibliothèque QxOrm).

    Pour ma part, je préfère largement gérer mes tables avec un outil spécifique à chaque SGBD (par exemple Navicat pour MySQL) => ça peut permettre d'ajouter des optimisations et sépare bien le travail à effectuer : créer le code C++ de mapping et gérer ses tables avec un outil spécifique.

    Après, si des personnes peuvent fournir des fonctions toutes prêtes (pour un type de BDD donné) pour générer des schémas SQL en fonction du mapping C++, je suis preneur. dodobibi en a fourni une pour une base PostgreSQL (ok sans les relations ), si d'autres personnes veulent en créer, je les mettrai à dispo sur le site et dans le code source de la bibliothèque...
    Le site de la bibliothèque QxOrm : bibliothèque C++ de gestion de données (Mapping Objet Relationnel ou ORM) basée sur les frameworks Qt et boost.
    QxEntityEditor : éditeur graphique pour la bibliothèque QxOrm (application multi-plateforme pour gérer graphiquement le modèle d'entités).

    Tutoriel : installer un environnement de développement avec QxOrm sous Windows.
    Tutoriel qxBlog : gestion de blogs en C++/Qt.
    Tutoriel qxClientServer : création d'un serveur d'applications en C++/Qt.

  9. #9
    Expert confirmé

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    481
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 481
    Points : 4 238
    Points
    4 238
    Par défaut
    Je viens de mettre en ligne une nouvelle version BETA de la prochaine version de QxOrm :
    http://www.qxorm.com/version/QxOrm_1.2.2_BETA_14.zip

    A partir de cette version, la méthode createExtraTable() n'a plus besoin du paramètre qx::QxSqlRelationParams, et te retourne sous forme de chaîne de caractères la table à créer (ça correspond au TODO que j'avais laissé dans le code).
    J'ai également ajouté des accesseurs dans la classe qx::IxSqlRelation pour avoir plus de données à disposition pour le moteur d'introspection.

    Donc à présent, si tu utilises une base SQLite, tu peux appeler la méthode qx::QxClassX::dumpSqlSchema() pour obtenir le script de création de ta BDD (contenant toutes les tables + extra-tables provenant des relations many-to-many).

    PS: si tu veux plus d'infos sur les nouveautés de la BETA 1.2.2, j'ai créé un topic sur le sujet :
    http://www.developpez.net/forums/d11...idator-tester/
    Le site de la bibliothèque QxOrm : bibliothèque C++ de gestion de données (Mapping Objet Relationnel ou ORM) basée sur les frameworks Qt et boost.
    QxEntityEditor : éditeur graphique pour la bibliothèque QxOrm (application multi-plateforme pour gérer graphiquement le modèle d'entités).

    Tutoriel : installer un environnement de développement avec QxOrm sous Windows.
    Tutoriel qxBlog : gestion de blogs en C++/Qt.
    Tutoriel qxClientServer : création d'un serveur d'applications en C++/Qt.

  10. #10
    Membre du Club
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    151
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 151
    Points : 49
    Points
    49
    Par défaut
    Ahhh !! Mais c'est génial ! Je sais pas où tu trouves toute cette énergie !

    C'est super. J'installe ça de suite !

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

Discussions similaires

  1. Création de bases de données avec SQLite
    Par slix_alex dans le forum Android
    Réponses: 2
    Dernier message: 22/03/2011, 17h49
  2. Script de création de base
    Par andlio dans le forum Oracle
    Réponses: 20
    Dernier message: 20/07/2005, 13h39
  3. Réponses: 1
    Dernier message: 17/06/2004, 17h44
  4. Réponses: 3
    Dernier message: 24/10/2003, 21h46
  5. Réponses: 3
    Dernier message: 24/10/2003, 21h46

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