commit ea09b5beca362ab738ee3d08a7aca3c3e1cb8d14
Author: Christian Ehringfeld <c.ehringfeld@t-online.de>
Date:   Thu Oct 8 15:21:03 2015 +0200

    some improvements in entity inspector

diff --git a/src/entityinspector.cpp b/src/entityinspector.cpp
index 6c7b887..9bf4429 100644
--- a/src/entityinspector.cpp
+++ b/src/entityinspector.cpp
@@ -136,7 +136,7 @@ bool EntityInspector::verifyRelations(Entity *&entity) {
                 if (!rel) {
                     ok = false;
                 } else {
-                    this->checkRelationMappings(metaProperty, i.value(), ok,entity);
+                    this->checkRelationMappings(metaProperty, i.value(), ok, entity);
                 }
             }
         }
@@ -209,55 +209,107 @@ void EntityInspector::checkRelationTypos(const QString &name, const Relation &r,
     }
 }
 
+void EntityInspector::checkNotMappedByAttributes(int foundMappedBy, bool &ok,
+        const QString &propertyName, const QString &foreignEntity) {
+    if (foundMappedBy == 0) {
+        this->logger->logMsg("Optional: The relation " + propertyName +
+                             " is not mapped in foreign class " + foreignEntity +
+                             ". You could map it.\n", MsgType::INFO);
+    } else if (foundMappedBy > 1) {
+        this->logger->logMsg("The relation " + propertyName +
+                             " is mapped several times (" +
+                             QString::number(foundMappedBy) + ") by foreign class " + foreignEntity +
+                             ". You should map it only once!\n",
+                             MsgType::WARNING);
+        ok = false;
+    }
+}
+
+void EntityInspector::checkRelationTypes(const Relation &r,
+        const Relation &foreign, bool &ok) {
+    if (r.getType() == RelationType::ONE_TO_ONE
+            && foreign.getType() != RelationType::ONE_TO_ONE) {
+        ok = false;
+        this->logRelationTypeErrorMsg("ONE_TO_ONE", r, foreign);
+
+    } else if (r.getType() == RelationType::MANY_TO_MANY
+               && foreign.getType() != RelationType::MANY_TO_MANY) {
+        this->logRelationTypeErrorMsg("MANY_TO_MANY", r, foreign);
+        ok = false;
+    } else if (r.getType() == RelationType::MANY_TO_ONE
+               && foreign.getType() != RelationType::ONE_TO_MANY) {
+        this->logRelationTypeErrorMsg("ONE_TO_MANY", r, foreign);
+        ok = false;
+    }
+}
+
+void EntityInspector::logRelationTypeErrorMsg(const QString &type,
+        const Relation &r, const Relation &foreign) {
+    this->logger->logMsg("Relation type of foreign relation " +
+                         foreign.getPropertyName() +
+                         " must be of type " + type + "! Foreign property name is called " +
+                         r.getPropertyName() + ".",
+                         MsgType::CRITICAL);
+}
+
+void EntityInspector::analyzeForeignRelations(const Relation &r,
+        const Entity *const entity, const Entity *const foreignInstance, bool &ok,
+        int &foundMappedBy, bool &foundForeignMappedRelation, bool &bothSidedMappedBy) {
+    auto foreignRelations = EntityHelper::getRelationProperties(foreignInstance);
+    auto superClasses = EntityHelper::superClasses(entity, true);
+    QStringList classNames = QStringList {EntityHelper::getClassName(entity)};
+    for (int s = 0; s < superClasses.size(); ++s) {
+        classNames.append(superClasses.at(s)->className());
+    }
+    for (auto i = foreignRelations.constBegin(); i != foreignRelations.constEnd();
+            ++i) {
+        if (r.getMappedBy().isEmpty()
+                && i.key().getMappedBy() == r.getPropertyName()) {
+            for (int x = 0; x < classNames.size(); ++x) {
+                if (QString(i.value().typeName()).contains(classNames.at(x))) {
+                    ++foundMappedBy;
+                    this->checkRelationTypes(r, i.key(), ok);
+                    break;
+                }
+            }
+        } else if (!r.getMappedBy().isEmpty()
+                   && r.getMappedBy() == i.key().getPropertyName()) {
+            foundForeignMappedRelation = true;
+            this->checkRelationTypes(r, i.key(), ok);
+            if (r.getPropertyName() == i.key().getMappedBy()) {
+                bothSidedMappedBy = true;
+            }
+            break;
+        }
+    }
+}
+
+
 void EntityInspector::checkRelationMappings(QMetaProperty &property,
         const Relation &r, bool &ok, Entity *&entity) {
     QString foreignEntityName = EntityInstanceFactory::extractEntityType(
                                     property.typeName());
     auto foreignInstance = EntityInstanceFactory::createInstance(foreignEntityName);
     if (foreignInstance) {
-        auto foreignRelations = EntityHelper::getRelationProperties(foreignInstance);
         int foundMappedBy = 0;
-        bool foundForeignMappedRelation = false;
-        auto superClasses = EntityHelper::superClasses(entity,true);
-        QStringList classNames = QStringList {EntityHelper::getClassName(entity)};
-        for (int s = 0; s < superClasses.size(); ++s) {
-           classNames.append(superClasses.at(s)->className());
-        }
-        for (auto i = foreignRelations.constBegin(); i != foreignRelations.constEnd();
-                ++i) {
-            if (r.getMappedBy().isEmpty()
-                    && i.key().getMappedBy() == r.getPropertyName()) {
-                for (int x = 0; x < classNames.size(); ++x) {
-                    if(QString(i.value().typeName()).contains(classNames.at(x))) {
-                        ++foundMappedBy;
-                        break;
-                    }
-                }
-            } else if (!r.getMappedBy().isEmpty()
-                       && r.getMappedBy() == i.key().getPropertyName()) {
-                foundForeignMappedRelation = true;
-                break;
-            }
-        }
+        bool foundForeignMappedRelation = false, bothSidedMappedBy = false;
+        this->analyzeForeignRelations(r, entity, foreignInstance, ok, foundMappedBy,
+                                      foundForeignMappedRelation, bothSidedMappedBy);
         if (r.getMappedBy().isEmpty()) {
-            if (foundMappedBy == 0) {
-                this->logger->logMsg("Optional: The relation " + r.getPropertyName() +
-                                     " is not mapped in foreign class " + foreignEntityName +
-                                     ". You could map it.\n", MsgType::INFO);
-            } else if (foundMappedBy > 1) {
-                this->logger->logMsg("The relation " + r.getPropertyName() +
-                                     " is mapped several times (" +
-                                     QString::number(foundMappedBy) + ") by foreign class " + foreignEntityName +
-                                     ". You should map it only once!\n",
-                                     MsgType::WARNING);
-                ok = false;
-            }
+            this->checkNotMappedByAttributes(foundMappedBy, ok, r.getPropertyName(),
+                                             foreignEntityName);
         } else if (!foundForeignMappedRelation) {
             this->logger->logMsg("Relation " + r.getPropertyName() +
                                  " with mappedBy attribute " +
                                  r.getMappedBy() + " has no mapped relation in " + foreignEntityName +
                                  " class!\n", MsgType::CRITICAL);
             ok = false;
+        } else if (bothSidedMappedBy) {
+            this->logger->logMsg("Relation " + r.getPropertyName() +
+                                 " with mappedBy attribute " +
+                                 r.getMappedBy() + " is also mappedBy in " + foreignEntityName +
+                                 " class!\n", MsgType::CRITICAL);
+            ok = false;
         }
         delete foreignInstance;
         foreignInstance = nullptr;
diff --git a/src/entityinspector.h b/src/entityinspector.h
index 210d5b6..7547639 100644
--- a/src/entityinspector.h
+++ b/src/entityinspector.h
@@ -49,6 +49,14 @@ class EntityInspector {
     void verifyBlobAttributes(Entity *&entity);
     void checkMetaProperties(QHash<QString, QMetaProperty> &metaProperties,
                              bool &ok, QHash<QString, Relation> &relations);
+    void checkNotMappedByAttributes(int foundMappedBy, bool &ok,
+                                    const QString &propertyName, const QString &foreignEntity);
+    void checkRelationTypes(const Relation &r, const Relation &foreign, bool &ok);
+    void logRelationTypeErrorMsg(const QString &type, const Relation &r,
+                                 const Relation &foreign);
+    void analyzeForeignRelations(const Relation &r, const Entity *const entity,
+                                 const Entity *const foreignInstance, bool &ok, int &foundMappedBy,
+                                 bool &foundForeignMappedRelation, bool &bothSidedMappedBy);
     void initLogger(const MsgType msgType);
     Logger *logger = nullptr;
 };
diff --git a/src/relation.cpp b/src/relation.cpp
index d1a7ddb..41b61f3 100644
--- a/src/relation.cpp
+++ b/src/relation.cpp
@@ -49,6 +49,25 @@ RelationType Relation::getType() const {
     return type;
 }
 
+QString Relation::getTypeAsString() const {
+    QString r = "";
+    switch (this->type) {
+    case RelationType::ONE_TO_MANY:
+        r = "ONE_TO_MANY";
+        break;
+    case RelationType::MANY_TO_MANY:
+        r = "MANY_TO_MANY";
+        break;
+    case RelationType:: MANY_TO_ONE:
+        r = "MANY_TO_ONE";
+        break;
+    case RelationType::ONE_TO_ONE:
+        r = "ONE_TO_ONE";
+        break;
+    }
+    return r;
+}
+
 void Relation::setType(const RelationType &value) {
     type = value;
 }
diff --git a/src/relation.h b/src/relation.h
index f8ebebf..db0cc89 100644
--- a/src/relation.h
+++ b/src/relation.h
@@ -51,9 +51,10 @@ class Relation {
      */
     explicit Relation(QString propertyName, RelationType type,
                       QString mappedBy = QString(),
-                      QList<CascadeType> cascadeType = QList<CascadeType>{CascadeType::MERGE, CascadeType::PERSIST, CascadeType::REFRESH});
+                      QList<CascadeType> cascadeType = QList<CascadeType> {CascadeType::MERGE, CascadeType::PERSIST, CascadeType::REFRESH});
     ~Relation();
     RelationType getType() const;
+    QString getTypeAsString() const;
     void setType(const RelationType &value);
 
     QString getPropertyName() const;
