Simplifique el trabajo con bases de datos en Qt con QSqlRelationalTableModel

Buen día, Khabrovsk! En este artículo, quiero hablar sobre mi experiencia de simplificar la interacción con las bases de datos SQL al desarrollar una aplicación de escritorio utilizando la clase QSqlRelationalTableModel de la biblioteca multiplataforma Qt.

Prologo


Conocí a Qt cuando era un estudiante de primer año, apenas comenzaba a programar en C ++, luego me interesé seriamente en la biblioteca y, desde entonces, he estado siguiendo sus actualizaciones. Hace unos meses, en el trabajo, me dieron un TOR en el que era necesario desarrollar una aplicación que interactúe con la base de datos SQLite. La estructura de la base es fija y la conozco de antemano TK.

La aplicación debe poder proporcionar convenientemente al operador los datos almacenados en la base de datos, permitir agregar nuevos registros, eliminar y cambiar los existentes.

A continuación, describiré brevemente el proceso de desarrollo con fragmentos de código e intentaré explicar razonablemente por qué en este caso la elección se hizo a favor de QSqlRelationalTableModel .

Inicio del desarrollo


Inicialmente, se decidió establecer una interacción con la base de datos utilizando consultas simples de la base de datos, es decir, SELECCIONAR , INSERTAR , ELIMINAR , que le permiten implementar todas las funciones necesarias de la aplicación.

Para hacer esto, necesitamos las clases QSqlDatabase y 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); // ,     , //   } 

Después de eso, todas las operaciones en la base de datos se realizan de la siguiente manera:

 // ,    <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..."; } 

Las instrucciones de selección se ejecutan de manera similar, excepto que los datos aún deben recibirse y colocarse en algún 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()); } 

Las declaraciones de eliminación se ejecutan exactamente de la misma manera que Insertar porque no devuelven nada.

Muy bien, ¿cuál es el problema?


Y la verdad es que puede implementar todo a través de estas expresiones y consultas, ¿por qué necesitamos modelos?

Cuando tenemos una tabla no relacionada, todo parece muy simple y no requiere la introducción de herramientas adicionales. Ahora imagine que tenemos tales tablas, por ejemplo, 5, cada una con 5 columnas, sin incluir id. Y cada uno tiene una conexión con el anterior usando una clave externa a través de id , es decir al eliminar, es necesario hacer una cascada para eliminar todos los registros "secundarios". Esto lleva a una gran cantidad de solicitudes, el trabajo de la aplicación se ralentiza significativamente, además, es necesario actualizar la tabla y su presentación en la interfaz cada vez, lo que lleva a escribir funciones adicionales para la actualización, la aparición de errores o el riesgo de que ocurran, y en general para reducir la legibilidad código

Por esta razón, durante el proceso de desarrollo, tuve que abandonar el concepto de usar consultas SQL desnudas.

Se hicieron otras elecciones a favor de QSqlRelationalTableModel junto con QTableView . Hay una versión aún más simple de la implementación del modelo: QSqlTableModel , el primero se hereda de él, tiene todos los mismos métodos, pero agrega la capacidad de crear una conexión QSqlRelation , lo cual es muy conveniente si el usuario necesita mostrar no la identificación del registro, sino el nombre del registro "padre" con el que conectado

Veamos la implementación con modelos.


Aquí hay algunos extractos de pod que muestran la implementación del modelo / vista.

En el archivo de encabezado:

 QSqlRelationalTableModel *model; 

En el constructor:

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

La línea a continuación contiene una de las características y ventajas más convenientes del modelo sobre las consultas sql: edita, agrega, elimina, según el contexto, los datos de la tabla sql al cambiar de QTableView. La conveniencia es que ya no necesita controlar la corrección de la eliminación de datos en cascada y actualizarlos dentro de un solo QTableView.

 model->setEditStrategy(QSqlRelationalTableModel::OnFieldChange); 

Luego viene otra característica conveniente proporcionada por esta clase: se establece una conexión entre dos columnas de tablas diferentes:

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

Además, todo es más estándar: select () ejecutará una instrucción SELECT y setHeaderData () establecerá el texto en los encabezados 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 

Ahora el model y tableView trabajan juntos y realizan sus funciones. Un enlace a github dejará todas las fuentes, en ellas implementé agregando una entrada al modelo, eliminándola, así como filtros.

Conclusión


En este artículo, quería alentar a todos aquellos que ya trabajan con la base de datos en Qt a abandonar las consultas sql desnudas para proyectos de complejidad al menos mediana y cambiar a trabajar con modelos para simplificar su vida, hacer que el código sea más legible y universal, bueno, solo haz algo bueno y nuevo.

Eso es todo! ¡Espero que mi experiencia con estas clases ayude a los lectores a resolver con éxito un problema similar!

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


All Articles