PowerModeler/source/sqlQueryExecutor.cpp

894 lines
31 KiB
C++
Raw Normal View History

2025-03-14 16:06:20 +08:00
#include "global.h"
#include "sqlQueryExecutor.h"
#include "logger.h"
#include <QSqlDatabase>
#include <QDateTime>
2025-03-14 16:06:20 +08:00
SqlQueryExecutor& SqlQueryExecutor::instance()
{
//采用静态局部变量的方式,静态局部变量的初始化是在第一次访问时,以后的调用不会多次初始化,并且生命周期和程序一致
static SqlQueryExecutor instance;
return instance;
}
SqlQueryExecutor::SqlQueryExecutor()
{}
SqlQueryExecutor::~SqlQueryExecutor()
{}
2025-03-17 18:36:10 +08:00
//单条SQL语句执行接口
QSqlQuery SqlQueryExecutor::executeSQL(const QString& connectionName, const QString& strSQL, const QVariantHash& params, bool useTranscation)
2025-03-14 16:06:20 +08:00
{
QSqlDatabase db = QSqlDatabase::database(connectionName);
2025-03-14 16:06:20 +08:00
if(!db.isOpen())
{
LOG_ERROR("DB", QString("Database not open. connectionName: %1").arg(connectionName));
2025-03-14 16:06:20 +08:00
throw DatabaseException(db.lastError());
}
//事务
bool transactionStarted = false;
if(useTranscation)
{
if(!db.transaction())
{
LOG_ERROR("DB", QString("Start transaction failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
throw DatabaseException(db.lastError());
}
transactionStarted = true;
}
2025-03-14 16:06:20 +08:00
QSqlQuery sqlQuery(db);
try
2025-03-14 16:06:20 +08:00
{
if(!sqlQuery.prepare(strSQL))
{
LOG_ERROR("SQL", QString("SQL '%1' prepare fialed. error: %2").arg(strSQL, sqlQuery.lastError().databaseText()));
throw DatabaseException(db.lastError());
}
//绑定参数
for(auto it = params.constBegin(); it != params.constEnd(); it++)
{
sqlQuery.bindValue(it.key(), it.value());
}
if (!sqlQuery.exec())
{
LOG_ERROR("SQL", QString("SQL '%1' execute error: %2").arg(strSQL, sqlQuery.lastError().databaseText()));
throw DatabaseException(sqlQuery.lastError());
}
// 提交事务(如果已开启)
if(transactionStarted && !db.commit())
{
throw DatabaseException(db.lastError());
LOG_ERROR("DB", QString("Commit transaction failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
}
2025-03-14 16:06:20 +08:00
}
catch (const DatabaseException& e)
2025-03-14 16:06:20 +08:00
{
// 错误处理:回滚事务(如果已开启)
if(transactionStarted)
{
2025-04-01 16:45:30 +08:00
LOG_INFO("DB", QString("DB Rollback"));
if(!db.rollback()) // 回滚失败时记录警告
{
LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
}
}
throw; // 重新抛出异常
2025-03-14 16:06:20 +08:00
}
return sqlQuery;
}
2025-03-17 18:36:10 +08:00
//多条批量SQL语句执行接口
QSqlQuery SqlQueryExecutor::executeBatchSQL(const QString& connectionName, const QStringList& sqlStatements, const QList<QVariantHash>& paramsList, bool useTranscation)
2025-03-17 18:36:10 +08:00
{
QSqlDatabase db = QSqlDatabase::database(connectionName);
2025-03-17 18:36:10 +08:00
if(!db.isOpen())
{
LOG_ERROR("DB", QString("Database not open. connectionName: %1").arg(connectionName));
2025-03-17 18:36:10 +08:00
throw DatabaseException(db.lastError());
}
//参数数量校验
if(!paramsList.isEmpty() && sqlStatements.size() != paramsList.size())
{
LOG_ERROR("SQL", QString("SQL statement does not match the number of parameters"));
throw DatabaseException(QSqlError("SQL statement does not match the number of parameters"));
}
//事务
bool transactionStarted = false;
if(useTranscation)
{
if(!db.transaction())
{
LOG_ERROR("DB", QString("Start transaction failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
2025-03-17 18:36:10 +08:00
throw DatabaseException(db.lastError());
}
transactionStarted = true;
}
QSqlQuery lastQuery(db);
try
{
for(int i = 0; i < sqlStatements.size(); i++)
{
const QString& strSQL = sqlStatements.at(i);
const QVariantHash& params = paramsList.isEmpty() ? QVariantHash() : paramsList.at(i);
QSqlQuery sqlQuery(db);
if(!sqlQuery.prepare(strSQL))
{
LOG_ERROR("SQL", QString("SQL '%1' prepare fialed. error: %2").arg(strSQL, sqlQuery.lastError().databaseText()));
throw DatabaseException(db.lastError());
}
//绑定参数
for(auto it = params.constBegin(); it != params.constEnd(); it++)
{
sqlQuery.bindValue(it.key(), it.value());
}
if (!sqlQuery.exec())
{
LOG_ERROR("SQL", QString("SQL '%1' execute error: %2").arg(strSQL, sqlQuery.lastError().databaseText()));
throw DatabaseException(sqlQuery.lastError());
}
lastQuery = std::move(sqlQuery);
2025-04-17 15:34:43 +08:00
}
// 提交事务(如果已开启)
if(transactionStarted && !db.commit())
{
throw DatabaseException(db.lastError());
LOG_ERROR("DB", QString("Commit transaction failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
2025-03-17 18:36:10 +08:00
}
}
catch (const DatabaseException& e)
{
// 错误处理:回滚事务(如果已开启)
if(transactionStarted)
{
LOG_INFO("DB", QString("DB Rollback"));
2025-03-17 18:36:10 +08:00
if(!db.rollback()) // 回滚失败时记录警告
{
LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
2025-03-17 18:36:10 +08:00
}
}
throw; // 重新抛出异常
}
return lastQuery;
}
//获取表的字段类型信息目前只针对PostgerSQL
QHash<QString, QString> SqlQueryExecutor::getFiledType(const QString& connectionName, const QString& table, const QString& schema)
{
QHash<QString, QString> fieldTypes;
QString strSQL = QString(
"SELECT a.attname, pg_catalog.format_type(a.atttypid, a.atttypmod) "
"FROM pg_catalog.pg_attribute a "
"JOIN pg_catalog.pg_class c ON a.attrelid = c.oid "
"JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid "
"WHERE c.relname = LOWER(:table_name) "
"AND n.nspname = LOWER(:schema_name) "
"AND a.attnum > 0 AND NOT a.attisdropped;"
);
QVariantHash params;
params.insert(":table_name", table);
params.insert(":schema_name", schema);
try
{
QSqlQuery query = executeSQL(connectionName, strSQL, params);
while(query.next())
fieldTypes.insert(query.value(0).toString(), query.value(1).toString());
}
catch (const DatabaseException& e)
{
LOG_ERROR("SQL", QString::fromWCharArray(L"获取属性原始数据类型失败"));
}
return fieldTypes;
}
2025-03-14 16:06:20 +08:00
//具体业务查询接口
const QVector<Model> SqlQueryExecutor::getModels(const QString& connectionName)
2025-03-14 16:06:20 +08:00
{
QVector<Model> models;
QString strSQL = "SELECT id, model_type, model_name, remark FROM basic.model_type ORDER BY id ASC";
try
{
QSqlQuery query = executeSQL(connectionName, strSQL);
2025-03-14 16:06:20 +08:00
while(query.next())
{
int id = query.value(0).toInt();
QString type = query.value(1).toString();
QString name = query.value(2).toString();
QString remark = query.value(3).toString();
QVector<int> groups = getModelGroups(connectionName, id);
2025-03-14 16:06:20 +08:00
models.emplace_back(id, name, type, remark, groups);
}
}
catch (const DatabaseException& e)
{
emit errorOccurred(QString::fromWCharArray(L"获取模型信息失败,详情可见日志文件"));
}
return models; //编译器的RVO/NRVO会自动优化、避免临时拷贝
}
QVector<int> SqlQueryExecutor::getModelGroups(const QString& connectionName, int modelID)
2025-03-14 16:06:20 +08:00
{
QVector<int> groups;
QString strSQL = "SELECT attribute_group_id FROM basic.model_group WHERE model_type_id = " + QString::number(modelID);
2025-03-14 16:06:20 +08:00
try
{
QSqlQuery query = executeSQL(connectionName, strSQL);
2025-03-14 16:06:20 +08:00
while(query.next())
{
groups.append(query.value(0).toInt());
}
}
catch (const DatabaseException& e)
{
LOG_ERROR("SQL", QString::fromWCharArray(L"获取模型所含属性组名称失败id:%1").arg(QString::number(modelID)));
return groups;
}
return groups;
}
bool SqlQueryExecutor::addModel(const QString& connectionName, Model& model)
{
2025-03-17 18:36:10 +08:00
//属于批量操作需要开启事务因为后续插入映射表时需要先插入进model_type记录的自增id所以无法在一个接口函数中执行所以事务放在在接口外部执行
QSqlDatabase db = QSqlDatabase::database(connectionName);
if(!db.isOpen())
{
LOG_ERROR("DB", QString("Database not open. connectionName: %1").arg(connectionName));
return false;
}
if(!db.transaction())
{
LOG_ERROR("DB", QString("Start transaction failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
return false;
}
2025-03-14 16:06:20 +08:00
int modelID = -1;
//先向model_type中插入一条记录
QString strSQL = "INSERT INTO basic.model_type (model_type, model_name, remark) VALUES "
2025-03-14 16:06:20 +08:00
"(:type, :name, :remark)";
QVariantHash params;
params.insert(":type", model.type);
params.insert(":name", model.name);
params.insert(":remark", model.remark);
2025-03-14 16:06:20 +08:00
try
{
QSqlQuery query = executeSQL(connectionName, strSQL, params);
2025-03-14 16:06:20 +08:00
modelID = query.lastInsertId().toInt(); //lasatInsertId()会返回最近插入行的自增id
model.id = modelID;
}
catch (const DatabaseException& e)
{
LOG_INFO("DB", QString("DB Rollback"));
2025-03-17 18:36:10 +08:00
if(!db.rollback()) // 回滚失败时记录警告
{
LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
}
2025-03-14 16:06:20 +08:00
return false;
}
2025-03-17 18:36:10 +08:00
//然后向model_group中插入记录采用批量接口
2025-04-18 18:44:26 +08:00
/*QStringList sqlStatements;
2025-03-17 18:36:10 +08:00
QList<QVariantHash> paramsList;
2025-03-14 16:06:20 +08:00
for(int groupID : model.groups)
{
2025-03-17 18:36:10 +08:00
sqlStatements << "INSERT INTO basic.model_group (model_type_id, attribute_group_id) VALUES "
"(:modelID, :groupID)";
2025-03-14 16:06:20 +08:00
params.clear();
params.insert(":modelID", modelID);
params.insert(":groupID", groupID);
2025-03-17 18:36:10 +08:00
paramsList << params;
}
try
{
executeBatchSQL(connectionName, sqlStatements, paramsList);
}
catch (const DatabaseException& e)
2025-04-18 18:44:26 +08:00
{
LOG_INFO("DB", QString("DB Rollback"));
if(!db.rollback()) // 回滚失败时记录警告
{
LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
}
return false;
}*/
QSqlQuery query(db);
strSQL = "INSERT INTO basic.model_group (model_type_id, attribute_group_id) VALUES (?, ?)";
if(!query.prepare(strSQL))
{
LOG_ERROR("SQL", QString("SQL '%1' prepare fialed. error: %2").arg(strSQL, query.lastError().databaseText()));
if(!db.rollback()) // 回滚
{
LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
}
return false;
}
QVariantList modelIds, groupIds;
for(int groupID : model.groups)
{
modelIds << modelID;
groupIds << groupID;
}
query.addBindValue(modelIds);
query.addBindValue(groupIds);
if( !query.execBatch() )
2025-03-17 18:36:10 +08:00
{
LOG_INFO("DB", QString("DB Rollback"));
2025-03-17 18:36:10 +08:00
if(!db.rollback()) // 回滚失败时记录警告
2025-03-14 16:06:20 +08:00
{
2025-03-17 18:36:10 +08:00
LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
2025-03-14 16:06:20 +08:00
}
2025-03-17 18:36:10 +08:00
return false;
}
if(!db.commit()) // 提交
{
LOG_ERROR("DB", QString("Commit transaction failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
return false;
2025-03-14 16:06:20 +08:00
}
return true;
}
bool SqlQueryExecutor::modelNameExistsInDB(const QString& connectionName, const QString& name)
{
bool exists = false;
QString strSQL = "SELECT id FROM basic.model_type WHERE model_name = \'" + name + "\'";
try
{
QSqlQuery query = executeSQL(connectionName, strSQL);
if(query.next())
exists = true;
}
catch (const DatabaseException& e)
{
exists = true;
}
return exists;
}
bool SqlQueryExecutor::modelTypeExistsInDB(const QString& connectionName, const QString& type)
{
bool exists = false;
QString strSQL = "SELECT id FROM basic.model_type WHERE model_type = \'" + type + "\'";
try
{
QSqlQuery query = executeSQL(connectionName, strSQL);
if(query.next())
exists = true;
}
catch (const DatabaseException& e)
{
exists = true;
}
return exists;
}
bool SqlQueryExecutor::removeModel(const QString& connectionName, int modelID)
2025-03-14 18:08:43 +08:00
{
2025-04-17 15:34:43 +08:00
//数据库中有级联删除只需要从model_type中删除即可
QString strSQL = "DELETE FROM basic.model_type WHERE id = :id"/* + QString::number(modelID)*/;
QVariantHash params;
params.insert(":id", modelID);
try
{
executeSQL(connectionName, strSQL, params, true);
}
catch (const DatabaseException& e)
{
return false;
}
return true;
2025-03-14 18:08:43 +08:00
}
2025-03-14 16:06:20 +08:00
2025-04-18 18:44:26 +08:00
bool SqlQueryExecutor::addModleGrpus(const QString& connectionName, int modelID, QVector<int> groups)
{
//属于批量操作,需要开启事务
QSqlDatabase db = QSqlDatabase::database(connectionName);
if(!db.isOpen())
{
LOG_ERROR("DB", QString("Database not open. connectionName: %1").arg(connectionName));
return false;
}
if(!db.transaction())
{
LOG_ERROR("DB", QString("Start transaction failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
return false;
}
QSqlQuery query(db);
QString strSQL = "INSERT INTO basic.model_group (model_type_id, attribute_group_id) VALUES (?, ?)";
if(!query.prepare(strSQL))
{
LOG_ERROR("SQL", QString("SQL '%1' prepare fialed. error: %2").arg(strSQL, query.lastError().databaseText()));
if(!db.rollback()) // 回滚
{
LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
}
return false;
}
QVariantList modelIds, groupIds;
for(int groupID : groups)
{
modelIds << modelID;
groupIds << groupID;
}
query.addBindValue(modelIds);
query.addBindValue(groupIds);
if( !query.execBatch() )
{
LOG_ERROR("SQL", QString("SQL '%1' execBatch error: %2").arg(strSQL, query.lastError().databaseText()));
LOG_INFO("DB", QString("DB Rollback"));
if(!db.rollback()) // 回滚
{
LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
}
return false;
}
if(!db.commit()) // 提交
{
LOG_ERROR("DB", QString("Commit transaction failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
return false;
}
return true;
}
const QVector<AttributeGroup> SqlQueryExecutor::getAttributeGroup(const QString& connectionName)
2025-03-14 16:06:20 +08:00
{
QVector<AttributeGroup> groupList;
QString strSQL = "SELECT id, group_type, group_name, remark, is_public FROM basic.attribute_group ORDER BY id ASC";
try
{
QSqlQuery query = executeSQL(connectionName, strSQL);
2025-03-14 16:06:20 +08:00
while(query.next())
{
int id = query.value(0).toInt();
QString type = query.value(1).toString();
QString name = query.value(2).toString();
QString remark = query.value(3).toString();
bool isPublic = query.value(4).toBool();
groupList.emplace_back(id,name,type,remark,isPublic); //直接调用构造函数,避免拷贝
}
}
catch (const DatabaseException& e)
{
emit errorOccurred(QString::fromWCharArray(L"获取属性组别信息失败,详情可见日志文件"));
}
return groupList;
}
const QString SqlQueryExecutor::getAttributeGroupName(const QString& connectionName, int groupID)
2025-03-14 16:06:20 +08:00
{
QString name = "";
QString strSQL = "SELECT group_name FROM basic.attribute_group WHERE id = :id";
QVariantHash params;
params.insert(":id", groupID);
2025-03-14 16:06:20 +08:00
try
{
QSqlQuery query = executeSQL(connectionName, strSQL, params);
2025-03-14 16:06:20 +08:00
if(query.next())
name = query.value(0).toString();
}
catch (const DatabaseException& e)
{
LOG_ERROR("SQL", QString::fromWCharArray(L"获取属性组名称失败id:%1").arg(QString::number(groupID)));
}
return name;
}
const AttributeGroup SqlQueryExecutor::getAttributeGroupData(const QString& connectionName, int groupID)
{
AttributeGroup group;
QString strSQL = "SELECT group_type, group_name, remark, is_public FROM basic.attribute_group WHERE id = :id";
QVariantHash params;
params.insert(":id", groupID);
try
{
QSqlQuery query = executeSQL(connectionName, strSQL, params);
if(query.next())
{
QString type = query.value(0).toString();
QString name = query.value(1).toString();
QString remark = query.value(2).toString();
bool isPublic = query.value(3).toBool();
return AttributeGroup(groupID,name,type,remark,isPublic);
}
}
catch (const DatabaseException& e)
{
LOG_ERROR("SQL", QString::fromWCharArray(L"获取属性组信息失败id:%1").arg(QString::number(groupID)));
}
return group;
}
bool SqlQueryExecutor::isPublicAttributeGroup(const QString& connectionName, int groupID)
{
bool isPublic = false;
QString strSQL = "SELECT is_public FROM basic.attribute_group WHERE id = :id";
QVariantHash params;
params.insert(":id", groupID);
try
{
QSqlQuery query = executeSQL(connectionName, strSQL, params);
if(query.next())
isPublic = query.value(0).toBool();
}
catch (const DatabaseException& e)
{
LOG_ERROR("SQL", QString::fromWCharArray(L"获取属性组类型失败id:%1").arg(QString::number(groupID)));
}
return isPublic;
}
2025-04-17 15:34:43 +08:00
bool SqlQueryExecutor::removeAttributeGroup(const QString& connectionName, int modelID, int groupID)
{
//从model_attribute和model_group两个map表中对相关记录进行删除(暂时不做属性本体的删除)
QStringList sqlStatements;
QList<QVariantHash> paramsList;
sqlStatements << "DELETE FROM basic.model_attribute WHERE model_type_id = :modelID AND attribute_group_id = :groupID";
QVariantHash params;
params.insert(":modelID", modelID);
params.insert(":groupID", groupID);
paramsList << params;
sqlStatements << "DELETE FROM basic.model_group WHERE model_type_id = :modelID AND attribute_group_id = :groupID";
params.clear();
params.insert(":modelID", modelID);
params.insert(":groupID", groupID);
paramsList << params;
try
{
executeBatchSQL(connectionName, sqlStatements, paramsList, true);
}
catch (const DatabaseException& e)
{
LOG_ERROR("SQL", QString::fromWCharArray(L"删除属性组失败model_type_id:%1attribute_group_id:%2").arg(modelID, groupID));
return false;
}
return true;
}
2025-04-01 16:45:30 +08:00
int SqlQueryExecutor::getAttributeCount(const QString& connectionName, int modelID, int groupID)
{
int count = 0;
2025-04-01 16:45:30 +08:00
QString strSQL = QString("SELECT COUNT(*) FROM basic.model_attribute WHERE model_type_id = %1 AND attribute_group_id = %2").arg(modelID).arg(groupID);
try
{
QSqlQuery query = executeSQL(connectionName, strSQL);
if(query.next())
count = query.value(0).toInt();
}
catch (const DatabaseException& e)
{
LOG_ERROR("SQL", QString::fromWCharArray(L"获取属性数量失败"));
}
return count;
}
2025-04-11 17:14:17 +08:00
int SqlQueryExecutor::getAllAttributeCount(const QString& connectionName)
{
int count = 0;
QString strSQL = QString("SELECT COUNT(*) FROM basic.attribute");
try
{
QSqlQuery query = executeSQL(connectionName, strSQL);
if(query.next())
count = query.value(0).toInt();
}
catch (const DatabaseException& e)
{
LOG_ERROR("SQL", QString::fromWCharArray(L"获取属性数量失败"));
}
return count;
}
bool SqlQueryExecutor::getAttributeInfo(const QString& connectionName, const QString& columns, Attribute& attribute)
2025-04-01 16:45:30 +08:00
{
QString strSQL = QString("SELECT %1 FROM basic.attribute WHERE id = %2").arg(columns).arg(attribute.id);
try
{
QSqlQuery query = executeSQL(connectionName, strSQL);
if(query.next())
{
attribute.type = query.value(0).toString();
attribute.name = query.value(1).toString();
attribute.dataTypeID = query.value(2).toInt();
attribute.dataLength = query.value(3).toInt();
attribute.defaultValue = query.value(4).toString();
2025-04-27 16:24:13 +08:00
attribute.isVisible = query.value(5).toInt();
2025-04-01 16:45:30 +08:00
}
else
return false;
}
catch (const DatabaseException& e)
{
LOG_ERROR("SQL", QString::fromWCharArray(L"获取属性数量失败"));
return false;
}
return true;
}
2025-04-11 17:14:17 +08:00
int SqlQueryExecutor::attributeTypeExistsInDB(const QString& connectionName, const QString& type)
{
2025-04-11 17:14:17 +08:00
int id = -1;
QString strSQL = "SELECT id FROM basic.attribute WHERE attribute = \'" + type + "\'";
try
{
QSqlQuery query = executeSQL(connectionName, strSQL);
if(query.next())
2025-04-11 17:14:17 +08:00
id = query.value(0).toInt();
}
catch (const DatabaseException& e)
{
2025-04-11 17:14:17 +08:00
id = -1;
}
2025-04-11 17:14:17 +08:00
return id;
}
bool SqlQueryExecutor::attributeTypeUseByModelGroup(const QString& connectionName, int attributeID, int modelID, int groupID)
{
QString strSQL = "SELECT id FROM basic.model_attribute WHERE model_type_id = :modelID AND attribute_group_id = :groupID AND attribute_id = :attributeID";
QVariantHash params;
params.insert(":modelID", modelID);
params.insert(":groupID", groupID);
params.insert(":attributeID", attributeID);
try
{
QSqlQuery query = executeSQL(connectionName, strSQL, params);
if(query.next())
return true;
}
catch (const DatabaseException& e)
{
return false;
}
return false;
}
2025-04-02 10:44:52 +08:00
bool SqlQueryExecutor::batchInsertAttributes(const QString& connectionName, int modelID, int attributeGroupID, QList<Attribute> attributes)
{
//属于批量操作,需要开启事务
QSqlDatabase db = QSqlDatabase::database(connectionName);
if(!db.isOpen())
{
LOG_ERROR("DB", QString("Database not open. connectionName: %1").arg(connectionName));
return false;
}
if(!db.transaction())
{
LOG_ERROR("DB", QString("Start transaction failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
return false;
}
//先插入进属性表attribute因为要获取插入后的自增id所以采用逐条插入的方法
QList<qint64> attributeIDList;
2025-04-02 14:58:42 +08:00
for(const Attribute& attribute : attributes)
{
2025-04-11 17:14:17 +08:00
if(attribute.id != -1) //新建条目是通过选择已有的记录完成,此类不再做重复插入
{
attributeIDList.append(attribute.id);
continue;
}
qint64 attributeID = QDateTime::currentDateTime().toMSecsSinceEpoch();
//先向model_type中插入一条记录
2025-04-27 16:24:13 +08:00
QString strSQL = "INSERT INTO basic.attribute (attribute, attribute_name, data_type_id, length_precision, default_value, is_visible) VALUES "
"(:type, :name, :dataType, :dataLength, :defaultValue, :isVisible)";
QVariantHash params;
2025-04-02 14:58:42 +08:00
params.insert(":type", attribute.type);
params.insert(":name", attribute.name);
params.insert(":dataType", attribute.dataTypeID);
params.insert(":dataLength", attribute.dataLength);
params.insert(":defaultValue", attribute.defaultValue);
2025-04-27 16:24:13 +08:00
params.insert(":isVisible", attribute.isVisible);
try
{
QSqlQuery query = executeSQL(connectionName, strSQL, params);
attributeID = query.lastInsertId().toInt(); //lasatInsertId()会返回最近插入行的自增id
}
catch (const DatabaseException& e)
{
LOG_INFO("DB", QString("DB Rollback"));
2025-04-02 10:44:52 +08:00
if(!db.rollback()) // 回滚
{
LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
}
return false;
}
attributeIDList.append(attributeID);
}
//插入数据到关联表
QSqlQuery linkQuery(db);
QString strSQL = "";
bool isPublicGroup = isPublicAttributeGroup(connectionName, attributeGroupID);
if(isPublicGroup)
strSQL = "INSERT INTO basic.model_attribute_public (attribute_group_id, attribute_id) VALUES (?, ?)";
else
strSQL = "INSERT INTO basic.model_attribute (model_type_id, attribute_group_id, attribute_id) VALUES (?, ?, ?)";
2025-04-02 10:44:52 +08:00
if(!linkQuery.prepare(strSQL))
{
LOG_ERROR("SQL", QString("SQL '%1' prepare fialed. error: %2").arg(strSQL, linkQuery.lastError().databaseText()));
if(!db.rollback()) // 回滚
{
LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
}
return false;
}
QVariantList modelIds, groupIds, attributeIds;
for(const qint64& attributeID : attributeIDList)
{
if(!isPublicGroup)
modelIds << modelID;
groupIds << attributeGroupID;
attributeIds << attributeID;
}
if(!isPublicGroup)
linkQuery.addBindValue(modelIds);
linkQuery.addBindValue(groupIds);
linkQuery.addBindValue(attributeIds);
if( !linkQuery.execBatch() )
{
LOG_ERROR("SQL", QString("SQL '%1' execBatch error: %2").arg(strSQL, linkQuery.lastError().databaseText()));
LOG_INFO("DB", QString("DB Rollback"));
2025-04-02 10:44:52 +08:00
if(!db.rollback()) // 回滚
{
LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
}
return false;
}
if(!db.commit()) // 提交
{
LOG_ERROR("DB", QString("Commit transaction failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
return false;
}
return true;
}
bool SqlQueryExecutor::batchDeleteAttributes(const QString& connectionName, int modelID, int attributeGroupID, QList<int> attributes)
{
//属于批量操作,需要开启事务
QSqlDatabase db = QSqlDatabase::database(connectionName);
if(!db.isOpen())
{
LOG_ERROR("DB", QString("Database not open. connectionName: %1").arg(connectionName));
return false;
}
if(!db.transaction())
{
LOG_ERROR("DB", QString("Start transaction failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
return false;
}
QSqlQuery query(db);
QString strSQL = "";
bool isPublicGroup = isPublicAttributeGroup(connectionName, attributeGroupID);
if(isPublicGroup)
strSQL = "DELETE FROM basic.model_attribute_public WHERE attribute_group_id = ? AND attribute_id = ?";
else
strSQL = "DELETE FROM basic.model_attribute WHERE model_type_id = ? AND attribute_group_id = ? AND attribute_id = ?";
2025-04-02 10:44:52 +08:00
if(!query.prepare(strSQL))
{
LOG_ERROR("SQL", QString("SQL '%1' prepare fialed. error: %2").arg(strSQL, query.lastError().databaseText()));
if(!db.rollback()) // 回滚
{
LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
}
return false;
}
QVariantList modelIds, groupIds, attributeIds;
for(const int& attributeID : attributes)
{
if(!isPublicGroup)
modelIds << modelID;
2025-04-02 10:44:52 +08:00
groupIds << attributeGroupID;
attributeIds << attributeID;
}
if(!isPublicGroup)
query.addBindValue(modelIds);
2025-04-02 10:44:52 +08:00
query.addBindValue(groupIds);
query.addBindValue(attributeIds);
if( !query.execBatch() )
{
LOG_ERROR("SQL", QString("SQL '%1' execBatch error: %2").arg(strSQL, query.lastError().databaseText()));
LOG_INFO("DB", QString("DB Rollback"));
if(!db.rollback()) // 回滚
{
LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
}
return false;
}
if(!db.commit()) // 提交
{
LOG_ERROR("DB", QString("Commit transaction failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
return false;
}
return true;
}
2025-04-02 14:58:42 +08:00
bool SqlQueryExecutor::batchUpdateAttributes(const QString& connectionName, int modelID, int attributeGroupID, QList<Attribute> attributes)
{
//属于批量操作,需要开启事务
QSqlDatabase db = QSqlDatabase::database(connectionName);
if(!db.isOpen())
{
LOG_ERROR("DB", QString("Database not open. connectionName: %1").arg(connectionName));
return false;
}
if(!db.transaction())
{
LOG_ERROR("DB", QString("Start transaction failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
return false;
}
QSqlQuery query(db);
2025-04-27 16:24:13 +08:00
QString strSQL = "UPDATE basic.attribute SET attribute = ?, attribute_name = ?, data_type_id = ?, length_precision = ?, default_value = ?, is_visible = ? WHERE id = ?";
2025-04-02 14:58:42 +08:00
if(!query.prepare(strSQL))
{
LOG_ERROR("SQL", QString("SQL '%1' prepare fialed. error: %2").arg(strSQL, query.lastError().databaseText()));
if(!db.rollback()) // 回滚
{
LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
}
return false;
}
2025-04-27 16:24:13 +08:00
QVariantList types, names, dataTypes, lengths, defaults, isVisibles, ids;
2025-04-02 14:58:42 +08:00
for(const Attribute& attribute : attributes)
{
types << attribute.type;
names << attribute.name;
dataTypes << attribute.dataTypeID;
lengths << attribute.dataLength;
defaults << attribute.defaultValue;
2025-04-27 16:24:13 +08:00
isVisibles << attribute.isVisible;
2025-04-02 14:58:42 +08:00
ids << attribute.id;
}
query.addBindValue(types);
query.addBindValue(names);
query.addBindValue(dataTypes);
query.addBindValue(lengths);
query.addBindValue(defaults);
2025-04-27 16:24:13 +08:00
query.addBindValue(isVisibles);
2025-04-02 14:58:42 +08:00
query.addBindValue(ids);
if( !query.execBatch() )
{
LOG_ERROR("SQL", QString("SQL '%1' execBatch error: %2").arg(strSQL, query.lastError().databaseText()));
LOG_INFO("DB", QString("DB Rollback"));
if(!db.rollback()) // 回滚
{
LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
}
return false;
}
if(!db.commit()) // 提交
{
LOG_ERROR("DB", QString("Commit transaction failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
return false;
}
return true;
}