Simplifique o trabalho com bancos de dados no Qt com QSqlRelationalTableModel

Bom dia, Khabrovsk! Neste artigo, quero falar sobre minha experiência de simplificar a interação com bancos de dados SQL ao desenvolver um aplicativo de desktop usando a classe QSqlRelationalTableModel da biblioteca de plataforma cruzada Qt.

Prólogo


Conheci o Qt quando eu era aluno do primeiro ano, começando a programar em C ++, ao mesmo tempo em que fiquei seriamente interessado na biblioteca e, desde então, acompanho suas atualizações. Alguns meses atrás, no trabalho, eles me forneceram um TOR no qual era necessário desenvolver um aplicativo que interaja com o banco de dados SQLite. A estrutura da base é fixa e conhecida por mim pela TK.

O aplicativo deve poder fornecer convenientemente ao operador os dados armazenados no banco de dados, permitir adicionar novos registros, excluir e alterar os existentes.

Em seguida, descreverei brevemente o processo de desenvolvimento com trechos de código e tentarei explicar razoavelmente por que, nesse caso, a escolha foi feita em favor de QSqlRelationalTableModel .

Início do desenvolvimento


Inicialmente, foi decidido estabelecer interação com o banco de dados usando consultas simples, ou seja, SELECT , INSERT , DELETE , que permitem implementar todas as funções necessárias do aplicativo.

Para fazer isso, precisamos das classes QSqlDatabase e QSQlQuery :

QSqlDatabase db; //    db = QSqlDatabase::addDatabase("QSQLITE"); //    db.setHostName("localhost"); //  ,    db.setDatabaseName(path); //QString path -    //   if(db.open()){ qDebug() << "db opened OK..."; }else{ qDebug() << " db opening failed..."; } }else{ qDebug() << "file doesnot exist"; exit(0); // ,     , //   } 

Depois disso, todas as operações no banco de dados são executadas da seguinte maneira:

 // ,    <b>QLineEdit</b>' QString query = "INSERT INTO Table (column) VALUES ('" + ui->Input->text() + "')"; QSqlQuery sqlQuery(db); //c   qDebug() << "QUERY: " << query; // //   if(sqlQuery.exec(query)){ qDebug() << "query failed..."; } else{ qDebug() << "query failed..."; } 

As instruções Select são executadas da mesma forma, exceto que os dados ainda precisam ser recebidos e colocados em algum lugar:

 QString query = "SELECT id, ka FROM Table"; QSqlQuery sqlQ(db); if(!sqlQ.exec(query)) { qDebug() << "query failed..."; return; } //     // ,        while (sqlQ.next()){ //           ui->ComboBox->addItem(sqlQ.value(1).toString(),sqlQ.value(0).toInt()); } 

As instruções de exclusão são executadas exatamente da mesma maneira que o Insert, porque não retornam nada.

Tudo bem, qual é o problema?


E a verdade é que você pode implementar tudo através dessas expressões e consultas. Por que precisamos de modelos?

Quando temos uma tabela não relacionada, tudo parece muito simples e não requer a introdução de ferramentas adicionais. Agora imagine que temos essas tabelas, por exemplo, 5, cada uma com 5 colunas, sem incluir o id. E cada um tem uma conexão com o anterior usando chave estrangeira via id , ou seja, ao excluir, é necessário fazer cascata para excluir todos os registros "filhos". Isso leva a um grande número de solicitações; o trabalho do aplicativo diminui significativamente; além disso, é necessário atualizar a tabela e sua apresentação na interface a cada vez, o que leva a escrever funções adicionais para atualização, aparência de bugs ou risco de ocorrência e, em geral, reduzir a legibilidade. código.

Por esse motivo, durante o processo de desenvolvimento, tive que abandonar o conceito de usar consultas SQL simples.

Outras opções foram feitas em favor do QSqlRelationalTableModel em conjunto com o QTableView . Existe uma versão ainda mais simples da implementação do modelo - QSqlTableModel , a primeira é herdada, possui os mesmos métodos, mas adiciona a capacidade de criar uma conexão QSqlRelation , o que é muito conveniente se o usuário não mostrar o ID do registro, mas o nome do registro "pai" com o qual ele conectado.

Vejamos a implementação com modelos


Aqui estão alguns trechos de pod que mostram a implementação do modelo / vista.

No arquivo de cabeçalho:

 QSqlRelationalTableModel *model; 

No construtor:

 //  ,    //  QTableView  ,    //QModelIndex     ,      connect(ui->tableView, SIGNAL(clicked(const QModelIndex &)), this, SLOT(onTableClicked(const QModelIndex &))); model = new QSqlRelationalTableModel(parent, db); // , QSqlDatabase    model->setTable("Table"); //    

A linha abaixo contém um dos recursos e vantagens mais convenientes do modelo em relação às consultas sql - edita, adiciona e exclui, dependendo do contexto, os dados na tabela sql ao mudar para QTableView. A conveniência é que você não precisa mais controlar a correção da exclusão em cascata de dados e atualizá-los em um único QTableView.

 model->setEditStrategy(QSqlRelationalTableModel::OnFieldChange); 

Em seguida, vem outro recurso conveniente fornecido por esta classe: uma conexão é estabelecida entre duas colunas de tabelas diferentes:

 //ParentTable - ,      //id - ,         //name - ,        model->setRelation(1,QSqlRelation("ParentTable", "id", "name")); 

Além disso, tudo é mais padrão: select () executará uma instrução SELECT e setHeaderData () definirá o texto nos cabeçalhos QTableView:

 model->select(); model->setHeaderData(0, Qt::Horizontal, tr("id")); model->setHeaderData(1, Qt::Horizontal, tr("id_sub")); model->setHeaderData(2, Qt::Horizontal, tr("count")); model->setHeaderData(3, Qt::Horizontal, tr("number")); model->setHeaderData(4, Qt::Horizontal, tr("data_word")); model->setHeaderData(5, Qt::Horizontal, tr("time")); model->setHeaderData(6, Qt::Horizontal, tr("name")); model->setHeaderData(7, Qt::Horizontal, tr("description")); ui->tableView->setModel(model); //     QTableView 

Agora, o modelo e o tableView trabalham juntos e desempenham suas funções. Um link para o github deixará todas as fontes, nas quais eu implementei adicionando uma entrada ao modelo, excluindo-o e também filtros.

Conclusão


Neste artigo, eu queria incentivar todos aqueles que já trabalham com o banco de dados no Qt a abandonar consultas sql nuas para projetos de pelo menos complexidade média e passar a trabalhar com modelos para simplificar sua vida, tornar o código mais legível e universal, bem, basta fazer algo de bom e novo.

Isso é tudo! Espero que minha experiência com essas aulas ajude os leitores a resolver com êxito um problema semelhante!

Source: https://habr.com/ru/post/pt435134/


All Articles