Revision c88e17d1
Von Christian Ehringfeld vor fast 8 Jahren hinzugefügt
| src/converter.cpp | ||
|---|---|---|
|
#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;
|
||
|
}
|
||
| src/converter.h | ||
|---|---|---|
|
#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
|
||
| src/entitymanager.cpp | ||
|---|---|---|
|
#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;
|
||
|
|
||
| ... | ... | |
|
|
||
|
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) {
|
||
| ... | ... | |
|
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;
|
||
|
}
|
||
| ... | ... | |
|
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());
|
||
|
}
|
||
|
}
|
||
| ... | ... | |
|
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());
|
||
| ... | ... | |
|
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);
|
||
| ... | ... | |
|
}
|
||
|
}
|
||
|
|
||
|
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[";
|
||
| ... | ... | |
|
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)) {
|
||
| ... | ... | |
|
}
|
||
|
}
|
||
|
|
||
|
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) {
|
||
| ... | ... | |
|
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,
|
||
| ... | ... | |
|
&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);
|
||
|
}
|
||
| ... | ... | |
|
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(
|
||
| ... | ... | |
|
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,
|
||
| ... | ... | |
|
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);
|
||
| ... | ... | |
|
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;
|
||
|
}
|
||
| src/entitymanager.h | ||
|---|---|---|
|
#include "querybuilder.h"
|
||
|
#include "validators/errormsg.h"
|
||
|
#include "attribute.h"
|
||
|
#include "resolver.h"
|
||
|
#include "converter.h"
|
||
|
|
||
|
namespace CuteEntityManager {
|
||
|
#ifdef QT_DEBUG
|
||
|
#include <QDebug>
|
||
| ... | ... | |
|
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
|
||
| ... | ... | |
|
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>>();
|
||
|
}
|
||
| ... | ... | |
|
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);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
| ... | ... | |
|
(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>>();
|
||
|
}
|
||
| ... | ... | |
|
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>>();
|
||
|
}
|
||
| ... | ... | |
|
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>>();
|
||
|
}
|
||
| ... | ... | |
|
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,
|
||
| ... | ... | |
|
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);
|
||
| ... | ... | |
|
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]
|
||
| ... | ... | |
|
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
|
||
| src/querybuilder.h | ||
|---|---|---|
|
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();
|
||
| src/relations/belongsto.cpp | ||
|---|---|---|
|
#include "belongsto.h"
|
||
|
using namespace CuteEntityManager;
|
||
|
|
||
|
BelongsTo::BelongsTo()
|
||
|
{
|
||
|
|
||
|
}
|
||
| src/relations/belongsto.h | ||
|---|---|---|
|
#ifndef BELONGSTO_H
|
||
|
#define BELONGSTO_H
|
||
|
namespace CuteEntityManager {
|
||
|
|
||
|
class BelongsTo
|
||
|
{
|
||
|
public:
|
||
|
BelongsTo();
|
||
|
};
|
||
|
}
|
||
|
#endif // BELONGSTO_H
|
||
| src/relations/hasmany.cpp | ||
|---|---|---|
|
#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());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
| src/relations/hasmany.h | ||
|---|---|---|
|
#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
|
||
| src/relations/hasone.cpp | ||
|---|---|---|
|
#include "hasone.h"
|
||
|
using namespace CuteEntityManager;
|
||
|
|
||
|
HasOne::HasOne()
|
||
|
{
|
||
|
|
||
|
}
|
||
| src/relations/hasone.h | ||
|---|---|---|
|
#ifndef HASONE_H
|
||
|
#define HASONE_H
|
||
|
namespace CuteEntityManager {
|
||
|
|
||
|
class HasOne
|
||
|
{
|
||
|
public:
|
||
|
HasOne();
|
||
|
};
|
||
|
}
|
||
|
#endif // HASONE_H
|
||
| src/resolver.cpp | ||
|---|---|---|
|
#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;
|
||
|
}
|
||
| src/resolver.h | ||
|---|---|---|
|
#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
|
||
| src/src.pro | ||
|---|---|---|
|
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 \
|
||
| ... | ... | |
|
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
|
||
Auch abrufbar als: Unified diff
n-m refactoring