commit c88e17d15885b3a9f9cdb5a05acbae75d65588f9
Author: Christian Ehringfeld <c.ehringfeld@t-online.de>
Date:   Sun Nov 19 23:54:10 2017 +0100

    n-m refactoring

diff --git a/src/converter.cpp b/src/converter.cpp
new file mode 100644
index 0000000..5b5e0da
--- /dev/null
+++ b/src/converter.cpp
@@ -0,0 +1,33 @@
+#include "converter.h"
+#include "entityinstancefactory.h"
+using namespace CuteEntityManager;
+
+Converter::Converter()
+{
+
+}
+
+QSharedPointer<Entity> Converter::convert(const QHash<QString, QVariant>
+                                              &map, const char *classname, Cache &cache) {
+    auto ptr = QSharedPointer<Entity>(map.isEmpty() ? nullptr : EntityInstanceFactory::createInstance(
+                                                          classname, map));
+    cache.insert(ptr);
+    return ptr;
+}
+
+void Converter::convert(const QHash<QString, QVariant> &map,
+                            QSharedPointer<Entity> &entity, Cache &cache) {
+    cache.insert(entity);
+    auto data = entity.data();
+    EntityInstanceFactory::setAttributes(data, map);
+}
+
+QList<QSharedPointer<Entity>> Converter::convert(QList<QHash<QString, QVariant>> maps,
+        const char *classname, Cache &cache) {
+    auto list = QList<QSharedPointer<Entity>>();
+    for (int var = 0; var < maps.size(); ++var) {
+        auto ptr = this->convert(maps.at(var), classname,cache);
+        list.append(ptr);
+    }
+    return list;
+}
diff --git a/src/converter.h b/src/converter.h
new file mode 100644
index 0000000..4bb53f5
--- /dev/null
+++ b/src/converter.h
@@ -0,0 +1,28 @@
+#ifndef CONVERTER_H
+#define CONVERTER_H
+#include <QSharedPointer>
+#include <QSqlQuery>
+#include "entity.h"
+#include "cache.h"
+namespace CuteEntityManager {
+class Converter
+{
+public:
+    Converter();
+    QSharedPointer<Entity> convert(const QHash<QString, QVariant> &map,
+                                   const char *classname, Cache &cache);
+    void convert(const QHash<QString, QVariant> &map, QSharedPointer<Entity> &entity, Cache &cache);
+    QList<QSharedPointer<Entity>> convert(QList<QHash<QString, QVariant>> maps,
+                                          const char *classname, Cache &cache);
+    template<class T, class X>
+    static QList<QSharedPointer<T>> convertList(const QList<QSharedPointer<X>> &list) {
+        QList<QSharedPointer<T>> newList = QList<QSharedPointer<T>>();
+        for (int i = 0; i < list.size(); ++i) {
+            newList.append(qSharedPointerObjectCast<T>(list.at(i)));
+        }
+        return newList;
+    }
+};
+}
+
+#endif // CONVERTER_H
diff --git a/src/entitymanager.cpp b/src/entitymanager.cpp
index c69476a..227b3f8 100644
--- a/src/entitymanager.cpp
+++ b/src/entitymanager.cpp
@@ -25,6 +25,9 @@
 #include "validators/validator.h"
 #include "validators/validatorrule.h"
 #include "entityinspector.h"
+#include "relations/hasmany.h"
+#include "relations/hasone.h"
+#include "relations/belongsto.h"
 
 using namespace CuteEntityManager;
 
@@ -300,13 +303,15 @@ QSharedPointer<Schema> EntityManager::getSchema() const {
 
 QList<QHash<QString, QVariant>> EntityManager::selectByQuery(Query &query) {
     QSqlQuery q = this->queryInterpreter->build(query);
-    return this->convertQueryResult(q);
+    Resolver r = Resolver(this->db);
+    return r.convertQueryResult(q);
 }
 
 QList<QHash<QString, QVariant>> EntityManager::selectBySql(
         const QString &sql) {
     QSqlQuery q = this->db->select(sql);
-    return this->convertQueryResult(q);
+    Resolver r = Resolver(this->db);
+    return r.convertQueryResult(q);
 }
 
 bool EntityManager::validate(QSharedPointer<Entity> &entity) {
@@ -402,7 +407,12 @@ QSharedPointer<Entity> EntityManager::findById(const qint64 &id,
     QSharedPointer<Entity> r;
     if (e && (refresh || !(r = this->cache.get(id, EntityHelper::getClassname(e.data()))))) {
         auto map  = this->findByPk(id, e);
-        r = this->convert(map, EntityHelper::getClassname(e.data()), refresh);
+        Converter c = Converter();
+        r = c.convert(map, EntityHelper::getClassname(e.data()),this->cache);
+        if(refresh) {
+            this->resolveRelations(r,map);
+        }
+
     }
     return r;
 }
@@ -439,9 +449,11 @@ void EntityManager::oneToMany(const QSharedPointer<Entity> &entity,
                         attr->getRelatedTable(),
                         attr->getRelatedColumnName(), entity->getId());
             QSqlQuery q = this->queryInterpreter->build(query);
-            auto listMap = this->convertQueryResult(q);
+            Resolver r = Resolver(this->db);
+            auto listMap = r.convertQueryResult(q);
             auto relationalClass = EntityHelper::getClassName(e.data());
-            auto entities = this->convert(listMap, relationalClass.toLatin1());
+            Converter c = Converter();
+            auto entities = c.convert(listMap, relationalClass.toLatin1(),this->cache);
             EntityHelper::setListProperty(entity,entities,attr->getMetaProperty());
         }
     }
@@ -461,8 +473,10 @@ void EntityManager::oneToOne(const QSharedPointer<Entity> &entity,
                             attr->getRelation().getMappedBy()),
                         entity->getProperty(entity->getPrimaryKey()).toLongLong(), 1);
             QSqlQuery q = this->queryInterpreter->build(query);
-            auto listMap = this->convertQueryResult(q);
-            auto entities = this->convert(listMap, EntityHelper::getClassname(e.data()));
+            Resolver r = Resolver(this->db);
+            auto listMap = r.convertQueryResult(q);
+            Converter c = Converter();
+            auto entities = c.convert(listMap, EntityHelper::getClassname(e.data()),this->cache);
             if (!entities.isEmpty()) {
                 QSharedPointer<Entity> ptr = entities.at(0);
                 EntityHelper::setFoundProperty(entity, ptr, attr->getMetaProperty());
@@ -509,8 +523,8 @@ void EntityManager::savePostPersistedRelations(const QSharedPointer<Entity>
         const Relation r = i.key();
         QVariant var = i.value().read(entity.data());
         if (r.getType() == RelationType::MANY_TO_MANY) {
-            this->persistManyToMany(entity, r, var, mergedObjects, ignoreHasChanged,
-                                    newItem);
+            HasMany hm(entity,r,this->schema);
+            hm.persist(var,mergedObjects,newItem,this);
         } else if (r.getType() == RelationType::ONE_TO_MANY) {
             QList<QSharedPointer<Entity>> list = EntityInstanceFactory::castQVariantList(
                         var);
@@ -536,39 +550,6 @@ void EntityManager::savePostPersistedRelations(const QSharedPointer<Entity>
     }
 }
 
-void EntityManager::persistMappedByRelation(const QList<QSharedPointer<Entity>>
-                                            &list, QSqlQuery &q, const QSharedPointer<Entity> &entity,
-                                            const QSharedPointer<Entity> &ptr, const Relation &r,
-                                            const QString &tblName, QList<Entity *> &mergedObjects) {
-    q.clear();
-    QList<QSharedPointer<Entity>> saved =
-            r.getCascadeType().contains(CascadeType::ALL) ||
-            r.getCascadeType().contains(CascadeType::MERGE) ||
-            r.getCascadeType().contains(CascadeType::PERSIST) ?
-                this->saveRelationEntities(list, r, mergedObjects) : list;
-    this->db->startTransaction();
-    auto builder = this->schema->getQueryBuilder();
-    q = builder->manyToManyInsert(tblName,
-                                  builder->generateManyToManyColumnName(entity, r.getPropertyName()),
-                                  builder->generateManyToManyColumnName(ptr, r.getMappedBy()));
-    q.bindValue(0, entity->getProperty(entity->getPrimaryKey()));
-    auto prop = EntityHelper::mappedProperty(r, ptr);
-    QSharedPointer<Entity> item;
-    for (int var = 0; var < saved.size(); ++var) {
-        item = list.at(var);
-        if (item->getProperty(item->getPrimaryKey()).toLongLong() > -1) {
-            q.bindValue(1, item->getProperty(ptr->getPrimaryKey()));
-            bool ok = this->db->exec(q);
-            if (ok) {
-                EntityHelper::addEntityToListProperty(item, entity, prop);
-            }
-        }
-    }
-    if (!this->db->commitTransaction()) {
-        this->db->rollbackTransaction();
-    }
-}
-
 QString EntityManager::generateObjectName() {
     int i = 0;
     QString name = "em[";
@@ -623,7 +604,8 @@ void EntityManager::removeRelations(const QSharedPointer<Entity> &entity) {
         auto property = i.value();
         auto var = property.read(entity.data());
         if (r.getType() == RelationType::MANY_TO_MANY) {
-            this->removeManyToManyEntityList(entity, r, var);
+            HasMany hm(entity,r,this->schema);
+            hm.removeEntityList(var,this);
         } else if (r.getType() == RelationType::ONE_TO_MANY) {
             if (r.getCascadeType().contains(CascadeType::REMOVE)
                     || r.getCascadeType().contains(CascadeType::ALL)) {
@@ -692,39 +674,6 @@ void EntityManager::removeEntityList(QVariant &var) {
     }
 }
 
-void EntityManager::removeManyToManyEntityList(const QSharedPointer<Entity> &e,
-                                               const Relation &r,
-                                               QVariant &var) {
-    if (!var.isNull() && var.canConvert<QVariantList>()) {
-        auto list = EntityInstanceFactory::castQVariantList(var);
-        if (!list.isEmpty()) {
-            auto builder = this->schema->getQueryBuilder();
-            auto ptr = list.at(0);
-            QString tblName = builder->generateManyToManyTableName(e, ptr, r);
-            if (this->schema->getTables().contains(tblName)) {
-                QSqlQuery q = builder->manyToManyDelete(
-                            tblName, builder->generateManyToManyColumnName(e, r.getPropertyName()),
-                            e->getProperty(e->getPrimaryKey()).toLongLong());
-                if (this->db->exec(q)) {
-                    bool refresh = r.getCascadeType().contains(CascadeType::REFRESH)
-                            || r.getCascadeType().contains(CascadeType::ALL);
-                    bool remove = r.getCascadeType().contains(CascadeType::REMOVE)
-                            || r.getCascadeType().contains(CascadeType::ALL);
-                    auto fkProp = EntityHelper::mappedProperty(r, ptr);
-                    for (int var = 0; var < list.size(); ++var) {
-                        auto entity = list.at(var);
-                        if (remove) {
-                            this->remove(entity);
-                        } else if (refresh) {
-                            EntityHelper::removeEntityFromListProperty(entity, e, fkProp);
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
-
 QList<QSharedPointer<Entity>> EntityManager::saveRelationEntities(
         const QList<QSharedPointer<Entity>> &list, const Relation &r,
         QList<Entity *> &mergedObjects) {
@@ -740,85 +689,12 @@ QList<QSharedPointer<Entity>> EntityManager::saveRelationEntities(
     return saved;
 }
 
-void EntityManager::persistManyToMany(const QSharedPointer<Entity> &entity,
-                                      const Relation &r, QVariant &property, QList<Entity *> &mergedObjects,
-                                      const bool ignoreHasChanged, const bool newItem) {
-    auto list = property.value<QList<QVariant>>();
-    auto ptr = QSharedPointer<Entity>(EntityInstanceFactory::createInstance(
-                                          EntityInstanceFactory::extractEntityType(QString(property.typeName()))));
-    auto builder = this->schema->getQueryBuilder();
-    QString tblName = builder->generateManyToManyTableName(entity, ptr, r);
-    if (this->schema->containsTable(tblName)) {
-        bool ok = newItem;
-        QSqlQuery q;
-        if (!newItem) {
-            /**
-              * @todo diff and remove entity from relational object when association is deleted
-              */
-            q = builder->manyToManyDelete(
-                        tblName, builder->generateManyToManyColumnName(entity, r.getPropertyName()),
-                        entity->getProperty(entity->getPrimaryKey()).toLongLong());
-            ok = this->db->exec(q);
-        } else {
-            q = builder->getQuery();
-        }
-        if (ok && !list.isEmpty() && list.at(0).data()) {
-            auto nList = EntityInstanceFactory::castQVariantList(property);
-            this->persistMappedByRelation(nList, q, entity, ptr, r, tblName, mergedObjects);
-        }
-    } else {
-        this->missingManyToManyTable(tblName, entity, r);
-    }
-}
-
-void EntityManager::missingManyToManyTable(const QString &tblName,
-                                           const QSharedPointer<Entity> &e, const Relation &r) {
-    QString text = "MANY_TO_MANY Table " + tblName + " is missing.\n" +
-            "Entity " + EntityHelper::getClassName(e.data()) +
-            " is affected.\n" + "Relation of property: " + r.getPropertyName();
-#ifdef QT_DEBUG
-    throw QString(text);
-#else
-    this->logger->logMsg(text, MsgType::CRITICAL);
-#endif
-}
-
-void EntityManager::manyToMany(const QSharedPointer<Entity> &entity,
-                               Attribute *&attr) {
-    QSharedPointer<Entity> secEntityPtr = QSharedPointer<Entity>
-            (EntityInstanceFactory::createInstance(attr->getRelatedClass()->className()));
-    auto builder = this->schema->getQueryBuilder();
-    EntityHelper::clearEntityListProperty(entity, attr->getMetaProperty());
-    if (secEntityPtr) {
-        if (this->schema->getTables().contains(attr->getTableName())) {
-            QSqlQuery q = builder->manyToMany(attr->getConjunctedTable(),
-                                              attr->getColumnName(),
-                                              entity->getProperty(entity->getPrimaryKey()).toLongLong());
-            auto listMap = this->convertQueryResult(q);
-            auto secClassName = attr->getRelatedClass()->className();
-            QSharedPointer<Entity> e;
-            for (int var = 0; var < listMap.size(); ++var) {
-                auto id = listMap.at(var).value(attr->getRelatedColumnName());
-                if (!(this->cache.contains(id.toLongLong(), secClassName) &&
-                      (e = this->cache.get(id.toLongLong(), secClassName)))) {
-                    e = this->findById(id.toLongLong(), secClassName);
-                }
-                if (e) {
-                    EntityHelper::addEntityToListProperty(entity, e, attr->getMetaProperty());
-                    e = QSharedPointer<Entity>();
-                }
-            }
-        } else {
-            this->missingManyToManyTable(attr->getConjunctedTable(), entity, attr->getRelation());
-        }
-    }
-}
-
 QList<QSharedPointer<Entity>> EntityManager::findEntityByAttributes(
         const QSharedPointer<Entity> &entity,
-        bool ignoreID, const bool resolveRelations) {
+        bool ignoreID) {
     auto maps = this->findAllByAttributes(entity, ignoreID);
-    return this->convert(maps, EntityHelper::getClassname(entity.data()), resolveRelations);
+    Converter c = Converter();
+    return c.convert(maps, EntityHelper::getClassname(entity.data()),this->cache);
 }
 
 QHash<QString, QVariant> EntityManager::findByPk(qint64 id,
@@ -826,7 +702,8 @@ QHash<QString, QVariant> EntityManager::findByPk(qint64 id,
                                                  &e) {
     QSqlQuery q = this->schema->getQueryBuilder()->find(id, e, 0,
                                                         e->getPrimaryKey());
-    auto listMap  = this->convertQueryResult(q);
+    Resolver r = Resolver(this->db);
+    auto listMap = r.convertQueryResult(q);
     if (!listMap.isEmpty()) {
         return listMap.at(0);
     }
@@ -841,7 +718,8 @@ QList<QHash<QString, QVariant>> EntityManager::findAllByAttributes(
     Query query = this->schema->getQueryBuilder()->findByAttributes(
                 entity, ignoreID);
     QSqlQuery q = this->queryInterpreter->build(query);
-    return this->convertQueryResult(q);
+    Resolver r = Resolver(this->db);
+    return r.convertQueryResult(q);
 }
 
 QList<QHash <QString, QVariant>> EntityManager::findAllByAttributes(
@@ -849,33 +727,17 @@ QList<QHash <QString, QVariant>> EntityManager::findAllByAttributes(
     Query query = this->schema->getQueryBuilder()->findByAttributes(m,
                                                                     tblname, ignoreID);
     QSqlQuery q = this->queryInterpreter->build(query);
-    return this->convertQueryResult(q);
+    Resolver r = Resolver(this->db);
+    return r.convertQueryResult(q);
 }
 
-QList<QHash<QString, QVariant>> EntityManager::convertQueryResult(
-        QSqlQuery &q) {
-    QList<QHash <QString, QVariant>> listmap = QList<QHash <QString, QVariant>>();
-    this->db->select(q);
-    QSqlRecord rec = q.record();
-    QStringList l = QStringList();
-    qint16 field_count = rec.count();
-    for (int var = 0; var < field_count; ++var) {
-        l.append(rec.fieldName(var));
-    }
-    QHash<QString, QVariant> map = QHash<QString, QVariant>();
-    while (q.next()) {
-        for (int var = 0; var < field_count; ++var) {
-            map.insert(l.at(var), q.value(rec.indexOf(l.at(var))));
-        }
-        listmap.append(map);
-    }
-    return listmap;
-}
+
 
 QList<QHash <QString, QVariant>> EntityManager::findAll(
         const QSharedPointer<Entity> &e) {
     QSqlQuery q = this->schema->getQueryBuilder()->findAll(e);
-    return this->convertQueryResult(q);
+    Resolver r = Resolver(this->db);
+    return r.convertQueryResult(q);
 }
 
 void EntityManager::resolveRelations(const QSharedPointer<Entity> &entity,
@@ -893,8 +755,10 @@ void EntityManager::resolveRelations(const QSharedPointer<Entity> &entity,
                 this->manyToOne(entity, map.value(colName), attr);
             }
             break;
-        case RelationType::MANY_TO_MANY:
-            this->manyToMany(entity, attr);
+        case RelationType::MANY_TO_MANY: {
+            HasMany hm = HasMany(entity,r,this->schema);
+            hm.resolve(entity,attr,this->cache,this);
+        }
             break;
         case RelationType::ONE_TO_MANY:
             this->oneToMany(entity, attr);
@@ -981,36 +845,3 @@ quint32 EntityManager::count(Query &query) {
 void EntityManager::setConnectionNames(QStringList list) {
     EntityManager::connectionNames = list;
 }
-
-QSharedPointer<Entity> EntityManager::convert(const QHash<QString, QVariant>
-                                              &map,
-                                              const char *classname, const bool resolveRelations) {
-    auto ptr = QSharedPointer<Entity>(map.isEmpty() ? nullptr : EntityInstanceFactory::createInstance(
-                                                          classname, map));
-    this->cache.insert(ptr);
-    if (resolveRelations) {
-        this->resolveRelations(ptr, map);
-    }
-    return ptr;
-}
-
-void EntityManager::convert(const QHash<QString, QVariant> &map,
-                            QSharedPointer<Entity> &entity, const bool resolveRelations) {
-    this->cache.insert(entity);
-    auto data = entity.data();
-    EntityInstanceFactory::setAttributes(data, map);
-    if (resolveRelations) {
-        this->resolveRelations(entity, map);
-    }
-}
-
-QList<QSharedPointer<Entity>> EntityManager::convert(
-        QList<QHash<QString, QVariant>> maps,
-        const char *classname, const bool resolveRelations) {
-    auto list = QList<QSharedPointer<Entity>>();
-    for (int var = 0; var < maps.size(); ++var) {
-        auto ptr = this->convert(maps.at(var), classname, resolveRelations);
-        list.append(ptr);
-    }
-    return list;
-}
diff --git a/src/entitymanager.h b/src/entitymanager.h
index c10b4ee..578a781 100644
--- a/src/entitymanager.h
+++ b/src/entitymanager.h
@@ -34,6 +34,9 @@
 #include "querybuilder.h"
 #include "validators/errormsg.h"
 #include "attribute.h"
+#include "resolver.h"
+#include "converter.h"
+
 namespace CuteEntityManager {
 #ifdef QT_DEBUG
 #include <QDebug>
@@ -64,7 +67,7 @@ class EntityManager : public QObject {
                                     const bool refresh = false);
     QList<QSharedPointer<Entity>> findEntityByAttributes(const
                                QSharedPointer<Entity> &entity,
-                               bool ignoreID = false, const bool resolveRelations = true);
+                               bool ignoreID = false);
     qint64 findId(QSharedPointer<Entity> &entity);
     /**
      * @todo should be an insert statement with many values
@@ -145,10 +148,16 @@ class EntityManager : public QObject {
                 q.appendJoins(this->schema->getQueryBuilder()->joinBaseClasses(ptr));
             }
             QSqlQuery query = this->queryInterpreter->build(q, ptr->metaObject());
-            auto maps = this->convertQueryResult(query);
-            auto converted = this->convert(maps, EntityHelper::getClassname(ptr.data()),
-                                           resolveRelations);
-            return EntityManager::convertList<T>(converted);
+            Resolver r(this->db);
+            auto maps = r.convertQueryResult(query);
+            Converter c = Converter();
+            auto converted = c.convert(maps, EntityHelper::getClassname(ptr.data()),this->cache);
+            if (resolveRelations) {
+                for (int var = 0; var < maps.size(); ++var) {
+                    this->resolveRelations(converted.at(var), maps.at(var));
+                }
+            }
+         return Converter::convertList<T>(converted);
         }
         return QList<QSharedPointer<T>>();
     }
@@ -232,7 +241,11 @@ class EntityManager : public QObject {
         if(entity) {
             auto map  = this->findByPk(entity->getId(), entity);
             QSharedPointer<Entity> e = entity;
-            this->convert(map, e, resolveRelations);
+            Converter c = Converter();
+            c.convert(map, e,this->cache);
+            if (resolveRelations) {
+                this->resolveRelations(entity, map);
+            }
         }
     }
     /**
@@ -261,9 +274,14 @@ class EntityManager : public QObject {
                                      (EntityInstanceFactory::createInstance<T *>());
         if (ptr) {
             auto maps = this->findAll(ptr);
-            auto converted = this->convert(maps, EntityHelper::getClassname(ptr.data()),
-                                           resolveRelations);
-            return EntityManager::convertList<T>(converted);
+            Converter c = Converter();
+            auto converted = c.convert(maps, EntityHelper::getClassname(ptr.data()),this->cache);
+            if (resolveRelations) {
+                for (int var = 0; var < maps.size(); ++var) {
+                    this->resolveRelations(converted.at(var), maps.at(var));
+                }
+            }
+            return Converter::convertList<T>(converted);
         }
         return QList<QSharedPointer<T>>();
     }
@@ -304,10 +322,16 @@ class EntityManager : public QObject {
             query.setLimit(limit);
             query.setOffset(offset);
             QSqlQuery q = this->queryInterpreter->build(query);
-            auto results = this->convertQueryResult(q);
-            auto list = this->convert(results, EntityHelper::getClassname(e.data()),
-                                      resolveRelations);
-            return EntityManager::convertList<T>(list);
+            Resolver r(this->db);
+            auto results = r.convertQueryResult(q);
+            Converter c = Converter();
+            auto list = c.convert(results, EntityHelper::getClassname(e.data()),this->cache);
+            if (resolveRelations) {
+                for (int var = 0; var < results.size(); ++var) {
+                    this->resolveRelations(list.at(var), results.at(var));
+                }
+            }
+            return Converter::convertList<T>(list);
         }
         return QList<QSharedPointer<T>>();
     }
@@ -317,9 +341,11 @@ class EntityManager : public QObject {
         auto e = EntityInstanceFactory::createInstance<T *>();
         if (e) {
             QSqlQuery q = this->schema->getDatabase()->getQuery(sql);
-            auto result = this->convertQueryResult(q);
-            auto converted = this->convert(result, EntityHelper::getClassname(e));
-            return EntityManager::convertList<T>(converted);
+            Resolver r = Resolver(this->db);
+            auto result = r.convertQueryResult(q);
+            Converter c = Converter();
+            auto converted = c.convert(result, EntityHelper::getClassname(e));
+            return Converter::convertList<T>(converted);
         }
         return QList<QSharedPointer<T>>();
     }
@@ -345,14 +371,9 @@ class EntityManager : public QObject {
         return false;
     }
 
-    template<class T, class X>
-    static QList<QSharedPointer<T>> convertList(const QList<QSharedPointer<X>> &list) {
-        QList<QSharedPointer<T>> newList = QList<QSharedPointer<T>>();
-        for (int i = 0; i < list.size(); ++i) {
-            newList.append(qSharedPointerObjectCast<T>(list.at(i)));
-        }
-        return newList;
-    }
+    QList<QSharedPointer<Entity>> saveRelationEntities(const
+                               QList<QSharedPointer<Entity>> &list, const Relation &r,
+                               QList<Entity *> &mergedObjects);
 
   protected:
     bool saveObject(QSharedPointer<Entity> &entity, QList<Entity *> &mergedObjects,
@@ -374,12 +395,8 @@ class EntityManager : public QObject {
     void manyToOne(const QSharedPointer<Entity> &entity, const QVariant &id,
                    Attribute *&attr);
     void oneToMany(const QSharedPointer<Entity> &entity, Attribute *&attr);
-    void manyToMany(const QSharedPointer<Entity> &entity, Attribute *&attr);
     void oneToOne(const QSharedPointer<Entity> &entity, Attribute *&attr,
                   const QVariant &id = "");
-    void persistManyToMany(const QSharedPointer<Entity> &entity, const Relation &r,
-                           QVariant &property, QList<Entity *> &mergedObjects,
-                           const bool ignoreHasChanged = false, const bool newItem = false);
     QList<QHash<QString, QVariant>> findAllByAttributes(const
                                  QSharedPointer<Entity> &entity,
                                  bool ignoreID = false);
@@ -406,39 +423,12 @@ class EntityManager : public QObject {
     void savePostPersistedRelations(const QSharedPointer<Entity> &entity,
                                     QList<Entity *> &mergedObjects, bool ignoreHasChanged = false,
                                     bool newItem = false);
-
-    QList<QSharedPointer<Entity>> saveRelationEntities(const
-                               QList<QSharedPointer<Entity>> &list, const Relation &r,
-                               QList<Entity *> &mergedObjects);
-    /**
-     * @brief EntityManager::persistManyToMany
-     * @param entity
-     * @param r
-     * @param property
-     * @param mergedObjects
-     * @todo compare old values with new values if nothing has changed don't persist them
-     */
-    void persistMappedByRelation(const QList<QSharedPointer<Entity>> &list,
-                                 QSqlQuery &q, const QSharedPointer<Entity> &entity,
-                                 const QSharedPointer<Entity> &ptr, const Relation &r,
-                                 const QString &tblName, QList<Entity *> &mergedObjects);
     bool shouldBeSaved(QSharedPointer<Entity> &entity , const Relation &r);
     void removeRelations(const QSharedPointer<Entity> &entity);
     void removeEntityList(QVariant &var);
-    void removeManyToManyEntityList(const QSharedPointer<Entity> &e,
-                                    const Relation &r, QVariant &var);
     void removeEntity(QVariant &var);
     void setNullOneToManyRelation(QVariant &var, const Relation &r);
     void setNullEntityPropertyRelation(QVariant &var, const Relation &r);
-    QSharedPointer<Entity> convert(const QHash<QString, QVariant> &map,
-                                   const char *classname,
-                                   const bool resolveRelations = true);
-    void convert(const QHash<QString, QVariant> &map, QSharedPointer<Entity> &entity,
-                 const bool resolveRelations = true);
-    QList<QSharedPointer<Entity>> convert(QList<QHash<QString, QVariant>> maps,
-                                          const char *classname, const bool resolveRelations = true);
-    void missingManyToManyTable(const QString &tblName,
-                                const QSharedPointer<Entity> &e, const Relation &r);
     /**
      * @brief EntityManager::generateObjectName
      * Generates a object name with this scheme: em[anyNumber]
@@ -458,7 +448,6 @@ class EntityManager : public QObject {
     QSharedPointer<Database> db;
     Cache cache;
     QString createConnection();
-    QList<QHash<QString, QVariant>> convertQueryResult(QSqlQuery &q);
     /**
      * @brief EntityManager::checkTable
      * Checks if a table has been already created, if not it will create it
diff --git a/src/querybuilder.h b/src/querybuilder.h
index b0a2d6f..325b468 100644
--- a/src/querybuilder.h
+++ b/src/querybuilder.h
@@ -45,6 +45,9 @@ class QueryBuilder {
     friend class EntityManager;
     friend class QueryInterpreter;
     friend class AttributeResolver;
+    friend class HasMany;
+    friend class HasOne;
+    friend class BelongsTo;
   public:
     QueryBuilder(Schema *schema, QSharedPointer<Database> &database);
     virtual ~QueryBuilder();
diff --git a/src/relations/belongsto.cpp b/src/relations/belongsto.cpp
new file mode 100644
index 0000000..b98c846
--- /dev/null
+++ b/src/relations/belongsto.cpp
@@ -0,0 +1,7 @@
+#include "belongsto.h"
+using namespace CuteEntityManager;
+
+BelongsTo::BelongsTo()
+{
+
+}
diff --git a/src/relations/belongsto.h b/src/relations/belongsto.h
new file mode 100644
index 0000000..544a6a2
--- /dev/null
+++ b/src/relations/belongsto.h
@@ -0,0 +1,11 @@
+#ifndef BELONGSTO_H
+#define BELONGSTO_H
+namespace CuteEntityManager {
+
+class BelongsTo
+{
+public:
+    BelongsTo();
+};
+}
+#endif // BELONGSTO_H
diff --git a/src/relations/hasmany.cpp b/src/relations/hasmany.cpp
new file mode 100644
index 0000000..16600e3
--- /dev/null
+++ b/src/relations/hasmany.cpp
@@ -0,0 +1,151 @@
+#include "hasmany.h"
+#include "entityinstancefactory.h"
+#include "entityhelper.h"
+#include "database.h"
+#include "resolver.h"
+using namespace CuteEntityManager;
+
+HasMany::HasMany(const QSharedPointer<Entity> &entity, const Relation &r, const QSharedPointer<Schema> schema)
+{
+    this->entity = entity;
+    this->relation = r;
+    this->schema = schema;
+}
+
+void HasMany::persist(
+        QVariant &property, QList<Entity *> &mergedObjects,
+        const bool newItem, EntityManager *em) {
+    auto list = property.value<QList<QVariant>>();
+    auto ptr = QSharedPointer<Entity>(EntityInstanceFactory::createInstance(
+                                          EntityInstanceFactory::extractEntityType(QString(property.typeName()))));
+    auto builder = this->schema->getQueryBuilder();
+    QString tblName = builder->generateManyToManyTableName(this->entity, ptr, this->relation);
+    if (this->schema->containsTable(tblName)) {
+        bool ok = newItem;
+        QSqlQuery q;
+        if (!newItem) {
+            /**
+              * @todo diff and remove entity from relational object when association is deleted
+              */
+            q = builder->manyToManyDelete(
+                        tblName, builder->generateManyToManyColumnName(this->entity, this->relation.getPropertyName()),
+                        this->entity->getProperty(this->entity->getPrimaryKey()).toLongLong());
+            ok = this->schema->getDatabase()->exec(q);
+        } else {
+            q = builder->getQuery();
+        }
+        if (ok && !list.isEmpty() && list.at(0).data()) {
+            auto nList = EntityInstanceFactory::castQVariantList(property);
+            QList<QSharedPointer<Entity>> saved =
+                    this->relation.getCascadeType().contains(CascadeType::ALL) ||
+                    this->relation.getCascadeType().contains(CascadeType::MERGE) ||
+                    this->relation.getCascadeType().contains(CascadeType::PERSIST) ?
+                        em->saveRelationEntities(nList, this->relation, mergedObjects) : nList;
+            this->persistMappedByRelation(saved, q, this->entity, ptr, this->relation, tblName);
+        }
+    } else {
+        this->missingTable(tblName);
+    }
+}
+
+void HasMany::missingTable(const QString &tblName) {
+    QString text = "MANY_TO_MANY Table " + tblName + " is missing.\n" +
+            "Entity " + EntityHelper::getClassName(this->entity.data()) +
+            " is affected.\n" + "Relation of property: " + this->relation.getPropertyName();
+#ifdef QT_DEBUG
+    throw QString(text);
+#else
+    this->logger->logMsg(text, MsgType::CRITICAL);
+#endif
+}
+
+void HasMany::persistMappedByRelation(const QList<QSharedPointer<Entity>>
+                                      &list, QSqlQuery &q, const QSharedPointer<Entity> &entity,
+                                      const QSharedPointer<Entity> &ptr, const Relation &r,
+                                      const QString &tblName) {
+    q.clear();
+    this->schema->getDatabase()->startTransaction();
+    auto builder = this->schema->getQueryBuilder();
+    q = builder->manyToManyInsert(tblName,
+                                  builder->generateManyToManyColumnName(entity, r.getPropertyName()),
+                                  builder->generateManyToManyColumnName(ptr, r.getMappedBy()));
+    q.bindValue(0, entity->getProperty(entity->getPrimaryKey()));
+    auto prop = EntityHelper::mappedProperty(r, ptr);
+    QSharedPointer<Entity> item;
+    for (int var = 0; var < list.size(); ++var) {
+        item = list.at(var);
+        if (item->getProperty(item->getPrimaryKey()).toLongLong() > -1) {
+            q.bindValue(1, item->getProperty(ptr->getPrimaryKey()));
+            bool ok = this->schema->getDatabase()->exec(q);
+            if (ok) {
+                EntityHelper::addEntityToListProperty(item, entity, prop);
+            }
+        }
+    }
+    if (!this->schema->getDatabase()->commitTransaction()) {
+        this->schema->getDatabase()->rollbackTransaction();
+    }
+}
+
+void HasMany::removeEntityList(QVariant &var, EntityManager *em) {
+    if (!var.isNull() && var.canConvert<QVariantList>()) {
+        auto list = EntityInstanceFactory::castQVariantList(var);
+        if (!list.isEmpty()) {
+            auto builder = this->schema->getQueryBuilder();
+            auto ptr = list.at(0);
+            QString tblName = builder->generateManyToManyTableName(this->entity, ptr, this->relation);
+            if (this->schema->getTables().contains(tblName)) {
+                QSqlQuery q = builder->manyToManyDelete(
+                            tblName, builder->generateManyToManyColumnName(this->entity, this->relation.getPropertyName()),
+                            this->entity->getProperty(this->entity->getPrimaryKey()).toLongLong());
+                if (this->schema->getDatabase()->exec(q)) {
+                    bool refresh = this->relation.getCascadeType().contains(CascadeType::REFRESH)
+                            || this->relation.getCascadeType().contains(CascadeType::ALL);
+                    bool remove = this->relation.getCascadeType().contains(CascadeType::REMOVE)
+                            || this->relation.getCascadeType().contains(CascadeType::ALL);
+                    auto fkProp = EntityHelper::mappedProperty(this->relation, ptr);
+                    for (int var = 0; var < list.size(); ++var) {
+                        auto removeEntity = list.at(var);
+                        if (remove) {
+                            em->remove(removeEntity);
+                        } else if (refresh) {
+                            EntityHelper::removeEntityFromListProperty(removeEntity, this->entity, fkProp);
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+void HasMany::resolve(const QSharedPointer<Entity> &entity,
+                      Attribute *&attr, Cache &cache, EntityManager *em) {
+    QSharedPointer<Entity> secEntityPtr = QSharedPointer<Entity>
+            (EntityInstanceFactory::createInstance(attr->getRelatedClass()->className()));
+    auto builder = this->schema->getQueryBuilder();
+    EntityHelper::clearEntityListProperty(entity, attr->getMetaProperty());
+    if (secEntityPtr) {
+        if (this->schema->getTables().contains(attr->getTableName())) {
+            QSqlQuery q = builder->manyToMany(attr->getConjunctedTable(),
+                                              attr->getColumnName(),
+                                              entity->getProperty(entity->getPrimaryKey()).toLongLong());
+            Resolver r(this->schema->getDatabase());
+            auto listMap = r.convertQueryResult(q);
+            auto secClassName = attr->getRelatedClass()->className();
+            for (int var = 0; var < listMap.size(); ++var) {
+                QSharedPointer<Entity> e;
+                auto id = listMap.at(var).value(attr->getRelatedColumnName());
+                if (!(cache.contains(id.toLongLong(), secClassName) &&
+                      (e = cache.get(id.toLongLong(), secClassName)))) {
+                    e = em->findById(id.toLongLong(), secClassName);
+                }
+                if (e) {
+                    EntityHelper::addEntityToListProperty(entity, e, attr->getMetaProperty());
+                    e = QSharedPointer<Entity>();
+                }
+            }
+        } else {
+            this->missingTable(attr->getConjunctedTable());
+        }
+    }
+}
diff --git a/src/relations/hasmany.h b/src/relations/hasmany.h
new file mode 100644
index 0000000..4af9142
--- /dev/null
+++ b/src/relations/hasmany.h
@@ -0,0 +1,34 @@
+#ifndef HASMANY_H
+#define HASMANY_H
+#include <QSharedPointer>
+#include "entity.h"
+#include "schema.h"
+#include "attribute.h"
+#include "cache.h"
+#include "entitymanager.h"
+namespace CuteEntityManager {
+class HasMany
+{
+public:
+    HasMany(const QSharedPointer<Entity> &entity, const Relation &r, const QSharedPointer<Schema> schema);
+    /**
+     * @todo compare old values with new values if nothing has changed don't persist them
+     */
+    void persist(QVariant &property, QList<Entity *> &mergedObjects, const bool newItem, EntityManager *em);
+    void resolve(const QSharedPointer<Entity> &entity, Attribute *&attr, Cache &cache, EntityManager *em);
+    void persistMappedByRelation(const QList<QSharedPointer<Entity>> &list,
+                                 QSqlQuery &q, const QSharedPointer<Entity> &entity,
+                                 const QSharedPointer<Entity> &ptr, const Relation &r,
+                                 const QString &tblName);
+    void removeEntityList(QVariant &var, EntityManager *em);
+    void missingTable(const QString &tblName);
+protected:
+    QSharedPointer<Entity> entity;
+    Relation relation;
+    QSharedPointer<Entity> target;
+    QSharedPointer<Schema> schema;
+
+
+};
+}
+#endif // HASMANY_H
diff --git a/src/relations/hasone.cpp b/src/relations/hasone.cpp
new file mode 100644
index 0000000..baba784
--- /dev/null
+++ b/src/relations/hasone.cpp
@@ -0,0 +1,7 @@
+#include "hasone.h"
+using namespace CuteEntityManager;
+
+HasOne::HasOne()
+{
+
+}
diff --git a/src/relations/hasone.h b/src/relations/hasone.h
new file mode 100644
index 0000000..d661dd3
--- /dev/null
+++ b/src/relations/hasone.h
@@ -0,0 +1,11 @@
+#ifndef HASONE_H
+#define HASONE_H
+namespace CuteEntityManager {
+
+class HasOne
+{
+public:
+    HasOne();
+};
+}
+#endif // HASONE_H
diff --git a/src/resolver.cpp b/src/resolver.cpp
new file mode 100644
index 0000000..5535970
--- /dev/null
+++ b/src/resolver.cpp
@@ -0,0 +1,27 @@
+#include "resolver.h"
+#include <QSqlRecord>
+using namespace CuteEntityManager;
+
+Resolver::Resolver(QSharedPointer<Database> db)
+{
+    this->db = db;
+}
+
+QList<QHash<QString, QVariant>> Resolver::convertQueryResult(QSqlQuery &q) {
+    QList<QHash <QString, QVariant>> listmap = QList<QHash <QString, QVariant>>();
+    this->db->select(q);
+    QSqlRecord rec = q.record();
+    QStringList l = QStringList();
+    qint16 field_count = rec.count();
+    for (int var = 0; var < field_count; ++var) {
+        l.append(rec.fieldName(var));
+    }
+    QHash<QString, QVariant> map = QHash<QString, QVariant>();
+    while (q.next()) {
+        for (int var = 0; var < field_count; ++var) {
+            map.insert(l.at(var), q.value(rec.indexOf(l.at(var))));
+        }
+        listmap.append(map);
+    }
+    return listmap;
+}
diff --git a/src/resolver.h b/src/resolver.h
new file mode 100644
index 0000000..f7e45a9
--- /dev/null
+++ b/src/resolver.h
@@ -0,0 +1,18 @@
+#ifndef RESOLVER_H
+#define RESOLVER_H
+#include <QSqlQuery>
+#include <QSharedPointer>
+#include "database.h"
+
+namespace CuteEntityManager {
+class Resolver
+{
+public:
+    Resolver(QSharedPointer<Database> db);
+    QList<QHash<QString, QVariant>> convertQueryResult(QSqlQuery &q);
+protected:
+    QSharedPointer<Database> db;
+};
+}
+
+#endif // RESOLVER_H
diff --git a/src/src.pro b/src/src.pro
index 70fa007..6150c6f 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -55,7 +55,12 @@ entity.h \
     entityinspector.h \
     sqlitebackupprocessor.h \
     attribute.h \
-    attributeresolver.h
+    attributeresolver.h \
+    relations/hasmany.h \
+    relations/hasone.h \
+    relations/belongsto.h \
+    converter.h \
+    resolver.h
 
 SOURCES += \
 entity.cpp \
@@ -101,7 +106,12 @@ entity.cpp \
     entityinspector.cpp \
     sqlitebackupprocessor.cpp \
     attribute.cpp \
-    attributeresolver.cpp
+    attributeresolver.cpp \
+    relations/hasmany.cpp \
+    relations/hasone.cpp \
+    relations/belongsto.cpp \
+    converter.cpp \
+    resolver.cpp
 
 windows|android: {
     DEFINES += SQLITE_OMIT_LOAD_EXTENSION SQLITE_OMIT_COMPLETE SQLITE_ENABLE_FTS3 SQLITE_ENABLE_FTS3_PARENTHESIS SQLITE_ENABLE_RTREE
