QxOrm 1.1.6
C++ Object Relational Mapping library
QxSqlRelation_ManyToMany.h
Go to the documentation of this file.
00001 /****************************************************************************
00002 **
00003 ** http://www.qxorm.com/
00004 ** http://sourceforge.net/projects/qxorm/
00005 ** Original file by Lionel Marty
00006 **
00007 ** This file is part of the QxOrm library
00008 **
00009 ** This software is provided 'as-is', without any express or implied
00010 ** warranty. In no event will the authors be held liable for any
00011 ** damages arising from the use of this software.
00012 **
00013 ** GNU Lesser General Public License Usage
00014 ** This file must be used under the terms of the GNU Lesser
00015 ** General Public License version 2.1 as published by the Free Software
00016 ** Foundation and appearing in the file 'license.lgpl.txt' included in the
00017 ** packaging of this file.  Please review the following information to
00018 ** ensure the GNU Lesser General Public License version 2.1 requirements
00019 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
00020 **
00021 ** If you have questions regarding the use of this file, please contact :
00022 ** contact@qxorm.com
00023 **
00024 ****************************************************************************/
00025 
00026 #ifndef _QX_SQL_RELATION_MANY_TO_MANY_H_
00027 #define _QX_SQL_RELATION_MANY_TO_MANY_H_
00028 
00029 #ifdef _MSC_VER
00030 #pragma once
00031 #endif
00032 
00040 #include <QxDao/QxSqlRelation.h>
00041 
00042 namespace qx {
00043 
00048 template <class DataType, class Owner>
00049 class QxSqlRelation_ManyToMany : public QxSqlRelation<DataType, Owner>
00050 {
00051 
00052 private:
00053 
00054    typedef typename QxSqlRelation<DataType, Owner>::type_owner type_owner;
00055    typedef typename QxSqlRelation<DataType, Owner>::type_data type_data;
00056    typedef typename QxSqlRelation<DataType, Owner>::type_container type_container;
00057    typedef typename QxSqlRelation<DataType, Owner>::type_generic_container type_generic_container;
00058    typedef typename QxSqlRelation<DataType, Owner>::type_item type_item;
00059    typedef typename type_generic_container::type_iterator type_iterator;
00060 
00061    enum { is_data_container = QxSqlRelation<DataType, Owner>::is_data_container };
00062 
00063 protected:
00064 
00065    QString m_sExtraTable;           
00066    QString m_sForeignKeyOwner;      
00067    QString m_sForeignKeyDataType;   
00068 
00069 public:
00070 
00071    QxSqlRelation_ManyToMany(IxDataMember * p, const QString & sExtraTable, const QString & sForeignKeyOwner, const QString & sForeignKeyDataType) : QxSqlRelation<DataType, Owner>(p), m_sExtraTable(sExtraTable), m_sForeignKeyOwner(sForeignKeyOwner), m_sForeignKeyDataType(sForeignKeyDataType) { this->verify(); }
00072    virtual ~QxSqlRelation_ManyToMany() { BOOST_STATIC_ASSERT(is_data_container); }
00073 
00074    virtual bool getCartesianProduct() const                                   { return true; }
00075    virtual void createTable(QxSqlRelationParams & params) const               { Q_UNUSED(params); }
00076    virtual void lazySelect(QxSqlRelationParams & params) const                { Q_UNUSED(params); }
00077    virtual void lazyFrom(QxSqlRelationParams & params) const                  { Q_UNUSED(params); }
00078    virtual void eagerFrom(QxSqlRelationParams & params) const                 { Q_UNUSED(params); }
00079    virtual void lazyJoin(QxSqlRelationParams & params) const                  { Q_UNUSED(params); }
00080    virtual void lazyWhere(QxSqlRelationParams & params) const                 { Q_UNUSED(params); }
00081    virtual void eagerWhere(QxSqlRelationParams & params) const                { Q_UNUSED(params); }
00082    virtual void lazyFetch_ResolveInput(QxSqlRelationParams & params) const    { Q_UNUSED(params); }
00083    virtual void eagerFetch_ResolveInput(QxSqlRelationParams & params) const   { Q_UNUSED(params); }
00084    virtual void lazyFetch_ResolveOutput(QxSqlRelationParams & params) const   { Q_UNUSED(params); }
00085    virtual void lazyInsert(QxSqlRelationParams & params) const                { Q_UNUSED(params); }
00086    virtual void lazyInsert_Values(QxSqlRelationParams & params) const         { Q_UNUSED(params); }
00087    virtual void lazyUpdate(QxSqlRelationParams & params) const                { Q_UNUSED(params); }
00088    virtual void lazyInsert_ResolveInput(QxSqlRelationParams & params) const   { Q_UNUSED(params); }
00089    virtual void lazyUpdate_ResolveInput(QxSqlRelationParams & params) const   { Q_UNUSED(params); }
00090    virtual QSqlError onBeforeSave(QxSqlRelationParams & params) const         { Q_UNUSED(params); return QSqlError(); }
00091 
00092    virtual QVariant getIdFromQuery(bool bEager, QxSqlRelationParams & params) const
00093    {
00094       QString sId; IxDataMember * pId = this->getDataId(); if (! bEager || ! pId) { return QVariant(); }
00095       for (int i = 0; i < pId->getNameCount(); i++) { sId += params.query().value(params.offset() + i).toString() + "|"; }
00096       return QVariant(sId);
00097    }
00098 
00099    virtual void updateOffset(bool bEager, QxSqlRelationParams & params) const
00100    { if (bEager) { params.setOffset(params.offset() + this->getDataCount() + (this->getDataId() ? this->getDataId()->getNameCount() : 0)); } }
00101 
00102    virtual void eagerSelect(QxSqlRelationParams & params) const
00103    {
00104       long l1(0);
00105       QString & sql = params.sql();
00106       IxDataMember * p = NULL; IxDataMember * pId = this->getDataId(); qAssert(pId);
00107       QString tableAlias = this->tableAlias(params);
00108       if (pId) { sql += (pId->getSqlTablePointNameAsAlias(tableAlias) + ", "); }
00109       while ((p = this->nextData(l1))) { sql += (p->getSqlTablePointNameAsAlias(tableAlias) + ", "); }
00110    }
00111 
00112    virtual void eagerJoin(QxSqlRelationParams & params) const
00113    {
00114       QString & sql = params.sql();
00115       IxDataMember * pIdOwner = params.builder().getDataId(); qAssert(pIdOwner);
00116       IxDataMember * pIdData = this->getDataId(); qAssert(pIdData);
00117       QString table = this->table(); QString tableAlias = this->tableAlias(params); QString tableOwner = params.builder().table();
00118       if (! pIdOwner || ! pIdData) { return; }
00119       QStringList lstForeignKeyOwner = m_sForeignKeyOwner.split("|");
00120       QStringList lstForeignKeyDataType = m_sForeignKeyDataType.split("|");
00121       qAssert(pIdOwner->getNameCount() == lstForeignKeyOwner.count());
00122       qAssert(pIdData->getNameCount() == lstForeignKeyDataType.count());
00123       sql += this->getSqlJoin() + m_sExtraTable + " ON ";
00124       for (int i = 0; i < pIdOwner->getNameCount(); i++)
00125       { sql += pIdOwner->getSqlAlias(tableOwner, true, i) + " = " + m_sExtraTable + "." + lstForeignKeyOwner.at(i) + " AND "; }
00126       sql = sql.left(sql.count() - 5); // Remove last " AND "
00127       sql += this->getSqlJoin() + table + " " + tableAlias + " ON ";
00128       for (int i = 0; i < pIdData->getNameCount(); i++)
00129       { sql += m_sExtraTable + "." + lstForeignKeyDataType.at(i) + " = " + pIdData->getSqlAlias(tableAlias, true, i) + " AND "; }
00130       sql = sql.left(sql.count() - 5); // Remove last " AND "
00131    }
00132 
00133    virtual void eagerFetch_ResolveOutput(QxSqlRelationParams & params) const
00134    {
00135       if (! this->verifyOffset(params, true)) { return; }
00136       QSqlQuery & query = params.query();
00137       IxDataMember * p = NULL; IxDataMember * pId = this->getDataId(); qAssert(pId);
00138       long lIndex = 0; long lOffsetId = (pId ? pId->getNameCount() : 0); bool bValidId(false);
00139       long lOffsetOld = params.offset(); params.setOffset(lOffsetOld + this->getDataCount() + lOffsetId);
00140       for (int i = 0; i < pId->getNameCount(); i++)
00141       { QVariant v = query.value(lOffsetOld + i); bValidId = (bValidId || qx::trait::is_valid_primary_key(v)); }
00142       if (! bValidId) { return; }
00143       type_item item = this->createItem();
00144       type_data & item_val = item.value_qx();
00145       for (int i = 0; i < pId->getNameCount(); i++)
00146       { QVariant v = query.value(lOffsetOld + i); qx::cvt::from_variant(v, item.key(), "", i); }
00147       for (int i = 0; i < pId->getNameCount(); i++)
00148       { QVariant v = query.value(lOffsetOld + i); pId->fromVariant((& item_val), v, "", i); }
00149       while ((p = this->nextData(lIndex)))
00150       { p->fromVariant((& item_val), query.value(lIndex + lOffsetOld + lOffsetId - 1)); }
00151       type_generic_container::insertItem(this->getContainer(params), item);
00152    }
00153 
00154    virtual QSqlError onAfterSave(QxSqlRelationParams & params) const
00155    {
00156       QSqlError daoError = qx::dao::save(this->getContainer(params), (& params.database()));
00157       if (daoError.isValid()) { return daoError; }
00158       daoError = this->deleteFromExtraTable(params);
00159       if (daoError.isValid()) { return daoError; }
00160       daoError = this->insertIntoExtraTable(params);
00161       if (daoError.isValid()) { return daoError; }
00162       return QSqlError();
00163    }
00164 
00165    virtual QSqlError createExtraTable(QxSqlRelationParams & params) const
00166    {
00167       IxDataMember * pIdOwner = params.builder().getDataId(); qAssert(pIdOwner);
00168       IxDataMember * pIdData = this->getDataId(); qAssert(pIdData);
00169       if (! pIdOwner || ! pIdData) { return QSqlError(); }
00170 
00171       bool bOldPKOwner = pIdOwner->getIsPrimaryKey(); pIdOwner->setIsPrimaryKey(false);
00172       bool bOldPKData = pIdData->getIsPrimaryKey(); pIdData->setIsPrimaryKey(false);
00173       bool bOldAIOwner = pIdOwner->getAutoIncrement(); pIdOwner->setAutoIncrement(false);
00174       bool bOldAIData = pIdData->getAutoIncrement(); pIdData->setAutoIncrement(false);
00175 
00176       QString sql = "CREATE TABLE IF NOT EXISTS " + m_sExtraTable + " (";
00177       sql += pIdOwner->getSqlNameAndTypeAndParams(", ", m_sForeignKeyOwner) + ", "; qAssert(! pIdOwner->getSqlType().isEmpty());
00178       sql += pIdData->getSqlNameAndTypeAndParams(", ", m_sForeignKeyDataType) + ", "; qAssert(! pIdData->getSqlType().isEmpty());
00179       sql = sql.left(sql.count() - 2); // Remove last ", "
00180       sql += ")";
00181 
00182       pIdOwner->setIsPrimaryKey(bOldPKOwner); pIdData->setIsPrimaryKey(bOldPKData);
00183       pIdOwner->setAutoIncrement(bOldAIOwner); pIdData->setAutoIncrement(bOldAIData);
00184       qDebug("[QxOrm] create extra-table (relation many-to-many) : %s", qPrintable(sql));
00185       QSqlQuery queryCreateTable(params.database());
00186       if (! queryCreateTable.exec(sql)) { return queryCreateTable.lastError(); }
00187       return QSqlError();
00188    }
00189 
00190 private:
00191 
00192    inline void verify()
00193    { qAssert(! m_sExtraTable.isEmpty() && ! m_sForeignKeyOwner.isEmpty() && ! m_sForeignKeyDataType.isEmpty() && (m_sForeignKeyOwner != m_sForeignKeyDataType)); }
00194 
00195    QSqlError deleteFromExtraTable(QxSqlRelationParams & params) const
00196    {
00197       IxDataMember * pIdOwner = params.builder().getDataId(); qAssert(pIdOwner);
00198       QString sql = "DELETE FROM " + m_sExtraTable + " WHERE ";
00199       QStringList lstForeignKeyOwner = m_sForeignKeyOwner.split("|");
00200       qAssert(pIdOwner->getNameCount() == lstForeignKeyOwner.count());
00201       for (int i = 0; i < pIdOwner->getNameCount(); i++)
00202       { sql += m_sExtraTable + "." + lstForeignKeyOwner.at(i) + " = " + pIdOwner->getSqlPlaceHolder("", i) + " AND "; }
00203       sql = sql.left(sql.count() - 5); // Remove last " AND "
00204       qDebug("[QxOrm] sql query (extra-table) : %s", qPrintable(sql));
00205 
00206       QSqlQuery queryDelete(params.database());
00207       queryDelete.prepare(sql);
00208       pIdOwner->setSqlPlaceHolder(queryDelete, params.owner());
00209       if (! queryDelete.exec()) { return queryDelete.lastError(); }
00210       return QSqlError();
00211    }
00212 
00213    QSqlError insertIntoExtraTable(QxSqlRelationParams & params) const
00214    {
00215       IxDataMember * pIdOwner = params.builder().getDataId(); qAssert(pIdOwner);
00216       IxDataMember * pIdData = this->getDataId(); qAssert(pIdData);
00217       if (! pIdOwner || ! pIdData) { return QSqlError(); }
00218       QStringList lstForeignKeyOwner = m_sForeignKeyOwner.split("|");
00219       QStringList lstForeignKeyDataType = m_sForeignKeyDataType.split("|");
00220       qAssert(pIdOwner->getNameCount() == lstForeignKeyOwner.count());
00221       qAssert(pIdData->getNameCount() == lstForeignKeyDataType.count());
00222 
00223       QString sql = "INSERT INTO " + m_sExtraTable + " (";
00224       sql += pIdOwner->getSqlName(", ", m_sForeignKeyOwner) + ", " + pIdData->getSqlName(", ", m_sForeignKeyDataType);
00225       sql += ") VALUES (";
00226       sql += pIdOwner->getSqlPlaceHolder("", -1, ", ", m_sForeignKeyOwner) + ", " + pIdData->getSqlPlaceHolder("", -1, ", ", m_sForeignKeyDataType) + ")";
00227       qDebug("[QxOrm] sql query (extra-table) : %s", qPrintable(sql));
00228 
00229       type_item item;
00230       type_container container = this->getContainer(params);
00231       type_iterator itr = type_generic_container::begin(container, item);
00232       type_iterator itr_end = type_generic_container::end(container);
00233       QSqlQuery queryInsert(params.database());
00234       queryInsert.prepare(sql);
00235 
00236       while (itr != itr_end)
00237       {
00238          pIdOwner->setSqlPlaceHolder(queryInsert, params.owner(), "", m_sForeignKeyOwner);
00239          pIdData->setSqlPlaceHolder(queryInsert, (& item.value_qx()), "", m_sForeignKeyDataType);
00240          if (! queryInsert.exec()) { return queryInsert.lastError(); }
00241          itr = type_generic_container::next(container, itr, item);
00242       }
00243 
00244       return QSqlError();
00245    }
00246 
00247 };
00248 
00249 } // namespace qx
00250 
00251 #endif // _QX_SQL_RELATION_MANY_TO_MANY_H_
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines