QSqlQueryModel 深度讲解

        QSqlQueryModel 是 Qt 框架中提供的一个高级数据库模型类,它继承自 QAbstractTableModel,专门用于执行 SQL 查询并在 Qt 的视图类(如 QTableView、QListView)中显示结果。

一、核心特点

  1. 只读性:默认是只读的,不能直接修改数据

  2. 轻量级:比 QSqlTableModel 更轻量,适合简单查询展示

  3. 灵活性:可以执行任意 SQL 查询

  4. 视图集成:与 Qt 的视图组件无缝集成

二、基本用法示例

#include <QApplication>
#include <QSqlDatabase>
#include <QSqlQueryModel>
#include <QTableView>
#include <QSqlQuery>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    
    // 建立数据库连接
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName(":memory:"); // 内存数据库
    if (!db.open()) {
        qDebug() << "无法打开数据库";
        return 1;
    }
    
    // 创建表并插入示例数据
    QSqlQuery query;
    query.exec("CREATE TABLE employees (id INT, name TEXT, salary REAL)");
    query.exec("INSERT INTO employees VALUES (1, '张三', 5000.0)");
    query.exec("INSERT INTO employees VALUES (2, '李四', 6000.0)");
    
    // 创建模型并设置查询
    QSqlQueryModel model;
    model.setQuery("SELECT * FROM employees");
    
    // 创建视图并设置模型
    QTableView view;
    view.setModel(&model);
    view.show();
    
    return app.exec();
}

三、常用方法详解

1. 设置查询

// 直接设置SQL语句
model.setQuery("SELECT name, salary FROM employees WHERE salary > 5500");

// 使用预编译查询
QSqlQuery preparedQuery;
preparedQuery.prepare("SELECT * FROM employees WHERE id = ?");
preparedQuery.addBindValue(employeeId);
model.setQuery(preparedQuery);

2. 访问数据

// 获取行数
int rowCount = model.rowCount();

// 获取列数
int columnCount = model.columnCount();

// 获取特定单元格数据
QString name = model.data(model.index(0, 1)).toString(); // 第一行第二列

3. 自定义显示

// 设置水平头标签
model.setHeaderData(0, Qt::Horizontal, tr("ID"));
model.setHeaderData(1, Qt::Horizontal, tr("姓名"));
model.setHeaderData(2, Qt::Horizontal, tr("薪水"));

// 自定义数据展示格式
QVariant QSqlQueryModel::data(const QModelIndex &index, int role) const
{
    if (role == Qt::DisplayRole && index.column() == 2) {
        // 对薪水列进行格式化
        return QString("¥%1").arg(QSqlQueryModel::data(index, role).toDouble());
    }
    return QSqlQueryModel::data(index, role);
}

四、高级用法

1. 自定义模型(使其可编辑)

class EditableSqlModel : public QSqlQueryModel
{
public:
    Qt::ItemFlags flags(const QModelIndex &index) const override
    {
        Qt::ItemFlags flags = QSqlQueryModel::flags(index);
        if (index.column() == 1 || index.column() == 2) // 使姓名和薪水可编辑
            flags |= Qt::ItemIsEditable;
        return flags;
    }
    
    bool setData(const QModelIndex &index, const QVariant &value, int role) override
    {
        if (index.column() < 1 || index.column() > 2)
            return false;
            
        QModelIndex primaryKeyIndex = QSqlQueryModel::index(index.row(), 0);
        int id = data(primaryKeyIndex).toInt();
        
        QString column;
        if (index.column() == 1) column = "name";
        else if (index.column() == 2) column = "salary";
        
        QSqlQuery query;
        query.prepare(QString("UPDATE employees SET %1 = ? WHERE id = ?").arg(column));
        query.addBindValue(value);
        query.addBindValue(id);
        
        if (!query.exec())
            return false;
            
        refresh(); // 刷新数据
        return true;
    }
    
    void refresh()
    {
        setQuery("SELECT * FROM employees");
    }
};

2. 性能优化(大数据量)

// 使用批量获取数据
model.setQuery("SELECT * FROM large_table");
model.fetchMore(); // 当需要更多数据时

// 重写canFetchMore和fetchMore方法
bool canFetchMore(const QModelIndex &parent) const override
{
    return currentRowCount < totalRowCount;
}

void fetchMore(const QModelIndex &parent) override
{
    int remaining = totalRowCount - currentRowCount;
    int itemsToFetch = qMin(100, remaining); // 每次获取100条
    
    // 执行查询获取更多数据...
    currentRowCount += itemsToFetch;
}

五、实际应用场景示例

1. 数据报表展示

// 复杂SQL查询生成报表
model.setQuery("SELECT department, COUNT(*) as count, AVG(salary) as avg_salary "
               "FROM employees GROUP BY department ORDER BY avg_salary DESC");

2. 主从视图关联

// 主表模型
QSqlQueryModel departmentsModel;
departmentsModel.setQuery("SELECT id, name FROM departments");

// 从表模型(当主表选择变化时更新)
QSqlQueryModel employeesModel;
QObject::connect(departmentsView->selectionModel(), &QItemSelectionModel::currentRowChanged,
    [&](const QModelIndex &current, const QModelIndex &previous) {
        int deptId = departmentsModel.data(departmentsModel.index(current.row(), 0)).toInt();
        employeesModel.setQuery(QString("SELECT name, position FROM employees WHERE dept_id = %1").arg(deptId));
    });

六、注意事项

1.内存管理:大数据量查询可能导致内存问题,考虑分页或增量加载

2.错误处理:检查查询是否执行成功

if (model.lastError().isValid()) {
    qDebug() << "查询错误:" << model.lastError().text();
}

3.线程安全:QSqlQueryModel 不是线程安全的,数据库操作应在同一线程

4.性能考虑:复杂查询可能影响UI响应,考虑在后台线程执行

总结

        QSqlQueryModel 是 Qt 中连接数据库和UI的高效桥梁,特别适合展示复杂查询结果。虽然默认是只读的,但通过继承和重写方法可以实现编辑功能。对于简单的数据展示需求,它提供了快速开发的途径;对于复杂需求,它又提供了足够的灵活性进行扩展。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值