完成属性信息的落库存储逻辑

This commit is contained in:
duanshengchao 2025-04-01 14:37:41 +08:00
parent 57fecb7a30
commit f5aa607369
10 changed files with 194 additions and 34 deletions

View File

@ -62,6 +62,7 @@ public:
void refresh();
void insertRecord(int);
void removeRecord(int);
void submitChanges(); //提交更改(增、删、改)
//展示列控制
//void setVisibleColumns(const QStringList& columns);
@ -98,6 +99,7 @@ private:
void getDataTypes();
void loadPageData(); // 加载当前页数据
void updateTotalCount(); // 更新总记录数
QList<RowData> filterRowsByEditState(EditState);
QString m_connection;
QString m_tableName;

View File

@ -32,6 +32,7 @@ private slots:
void onBtnClicked_addRecord();
void onBtnClicked_removeRecord();
void onBtnClicked_submitChanges();
private:
int tabIndex(const QString&);

View File

@ -74,11 +74,11 @@ struct Model
struct Attribute
{
int id;
int id = -1;
QString name; //中文展示名称(filed:attribute_name)
QString type; //英文表示名称(filed:attribute),不可重名
int dataTypeID;
int dataLength; //filed:length_precision
int dataLength = -1; //filed:length_precision
QString defaultValue;
Attribute(int id, QString name, QString type, int dataTypeID, int dataLength, QString defaultVaule)

View File

@ -13,24 +13,28 @@ class SqlQueryExecutor : public QObject
public:
static SqlQueryExecutor& instance();
//单条SQL语句执行接口
QSqlQuery executeSQL(const QString& strConnectionName, const QString& strSQL, const QVariantHash& params = {}, bool useTranscation = false);
QSqlQuery executeSQL(const QString& connectionName, const QString& strSQL, const QVariantHash& params = {}, bool useTranscation = false);
/**
* @brief SQL语句执行接口
* @param sqlStatements SQL语句列表
* @param paramsList SQL语句一一对应
*/
QSqlQuery executeBatchSQL(const QString& strConnectionName, const QStringList& sqlStatements,
QSqlQuery executeBatchSQL(const QString& connectionName, const QStringList& sqlStatements,
const QList<QVariantHash>& paramsList = QList<QVariantHash>(), bool useTranscation = false);
QHash<QString, QString> getFiledType(const QString& strConnectionName, const QString& table, const QString& schema = "basic");
QHash<QString, QString> getFiledType(const QString& connectionName, const QString& table, const QString& schema = "basic");
//基于具体业务的查询接口-对外调用
const QVector<Model> getModels(const QString&);
//属性组相关
const QVector<AttributeGroup> getAttributeGroup(const QString&);
const QString getArributeGropuName(const QString&, int);
//模型相关
const QVector<Model> getModels(const QString&);
bool addModel(const QString&, Model&);
bool modelNameExistsInDB(const QString&, const QString&);
bool modelTypeExistsInDB(const QString&, const QString&);
bool removeModel(const QString&, int);
//属性相关
int getAttributeCount(const QString&, const QString&);
bool batchInserAttributis(const QString&, int, int, QList<Attribute>);
signals:
void errorOccurred(const QString& error);

View File

@ -328,6 +328,17 @@ void AttributeTableModel::updateTotalCount()
m_paginationInfo.totalEntries = SqlQueryExecutor::instance().getAttributeCount(m_connection, m_tableName);
}
QList<AttributeTableModel::RowData> AttributeTableModel::filterRowsByEditState(EditState state)
{
QList<RowData> result;
for(auto it = m_modifiedRows.begin(); it != m_modifiedRows.end(); it++)
{
if(it.value().state == state)
result.append(it.value());
}
return result;
}
void AttributeTableModel::setTable(const QString& tableName)
{
if(m_tableName == tableName)
@ -407,6 +418,42 @@ void AttributeTableModel::removeRecord(int row)
}
void AttributeTableModel::submitChanges()
{
QList<RowData> insertRows = filterRowsByEditState(New);
// QList<RowData> updateRows = filterRowsByEditState(Modified);
// QList<RowData> deleteRows = filterRowsByEditState(Deleted);
bool insertResult = false;
if(!insertRows.isEmpty())
{
QList<Attribute> insertAttributes;
for(const RowData& rowData : insertRows)
{
QString type = rowData.values.value(0).toString();
QString name = rowData.values.value(1).toString();
if(type.isEmpty() || name.isEmpty())
continue;
int dataTypeID = rowData.values.value(2).toInt();
int dataLength = -1;
if(rowData.values.value(3).isValid())
dataLength = rowData.values.value(3).toInt();
QString defaultValue = rowData.values.value(4).toString();
insertAttributes.emplace_back(-1, name, type, dataTypeID, dataLength, defaultValue);
}
insertResult = SqlQueryExecutor::instance().batchInserAttributis(m_connection, m_modelAttributeGroup.modelID, m_modelAttributeGroup.groupID, insertAttributes);
}
if( (!insertRows.isEmpty() && insertResult) )
{
m_modifiedRows.clear();
refresh();
}
else
emit showMessage(type_warning, QString::fromWCharArray(L"错误"), QString::fromWCharArray(L"数据提交失败,详情可查看日志文件"));
}
void AttributeTableModel::triggerSyncSignal()
{
emit syncDataStatus(m_modifiedRows.isEmpty(), m_paginationInfo);

View File

@ -67,7 +67,7 @@ void ConnectionDialog::initialize()
ui->connectionList->setColumnWidth(0, 120); //名称
//从配置文件初始化列表
QStringList connList = Settings::instance().getConnectionList();
for(QString connID : connList)
for(const QString& connID : connList)
{
DatabaseConfig config = Settings::instance().loadDatabaseConfig(connID);
appendConnListItem(connID, config.strConnectionName, config.strComment);

View File

@ -16,6 +16,7 @@ DatabaseBrowser::DatabaseBrowser(QWidget *parent)
connect(ui->btnAdd, &QPushButton::clicked, this, &DatabaseBrowser::onBtnClicked_addRecord);
connect(ui->btnRemove, &QPushButton::clicked, this, &DatabaseBrowser::onBtnClicked_removeRecord);
connect(ui->btnSave, &QPushButton::clicked, this, &DatabaseBrowser::onBtnClicked_submitChanges);
}
DatabaseBrowser::~DatabaseBrowser()
@ -132,6 +133,8 @@ void DatabaseBrowser::onBtnClicked_addRecord()
if(currentIndex.row() != -1)
row = currentIndex.row();*/
model->insertRecord(row);
ui->btnSave->setEnabled(true);
ui->btnCancle->setEnabled(true);
}
}
}
@ -149,11 +152,28 @@ void DatabaseBrowser::onBtnClicked_removeRecord()
QModelIndex currentIndex = view->currentIndex();
int row = currentIndex.row();
if( row != -1)
{
model->removeRecord(row);
ui->btnSave->setEnabled(true);
ui->btnCancle->setEnabled(true);
}
}
}
}
void DatabaseBrowser::onBtnClicked_submitChanges()
{
QWidget* widget = ui->tabWidget->currentWidget();
AttributeView* attributeView = qobject_cast<AttributeView*>(widget);
if(attributeView)
{
QTableView* view = attributeView->view();
AttributeTableModel* model = attributeView->model();
if(view && model)
model->submitChanges();
}
}
void DatabaseBrowser::onSyncDataStatus(bool hasModifiedData, const PaginationInfo& paginationInfo)
{
ui->btnSave->setEnabled(!hasModifiedData);

View File

@ -248,6 +248,7 @@ void DBStructureModel::refreshStructure_Connection(const QString& connection)
{
QString groupName = SqlQueryExecutor::instance().getArributeGropuName(connection, groupID);
DBStructureNode* groupNode = new DBStructureNode(GroupNode, groupName, modelNode);
groupNode->setData(Qt::UserRole + NodeDataRole::ID, groupID);
modelNode->appendChild(groupNode);
}
connNode->appendChild(modelNode);

View File

@ -200,9 +200,9 @@ void DBStructureView::showContextMenu(const QPoint& pos)
DBStructureModel* model = dynamic_cast<DBStructureModel*>(this->model());
if(model)
model->refreshStructure_Connection(connName);
});
})->setEnabled(isConnected);
menu.addSeparator();
menu.addAction(QString::fromWCharArray(L"添加模型"), [this]{emit actionTrigger_addModel();});
menu.addAction(QString::fromWCharArray(L"添加模型"), [this]{emit actionTrigger_addModel();})->setEnabled(isConnected);
/*menu.addAction(QString::fromWCharArray(L"导入数据"), []{});
menu.addAction(QString::fromWCharArray(L"导出数据"), []{});*/
QPoint originPoint = this->mapToGlobal(QPoint(0,0));

View File

@ -2,6 +2,7 @@
#include "sqlQueryExecutor.h"
#include "logger.h"
#include <QSqlDatabase>
#include <QDateTime>
SqlQueryExecutor& SqlQueryExecutor::instance()
{
@ -16,12 +17,12 @@ SqlQueryExecutor::~SqlQueryExecutor()
{}
//单条SQL语句执行接口
QSqlQuery SqlQueryExecutor::executeSQL(const QString& strConnectionName, const QString& strSQL, const QVariantHash& params, bool useTranscation)
QSqlQuery SqlQueryExecutor::executeSQL(const QString& connectionName, const QString& strSQL, const QVariantHash& params, bool useTranscation)
{
QSqlDatabase db = QSqlDatabase::database(strConnectionName);
QSqlDatabase db = QSqlDatabase::database(connectionName);
if(!db.isOpen())
{
LOG_ERROR("DB", QString("Database not open. connectionName: %1").arg(strConnectionName));
LOG_ERROR("DB", QString("Database not open. connectionName: %1").arg(connectionName));
throw DatabaseException(db.lastError());
}
@ -31,7 +32,7 @@ QSqlQuery SqlQueryExecutor::executeSQL(const QString& strConnectionName, const Q
{
if(!db.transaction())
{
LOG_ERROR("DB", QString("Start transaction failed. connectionName: %1. error: %2").arg(strConnectionName, db.lastError().databaseText()));
LOG_ERROR("DB", QString("Start transaction failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
throw DatabaseException(db.lastError());
}
transactionStarted = true;
@ -59,17 +60,18 @@ QSqlQuery SqlQueryExecutor::executeSQL(const QString& strConnectionName, const Q
if(transactionStarted && !db.commit())
{
throw DatabaseException(db.lastError());
LOG_ERROR("DB", QString("Commit transaction failed. connectionName: %1. error: %2").arg(strConnectionName, db.lastError().databaseText()));
LOG_ERROR("DB", QString("Commit transaction failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
}
}
catch (const DatabaseException& e)
{
LOG_INFO("DB", QString("DB Rollback"));
// 错误处理:回滚事务(如果已开启)
if(transactionStarted)
{
if(!db.rollback()) // 回滚失败时记录警告
{
LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(strConnectionName, db.lastError().databaseText()));
LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
}
}
@ -79,12 +81,12 @@ QSqlQuery SqlQueryExecutor::executeSQL(const QString& strConnectionName, const Q
return sqlQuery;
}
//多条批量SQL语句执行接口
QSqlQuery SqlQueryExecutor::executeBatchSQL(const QString& strConnectionName, const QStringList& sqlStatements, const QList<QVariantHash>& paramsList, bool useTranscation)
QSqlQuery SqlQueryExecutor::executeBatchSQL(const QString& connectionName, const QStringList& sqlStatements, const QList<QVariantHash>& paramsList, bool useTranscation)
{
QSqlDatabase db = QSqlDatabase::database(strConnectionName);
QSqlDatabase db = QSqlDatabase::database(connectionName);
if(!db.isOpen())
{
LOG_ERROR("DB", QString("Database not open. connectionName: %1").arg(strConnectionName));
LOG_ERROR("DB", QString("Database not open. connectionName: %1").arg(connectionName));
throw DatabaseException(db.lastError());
}
@ -101,7 +103,7 @@ QSqlQuery SqlQueryExecutor::executeBatchSQL(const QString& strConnectionName, co
{
if(!db.transaction())
{
LOG_ERROR("DB", QString("Start transaction failed. connectionName: %1. error: %2").arg(strConnectionName, db.lastError().databaseText()));
LOG_ERROR("DB", QString("Start transaction failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
throw DatabaseException(db.lastError());
}
transactionStarted = true;
@ -136,7 +138,7 @@ QSqlQuery SqlQueryExecutor::executeBatchSQL(const QString& strConnectionName, co
if(transactionStarted && !db.commit())
{
throw DatabaseException(db.lastError());
LOG_ERROR("DB", QString("Commit transaction failed. connectionName: %1. error: %2").arg(strConnectionName, db.lastError().databaseText()));
LOG_ERROR("DB", QString("Commit transaction failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
}
}
}
@ -145,9 +147,10 @@ QSqlQuery SqlQueryExecutor::executeBatchSQL(const QString& strConnectionName, co
// 错误处理:回滚事务(如果已开启)
if(transactionStarted)
{
LOG_INFO("DB", QString("DB Rollback"));
if(!db.rollback()) // 回滚失败时记录警告
{
LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(strConnectionName, db.lastError().databaseText()));
LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
}
}
@ -157,7 +160,7 @@ QSqlQuery SqlQueryExecutor::executeBatchSQL(const QString& strConnectionName, co
return lastQuery;
}
//获取表的字段类型信息目前只针对PostgerSQL
QHash<QString, QString> SqlQueryExecutor::getFiledType(const QString& strConnectionName, const QString& table, const QString& schema)
QHash<QString, QString> SqlQueryExecutor::getFiledType(const QString& connectionName, const QString& table, const QString& schema)
{
QHash<QString, QString> fieldTypes;
QString strSQL = QString(
@ -174,7 +177,7 @@ QHash<QString, QString> SqlQueryExecutor::getFiledType(const QString& strConnect
params.insert(":schema_name", schema);
try
{
QSqlQuery query = executeSQL(strConnectionName, strSQL, params);
QSqlQuery query = executeSQL(connectionName, strSQL, params);
while(query.next())
fieldTypes.insert(query.value(0).toString(), query.value(1).toString());
}
@ -187,20 +190,20 @@ QHash<QString, QString> SqlQueryExecutor::getFiledType(const QString& strConnect
}
//具体业务查询接口
const QVector<Model> SqlQueryExecutor::getModels(const QString& strConnectionName)
const QVector<Model> SqlQueryExecutor::getModels(const QString& connectionName)
{
QVector<Model> models;
QString strSQL = "SELECT id, model_type, model_name, remark FROM basic.model_type ORDER BY id ASC";
try
{
QSqlQuery query = executeSQL(strConnectionName, strSQL);
QSqlQuery query = executeSQL(connectionName, strSQL);
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(strConnectionName, id);
QVector<int> groups = getModelGroups(connectionName, id);
models.emplace_back(id, name, type, remark, groups);
}
}
@ -210,13 +213,13 @@ const QVector<Model> SqlQueryExecutor::getModels(const QString& strConnectionNam
}
return models; //编译器的RVO/NRVO会自动优化、避免临时拷贝
}
QVector<int> SqlQueryExecutor::getModelGroups(const QString& strConnectionName, int modelID)
QVector<int> SqlQueryExecutor::getModelGroups(const QString& connectionName, int modelID)
{
QVector<int> groups;
QString strSQL = "SELECT attribute_group_id FROM basic.model_group WHERE model_type_id = " + QString::number(modelID);
try
{
QSqlQuery query = executeSQL(strConnectionName, strSQL);
QSqlQuery query = executeSQL(connectionName, strSQL);
while(query.next())
{
groups.append(query.value(0).toInt());
@ -262,6 +265,7 @@ bool SqlQueryExecutor::addModel(const QString& connectionName, Model& model)
}
catch (const DatabaseException& e)
{
LOG_INFO("DB", QString("DB Rollback"));
if(!db.rollback()) // 回滚失败时记录警告
{
LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
@ -287,6 +291,7 @@ bool SqlQueryExecutor::addModel(const QString& connectionName, Model& model)
}
catch (const DatabaseException& e)
{
LOG_INFO("DB", QString("DB Rollback"));
if(!db.rollback()) // 回滚失败时记录警告
{
LOG_ERROR("DB", QString("Rollback failed. connectionName: %1. error: %2").arg(connectionName, db.lastError().databaseText()));
@ -353,13 +358,13 @@ bool SqlQueryExecutor::removeModel(const QString& connectionName, int modelID)
return true;
}
const QVector<AttributeGroup> SqlQueryExecutor::getAttributeGroup(const QString& strConnectionName)
const QVector<AttributeGroup> SqlQueryExecutor::getAttributeGroup(const QString& connectionName)
{
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(strConnectionName, strSQL);
QSqlQuery query = executeSQL(connectionName, strSQL);
while(query.next())
{
int id = query.value(0).toInt();
@ -377,7 +382,7 @@ const QVector<AttributeGroup> SqlQueryExecutor::getAttributeGroup(const QString&
return groupList;
}
const QString SqlQueryExecutor::getArributeGropuName(const QString& strConnectionName, int groupID)
const QString SqlQueryExecutor::getArributeGropuName(const QString& connectionName, int groupID)
{
QString name;
QString strSQL = "SELECT group_name FROM basic.attribute_group WHERE id = :id";
@ -385,7 +390,7 @@ const QString SqlQueryExecutor::getArributeGropuName(const QString& strConnectio
params.insert(":id", groupID);
try
{
QSqlQuery query = executeSQL(strConnectionName, strSQL, params);
QSqlQuery query = executeSQL(connectionName, strSQL, params);
if(query.next())
name = query.value(0).toString();
}
@ -398,13 +403,13 @@ const QString SqlQueryExecutor::getArributeGropuName(const QString& strConnectio
return name;
}
int SqlQueryExecutor::getAttributeCount(const QString& strConnectionName, const QString& tableName)
int SqlQueryExecutor::getAttributeCount(const QString& connectionName, const QString& tableName)
{
int count = 0;
QString strSQL = QString("SELECT COUNT(*) FROM %1").arg(tableName);
try
{
QSqlQuery query = executeSQL(strConnectionName, strSQL);
QSqlQuery query = executeSQL(connectionName, strSQL);
if(query.next())
count = query.value(0).toInt();
}
@ -415,3 +420,83 @@ int SqlQueryExecutor::getAttributeCount(const QString& strConnectionName, const
return count;
}
bool SqlQueryExecutor::batchInserAttributis(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;
for(const Attribute& atrribute : attributes)
{
qint64 attributeID = QDateTime::currentDateTime().toMSecsSinceEpoch();
//先向model_type中插入一条记录
QString strSQL = "INSERT INTO basic.attribute (attribute, attribute_name, data_type_id, length_precision, default_value) VALUES "
"(:type, :name, :dataType, :dataLength, :defaultValue)";
QVariantHash params;
params.insert(":type", atrribute.type);
params.insert(":name", atrribute.name);
params.insert(":dataType", atrribute.dataTypeID);
params.insert(":dataLength", atrribute.dataLength);
params.insert(":defaultValue", atrribute.defaultValue);
try
{
QSqlQuery query = executeSQL(connectionName, strSQL, params);
attributeID = query.lastInsertId().toInt(); //lasatInsertId()会返回最近插入行的自增id
}
catch (const DatabaseException& e)
{
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;
}
attributeIDList.append(attributeID);
}
//插入数据到关联表
QSqlQuery linkQuery(db);
QString strSQL = "INSERT INTO basic.model_attribute (model_type_id, attribute_group_id, attribute_id) VALUES (?, ?, ?)";
linkQuery.prepare(strSQL);
QVariantList modelIds, groupIds, attributeIds;
for(const qint64& attributeID : attributeIDList)
{
modelIds << modelID;
groupIds << attributeGroupID;
attributeIds << attributeID;
}
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"));
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;
}