commit da3ce9cff4c9fc629e1425470393ac3881501792
Author: Christian Ehringfeld <c.ehringfeld@t-online.de>
Date:   Fri Jun 26 22:30:21 2015 +0200

    improved usage of primary keys

diff --git a/example/main.cpp b/example/main.cpp
index b05b5f5..8dcf157 100644
--- a/example/main.cpp
+++ b/example/main.cpp
@@ -53,6 +53,7 @@ int main(int argc, char *argv[]) {
     qDebug() << "Dauer:" << t.elapsed();
     //QSharedPointer<Artikel> aPtr = QSharedPointer<Artikel>(entity);
     Pupil *p = new Pupil();
+
 //    auto iterator = hash.constBegin();
 //    while(iterator != hash.constEnd()) {
 //        qDebug() << iterator.key() << " Value:" << iterator.value().read(p);
diff --git a/src/entity.cpp b/src/entity.cpp
index 8837c73..e927fcb 100644
--- a/src/entity.cpp
+++ b/src/entity.cpp
@@ -68,13 +68,17 @@ InheritanceStrategy Entity::getInheritanceStrategy() const {
     return JOINED_TABLE;
 }
 
+bool Entity::isInheritanceCascaded() const {
+    return true;
+}
+
 QString Entity::getPrimaryKey() const {
     return "id";
 }
 
-const QStack<const QMetaObject *> Entity::superClasses(bool
+const QList<const QMetaObject *> Entity::superClasses(bool
         stopAtSingleTableInheritance) const {
-    QStack<const QMetaObject *> classes = QStack<const QMetaObject *>();
+    QList<const QMetaObject *> classes = QList<const QMetaObject *>();
     auto superMetaObject = this->metaObject()->superClass();
     if (this->getInheritanceStrategy() == JOINED_TABLE) {
         Entity *e = 0;
@@ -83,7 +87,7 @@ const QStack<const QMetaObject *> Entity::superClasses(bool
                 QString("CuteEntityManager::Entity")) {
             e = EntityInstanceFactory::createInstance(superMetaObject->className());
             if (e) {
-                classes.push(superMetaObject);
+                classes.append(superMetaObject);
                 superMetaObject = superMetaObject->superClass();
                 quint8 s = e->getInheritanceStrategy();
                 delete e;
@@ -133,8 +137,8 @@ const QHash<QString, QMetaProperty> Entity::getMetaProperties(
 const QHash<QString, QMetaProperty> Entity::getInheritedMetaProperties() const {
     auto classes = this->superClasses();
     auto wholeProperties = QHash<QString, QMetaProperty>();
-    while (!classes.isEmpty()) {
-        auto metaObject = classes.pop();
+    for (int var = classes.size() - 1; var >= 0; --var) {
+        auto metaObject = classes.at(var);
         auto properties = Entity::getMetaProperties(metaObject);
         auto iterator = properties.constBegin();
         while (iterator != properties.constEnd()) {
@@ -161,6 +165,10 @@ const char *Entity::getClassname() const {
     return this->metaObject()->className();
 }
 
+QVariant Entity::property(const QString &name) const {
+    return this->property(name.toLatin1().constData());
+}
+
 qint64 Entity::getId() const {
     return id;
 }
diff --git a/src/entity.h b/src/entity.h
index b39ef60..02dd263 100644
--- a/src/entity.h
+++ b/src/entity.h
@@ -45,19 +45,16 @@ class Entity : public QObject {
     virtual QString toString() const;
     virtual ~Entity();
     virtual QString getTablename() const;
-    /**
-     * @brief getRelations
-     * @return
-     */
     virtual const QHash<QString, Relation> getRelations() const;
     virtual const QHash<QString, Relation> getNonInheritedRelations() const;
     virtual const QStringList getTransientAttributes() const;
     virtual const QStringList getBLOBColumns() const;
     virtual InheritanceStrategy getInheritanceStrategy() const;
+    virtual bool isInheritanceCascaded() const;
 
     //return value must be the exact name defined in Q_PROPERTY
     virtual QString getPrimaryKey() const;
-    const QStack<const QMetaObject *> superClasses(bool stopAtSingleTableInheritance
+    const QList<const QMetaObject *> superClasses(bool stopAtSingleTableInheritance
             = false) const;
     const QHash<QString, QMetaProperty> getMetaProperties() const;
     const QHash<QString, QMetaProperty> getSuperMetaProperties() const;
@@ -66,6 +63,7 @@ class Entity : public QObject {
     const QHash<QString, QMetaProperty> getInheritedMetaProperties() const;
     const QHash<Relation, QMetaProperty> getRelationProperties() const;
     const char *getClassname() const;
+    QVariant property(const QString &name) const;
 
     qint64 getId() const;
     void setId(const qint64 &value);
diff --git a/src/querybuilder.cpp b/src/querybuilder.cpp
index 29665ea..37a2f2d 100644
--- a/src/querybuilder.cpp
+++ b/src/querybuilder.cpp
@@ -416,12 +416,12 @@ const {
         Relation r = i.value();
         if (r.getType() == MANY_TO_MANY && r.getMappedBy().isEmpty()) {
             QHash<QString, QString> h = QHash<QString, QString>();
-            h.insert("id", this->schema.data()->TYPE_BIGPK);
+            h.insert(entity.data()->getPrimaryKey(), this->schema.data()->TYPE_BIGPK);
             h.insert(this->generateManyToManyColumnName(entity),
                      this->schema.data()->TYPE_BIGINT);
             auto m = props.value(r.getPropertyName());
-            Entity *e = EntityInstanceFactory::createInstance(m.type());
-            QSharedPointer<Entity> ptr = QSharedPointer<Entity>(e);
+            QSharedPointer<Entity> ptr = QSharedPointer<Entity>
+                                         (EntityInstanceFactory::createInstance(m.type()));
             h.insert(this->generateManyToManyColumnName(ptr),
                      this->schema.data()->TYPE_BIGINT);
             relations.insert(this->generateManyToManyTableName(entity, ptr), h);
@@ -569,42 +569,44 @@ QSqlQuery QueryBuilder::findAll(const QString &tableName) const {
 QList<QSqlQuery> QueryBuilder::remove(const QSharedPointer<Entity> &entity)
 const {
     QList<QSqlQuery> queries = QList<QSqlQuery>();
-    if (entity.data()->getInheritanceStrategy() != PER_CLASS_TABLE) {
-        auto stack = entity.data()->superClasses(true);
-        while (!stack.isEmpty()) {
-            auto item = stack.pop();
+    queries.append(this->remove(entity.data()->getTablename(),
+                                entity.data()->property(entity.data()->getPrimaryKey()).toLongLong()));
+    if (entity.data()->getInheritanceStrategy() != PER_CLASS_TABLE
+            && entity.data()->isInheritanceCascaded()) {
+        auto classes = entity.data()->superClasses(true);
+        for (int var = 0; var < classes.size(); ++var) {
+            auto item = classes.at(var);
             auto instance = EntityInstanceFactory::createInstance(item->className());
             if (instance) {
-                queries.append(this->remove(instance->getTablename(), entity.data()->getId()));
+                queries.append(this->remove(instance->getTablename(),
+                                            entity.data()->property(entity.data()->getPrimaryKey()).toLongLong()));
                 delete instance;
                 instance = 0;
             }
         }
     }
-    queries.append(this->remove(entity.data()->getTablename(),
-                                entity.data()->getId()));
     return queries;
 }
 
 
 QSqlQuery QueryBuilder::remove(const QString &tableName,
-                               const qint64 &id) const {
+                               const qint64 &id, const QString &primaryKey) const {
     QSqlQuery q = this->database->getQuery("DELETE FROM " +
                                            this->schema.data()->quoteTableName(
                                                    tableName) + " WHERE " +
-                                           this->schema.data()->quoteColumnName("id") + "=:id;");
+                                           this->schema.data()->quoteColumnName(primaryKey) + "=:id;");
     q.bindValue(":id", id);
     return q;
 }
 
-
 QSqlQuery QueryBuilder::findId(const QSharedPointer<Entity> &entity) const {
     QHash<QString, QVariant> values = this->getEntityAttributes(
                                           entity.data()->getMetaProperties(),
                                           entity);
     QSqlQuery q = this->database.data()->getQuery(this->selectBase(QStringList(
-                      entity.data()->getTablename()), QStringList("id")) + this->where(values,
-                              "AND", true) + " LIMIT 1");
+                      entity.data()->getTablename()),
+                  QStringList(entity.data()->getPrimaryKey())) + this->where(values,
+                          "AND", true) + " LIMIT 1");
     this->bindValues(values, q);
     return q;
 }
@@ -633,26 +635,34 @@ QSqlQuery QueryBuilder::merge(const QSharedPointer<Entity> &entity) const {
     QSqlQuery q = this->database.data()->getQuery("UPDATE " +
                   this->schema.data()->quoteTableName(
                       entity->getTablename()) + " SET " + this->attributes(
-                      values) + " WHERE " + this->schema.data()->quoteColumnName("id") + "=:id;");
+                      values) + " WHERE " + this->schema.data()->quoteColumnName(
+                      entity.data()->getPrimaryKey()) + "=:id;");
     this->bindValues(values, q);
     return q;
 }
 
 QSqlQuery QueryBuilder::create(const QSharedPointer<Entity> &entity) const {
     QHash<QString, QVariant> values = this->saveAttributes(entity);
-    values.remove("id");
+    return this->insert(entity.data()->getTablename(), values,
+                        entity.data()->getPrimaryKey());
+}
+
+QSqlQuery QueryBuilder::insert(const QString &tableName,
+                               QHash<QString, QVariant> &attributes, const QString &primaryKey) const {
+    attributes.remove(primaryKey);
     QSqlQuery q = this->database.data()->getQuery();
     QString p1 = "INSERT INTO " + this->schema.data()->quoteTableName(
-                     entity->getTablename()) + "(";
+                     tableName) + "(";
     QString p2 = "VALUES(";
-    if (!values.isEmpty()) {
-        q.prepare(this->buildCreateQuery(values.constBegin(), values.constEnd(),
+    if (!attributes.isEmpty()) {
+        q.prepare(this->buildCreateQuery(attributes.constBegin(), attributes.constEnd(),
                                          p1, p2));
     }
-    this->bindValues(values, q);
+    this->bindValues(attributes, q);
     return q;
 }
 
+
 QSqlQuery QueryBuilder::oneToMany(const QString &tableName,
                                   const QString &attribute,
                                   const qint64 &id,
@@ -705,11 +715,11 @@ const {
 
 QString QueryBuilder::joinSuperClasses(const QSharedPointer<Entity> &entity)
 const {
-    auto stack = entity.data()->superClasses();
+    auto classes = entity.data()->superClasses(true);
     QString joined = "";
     Entity *e = 0;
-    while (!stack.isEmpty()) {
-        auto metaObject = stack.pop();
+    for (int var = 0; var < classes.size(); ++var) {
+        auto metaObject = classes.at(var);
         e = EntityInstanceFactory::createInstance(metaObject->className());
         if (e) {
             joined.append(" ");
@@ -822,8 +832,9 @@ QHash<QString, QVariant> QueryBuilder::getManyToOneAttributes(
 void QueryBuilder::insertRelationId(const Entity *e,
                                     QHash<QString, QVariant> &map,
                                     QString relName) const {
-    if (e && e->getId() > -1) {
-        map.insert(this->generateColumnNameID(relName), e->getId());
+    if (e && e->property(e->getPrimaryKey()).toLongLong() > -1) {
+        map.insert(this->generateColumnNameID(relName),
+                   e->property(e->getPrimaryKey()));
     }
 }
 
@@ -842,10 +853,10 @@ QString QueryBuilder::buildColumns(const QStringList &columns) const {
 }
 
 void QueryBuilder::bindValues(const QHash<QString, QVariant> &h, QSqlQuery &q,
-                              bool ignoreID) const {
+                              bool ignoreID, const QString &primaryKey) const {
     QHash<QString, QVariant>::const_iterator i = h.constBegin();
     while (i != h.constEnd()) {
-        if (!ignoreID || (ignoreID && !(i.key() == "id"))) {
+        if (!ignoreID || (ignoreID && !(i.key() == primaryKey))) {
             q.bindValue(":" + i.key(), i.value());
         }
         ++i;
@@ -857,26 +868,26 @@ QString QueryBuilder::where(const QSharedPointer<Entity> &entity,
                             bool ignoreID) const {
     return this->where(this->getEntityAttributes(entity.data()->getMetaProperties(),
                        entity),
-                       conjunction, ignoreID);
+                       conjunction, ignoreID, entity.data()->getPrimaryKey());
 }
 
 QString QueryBuilder::where(const QHash<QString, QVariant> &m,
                             const QString &conjunction,
-                            bool ignoreID) const {
-    if (m.size() == 0 || (ignoreID && m.contains("id") && m.size() == 1)) {
+                            bool ignoreID, const QString &primaryKey) const {
+    if (m.size() == 0 || (ignoreID && m.contains(primaryKey) && m.size() == 1)) {
         return "";
     }
-    return " WHERE " + this->attributes(m, conjunction, ignoreID);
+    return " WHERE " + this->attributes(m, conjunction, ignoreID, primaryKey);
 }
 
 QString QueryBuilder::attributes(const QHash<QString, QVariant> &m,
                                  const QString &conjunction,
-                                 bool ignoreID) const {
+                                 bool ignoreID, const QString &primaryKey) const {
     QString rc = "";
     if (!m.isEmpty()) {
         QHash<QString, QVariant>::const_iterator i = m.constBegin();
         while (i != m.constEnd()) {
-            if (!ignoreID || (ignoreID && !(i.key() == "id"))) {
+            if (!ignoreID || (ignoreID && !(i.key() == primaryKey))) {
                 if (!(rc == "")) {
                     rc += " " + conjunction + " ";
                 }
diff --git a/src/querybuilder.h b/src/querybuilder.h
index 72d1f27..93cc095 100644
--- a/src/querybuilder.h
+++ b/src/querybuilder.h
@@ -137,7 +137,10 @@ class QueryBuilder {
     QSqlQuery getQuery() const;
 
   protected:
-    QSqlQuery remove(const QString &tableName, const qint64 &id) const;
+    QSqlQuery remove(const QString &tableName, const qint64 &id,
+                     const QString &primaryKey = "id") const;
+    QSqlQuery insert(const QString &tableName, QHash<QString, QVariant> &attributes,
+                     const QString &primaryKey = "id") const;
     virtual void createRelationFK(QStringList &queries,
                                   const QSharedPointer<Entity> &entity, const Relation &relation,
                                   const QMetaProperty &metaProperty, const QString &update,
@@ -159,15 +162,15 @@ class QueryBuilder {
                              QHash<QString, QVariant>::const_iterator end,
                              QString &p1, QString &p2) const;
     void bindValues(const QHash<QString, QVariant> &h, QSqlQuery &q,
-                    bool ignoreID = false) const;
+                    bool ignoreID = false, const QString &primaryKey = "id") const;
     QString where(const QSharedPointer<Entity> &entity, QString conjunction = ",",
                   bool ignoreID = false) const;
     QString where(const QHash<QString, QVariant> &m,
                   const QString &conjunction = ",",
-                  bool ignoreID = false) const;
+                  bool ignoreID = false, const QString &primaryKey = "id") const;
     QString attributes(const QHash<QString, QVariant> &m,
                        const QString &conjunction = ",",
-                       bool ignoreID = false) const;
+                       bool ignoreID = false, const QString &primaryKey = "id") const;
     QHash<QString, QVariant> saveAttributes(const QSharedPointer<Entity> &entity)
     const;
     QString leftJoin(const QString &foreignTable, const QString &tableName,
