Arrow
Arrow19 марта 2017 г. 14:04

Добавление новой записи в базу данных

QDataWidgetMapper

Есть база данных с таблицей:

#define TABLE                                            "main"
#define TABLE_REG_NUMBER        "Reg_number"
#define TABLE_SHIFR                             "Shifr"
#define TABLE_NAME                            "Name"
Существуют поля ввода QLineEdit данные в которые подставляются через QDataWidgetMapper:
    model = new QSqlTableModel(this);
    model->setTable(TABLE);
    model->setEditStrategy(QSqlTableModel::OnManualSubmit);
    model->select();

    mapper = new QDataWidgetMapper();
    mapper->setModel(model);
    mapper->addMapping(ui->reg_numEdit, 1);
    mapper->addMapping(ui->shifrEdit, 2);
    mapper->addMapping(ui->nameEdit, 3);

    mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit);

     mapper->setCurrentModelIndex(model->index(index.row(),0));
Далее сохранение данных происходит так:
        
        mapper->submit();
        model->submitAll();
        model->select();
Проблема в том, что данные редактируются и изменения сохраняются без проблем, но только в уже существующих записях. Создавать же новую запись не выходит. Каким образом можно создать новую запись в базе данных?
Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Вам это нравится? Поделитесь в социальных сетях!

15
Arrow
  • 19 марта 2017 г. 14:08

Пробовал добавить запись таким образом:

    modelMain->insertRow(modelMain->rowCount(QModelIndex()));
    mapper->toLast();
Строка добавляется, но при попытке сохранения исчезает и данные не записываются.
    Arrow
    • 19 марта 2017 г. 14:09

    Статью https://evileg.com/post/71/ читал и класс обертка реализован по описанному принципу.

      Evgenii Legotckoi
      • 20 марта 2017 г. 0:16

      Из этого кода проблема не ясна, поскольку он идентичен тому, что в статье.

      В самой базе данных случаем нет ограничений на добавление новых записей?

        Arrow
        • 20 марта 2017 г. 8:53

        Ограничений нет. Через утилиту SQLiteStudio все добавляется без проблем.

          Evgenii Legotckoi
          • 20 марта 2017 г. 8:57

          Тогда хотелось бы увидеть более полный листинг

            Arrow
            • 20 марта 2017 г. 9:20

            database.h

            #ifndef DATABASE_H
            #define DATABASE_H
            
            #include <QObject>
            #include <QSql>
            #include <QSqlQuery>
            #include <QSqlError>
            #include <QSqlDatabase>
            #include <QFile>
            #include <QDate>
            #include <QDebug>
            
            #include <QDir>
            
            #define DATABASE_HOSTNAME   "DrawBase"
            #define DATABASE_NAME       "DrawBase.db"
            
            #define TABLE                   "main"
            #define TABLE_REG_NUMBER        "Reg_number"
            #define TABLE_SHIFR             "Shifr"
            #define TABLE_NAME              "Name"
            #define TABLE_DATE              "Date"
            #define TABLE_LIST              "List"
            #define TABLE_PATH              "Path"
            #define TABLE_UZEL              "Uzel"
            #define TABLE_PICT_PATH         "Pict_path"
            #define TABLE_PRIMECHANIA       "Primechania"
            
            class DataBase : public QObject
            {
                Q_OBJECT
            public:
                explicit DataBase(QObject *parent = 0);
                ~DataBase();
            
                void connectToDataBase();
                bool insertIntoMainTable(const QVariantList &data);
            
            private:
                QSqlDatabase db;
            
                bool openDataBase();
                bool restoreDataBase();
                void closeDataBase();
                bool createMainTable();
            };
            
            #endif // DATABASE_H
            
            database.cpp
            #include "database.h"
            
            DataBase::DataBase(QObject *parent) : QObject(parent)
            {
            
            }
            
            DataBase::~DataBase()
            {
            
            }
            
            void DataBase::connectToDataBase()
            {
                if(!QFile(QDir::currentPath() + "/" + DATABASE_NAME).exists()) {
                    this->restoreDataBase();;
                }
                else {
                    this->openDataBase();
                }
            }
            
            bool DataBase::restoreDataBase()
            {
                if(this->openDataBase()) {
                    if(!this->createMainTable()) {
                        return false;
                    }
                    else {
                        return true;
                    }
                }
                else {
                    qDebug() << "Не удалось восстановить базу данных";
                    return false;
                }
                return false;
            }
            
            bool DataBase::openDataBase()
            {
                db = QSqlDatabase::addDatabase("QSQLITE");
                db.setHostName(DATABASE_HOSTNAME);
                db.setDatabaseName(QDir::currentPath() + "/" + DATABASE_NAME);
                if(db.open()) {
                    return true;
                }
                else {
                    return false;
                }
            }
            
            void DataBase::closeDataBase()
            {
                db.close();
            }
            
            bool DataBase::createMainTable()
            {
                QSqlQuery query;
                if(!query.exec( "CREATE TABLE " TABLE " ("
                                        "id INTEGER PRIMARY KEY AUTOINCREMENT, "
                                        TABLE_REG_NUMBER        " STRING        NOT NULL,"
                                        TABLE_SHIFR             " STRING        NOT NULL,"
                                        TABLE_NAME              " STRING        NOT NULL,"
                                        TABLE_DATE              " DATE          NOT NULL,"
                                        TABLE_LIST              " INTEGER       NOT NULL,"
                                        TABLE_PATH              " STRING        NOT NULL,"
                                        TABLE_UZEL              " STRING,"
                                        TABLE_PICT_PATH         " STRING        NOT NULL,"
                                        TABLE_PRIMECHANIA       " STRING"
                                    " )"
                                )) {
                    qDebug() << "DataBase: error of create " << TABLE;
                    qDebug() << query.lastError().text();
                    return false;
                }
                else {
                    return true;
                }
                return false;
            }
            
            bool DataBase::insertIntoMainTable(const QVariantList &data)
            {
                QSqlQuery query;
                query.prepare("INSERT INTO " TABLE " ( " TABLE_REG_NUMBER ", "
                                                         TABLE_SHIFR ", "
                                                         TABLE_NAME ", "
                                                         TABLE_DATE " ) "
                                                         TABLE_LIST " ) "
                                                         TABLE_PATH " ) "
                                                         TABLE_UZEL " ) "
                                                         TABLE_PICT_PATH " ) "
                                                         TABLE_PRIMECHANIA " ) "
                              "VALUES (:Reg_number, :Shifr, :Name, :Date,"
                                       ":List, :Path, :Uzel, :Pict_path, :Primechania )");
                query.bindValue(":Reg_number",  data[0].toString());
                query.bindValue(":Shifr",       data[0].toString());
                query.bindValue(":Name",        data[0].toString());
                query.bindValue(":Date",        data[0].toDate());
                query.bindValue(":List",        data[0].toString());
                query.bindValue(":Path",        data[0].toString());
                query.bindValue(":Uzel",        data[0].toString());
                query.bindValue(":Pict_path",   data[3].toString());
                query.bindValue(":Primechania", data[0].toString());
                if(!query.exec()) {
                    qDebug() << "error insert into " << TABLE;
                    qDebug() << query.lastError().text();
                    return false;
                }
                else {
                    return true;
                }
                return false;
            }
            
            drawwidget.h
            #ifndef DRAWWIDGET_H
            #define DRAWWIDGET_H
            
            #include <QWidget>
            #include <QSqlTableModel>
            #include <QDataWidgetMapper>
            #include <QMessageBox>
            #include <QSqlRecord>
            
            #include "database.h"
            
            namespace Ui {
            class DrawWidget;
            }
            
            class DrawWidget : public QWidget
            {
                Q_OBJECT
            
            public:
                explicit DrawWidget(QWidget *parent = 0);
                ~DrawWidget();
            
            private slots:
                void on_mainTable_clicked(const QModelIndex &index);
            
                void on_addBtn_clicked();
            
                void on_acceptBtn_clicked();
            
                void on_removeBtn_clicked();
            
            private:
                Ui::DrawWidget *ui;
            
                DataBase                    *db;
                QSqlTableModel              *modelMain;
                QSqlTableModel              *model;
                QDataWidgetMapper           *mapper;
            
                void setupMainModel(const QString &tableName, const QStringList &headers);
                void createUI();
                void mapping();
            };
            
            #endif // DRAWWIDGET_H
            
            drawwidget.cpp
            #include "drawwidget.h"
            #include "ui_drawwidget.h"
            
            DrawWidget::DrawWidget(QWidget *parent) :
                QWidget(parent),
                ui(new Ui::DrawWidget)
            {
                ui->setupUi(this);
            
                setWindowState(Qt::WindowMaximized);
            
                db = new DataBase();
                db->connectToDataBase();
            
                this->setupMainModel(TABLE,
                                     QStringList() << trUtf8("id")
                                                   << trUtf8("Рег. №")
                                                   << trUtf8("Шифр")
                                                   << trUtf8("Наименование")
                                                   << trUtf8("Дата")
                                                   << trUtf8("Кол.")
                                                   << trUtf8("Путь")
                                                   << trUtf8("Узел")
                                                   << trUtf8("Изображение")
                                                   << trUtf8("Примечания")
                               );
            
                // Внешний вид таблицы с данными
                this->createUI();
            
                mapping();
            
                mapper->toFirst();
            }
            
            DrawWidget::~DrawWidget()
            {
                delete ui;
            }
            
            void DrawWidget::setupMainModel(const QString &tableName,
                                            const QStringList &headers)
            {
                modelMain = new QSqlTableModel(this);
                modelMain->setTable(tableName);
            
                for(int i = 0, j = 0; i < modelMain->columnCount(); i++, j++){
                    modelMain->setHeaderData(i,Qt::Horizontal,headers[j]);
                }
            
                modelMain->setSort(0,Qt::AscendingOrder);
            
                modelMain->select();
            }
            
            void DrawWidget::createUI()
            {
                ui->mainTable->setModel(modelMain);
            
                ui->mainTable->setColumnHidden(0, true);
            
                ui->mainTable->setSelectionBehavior(QAbstractItemView::SelectRows);
                
                ui->mainTable->setSelectionMode(QAbstractItemView::SingleSelection);
            
                ui->mainTable->resizeColumnsToContents();
                ui->mainTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
                ui->mainTable->horizontalHeader()->setStretchLastSection(true);
            
                modelMain->select();
            }
            
            void DrawWidget::mapping()
            {
                model = new QSqlTableModel(this);
                model->setTable(TABLE);
                model->setEditStrategy(QSqlTableModel::OnManualSubmit);
                model->select();
            
                mapper = new QDataWidgetMapper();
                mapper->setModel(model);
                mapper->addMapping(ui->reg_numEdit, 1);
                mapper->addMapping(ui->shifrEdit, 2);
                mapper->addMapping(ui->nameEdit, 3);
                mapper->addMapping(ui->dateEdit, 4);
                mapper->addMapping(ui->listEdit, 5);
                // 5 - Path
                mapper->addMapping(ui->uzelEdit, 7);
                // 8 - Pict_path
                mapper->addMapping(ui->primEdit, 9);
            
                mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit);
            }
            
            void DrawWidget::on_mainTable_clicked(const QModelIndex &index)
            {
                mapping();
                mapper->setCurrentModelIndex(model->index(index.row(),0));
            
            }
            
            void DrawWidget::on_addBtn_clicked()
            {
                // Добавить новую запись
                modelMain->insertRow(modelMain->rowCount(QModelIndex()));
            
                QSqlRecord record = modelMain->record();
                record.setValue("Shifr", "");
                mapper->toLast();
                int row = mapper->currentIndex() + 1;
                modelMain->insertRecord(row, record);
            
                mapper->toLast();
            }
            
            void DrawWidget::on_acceptBtn_clicked()
            {
                // Подтвердить изменения
            
                QSqlQuery query;
                QString str = QString("SELECT EXISTS (SELECT " TABLE_SHIFR " FROM " TABLE
                                      " WHERE ( " TABLE_SHIFR " = '%1' "
                                      " OR " TABLE_REG_NUMBER " = '%2' )"
                                      " AND id NOT LIKE '%3' )")
                        .arg(ui->shifrEdit->text(),
                             ui->reg_numEdit->text(),
                             model->data(model->index(mapper->currentIndex(),0),
                                             Qt::DisplayRole).toString());
            
                query.prepare(str);
                query.exec();
                query.next();
            
                if(query.value(0) != 0){
                    QMessageBox::information(this, trUtf8("Ошибка"),
                                             trUtf8("Данный шифр или регистрационный "
                                                    "номер уже существует"));
                }
                else {
                    mapper->submit();
                    model->submitAll();
                }
                modelMain->select();
            }
            
            void DrawWidget::on_removeBtn_clicked()
            {
                // Удалить запись
                QModelIndex index = ui->mainTable->currentIndex();
            
                if(!index.isValid()) return;
            
                modelMain->removeRow(index.row());
                modelMain->submitAll();
                modelMain->select();
            }
            
            database - класс базы данных drawwidget - окно программы
              Evgenii Legotckoi
              • 20 марта 2017 г. 9:50

              Я правильно понимаю, что для одной таблицы, Вы используете две модели данных?

              То есть одна используется для отображения в таблицы, а другая используется для работы в QDataWidgetMapper (вопрос риторический, сконцентрируйтесь на этом утверждении)

              Таким образом, по клику по кнопке вы добавляете пустуй строку в модель, которая отвечает за таблицу, но не в модель, которая отвечает за маппер.

              void DrawWidget::on_addBtn_clicked()
              {
                  // Добавить новую запись
                  modelMain->insertRow(modelMain->rowCount(QModelIndex()));  // Добавили строку в таблицу, а не в маппер
              
                  QSqlRecord record = modelMain->record();
                  record.setValue("Shifr", "");
                  mapper->toLast();
                  int row = mapper->currentIndex() + 1;
                  modelMain->insertRecord(row, record);
              
                  mapper->toLast();
              }

              То есть в модели данных маппера новой строки не появилось. Думаю, что стоит добавлять новую строку не в modelMain , а просто в model . А потом уже обновлять данные через метод select() для mainModel

              Дело в том, что если вы добавили строку в одну модель, то она не появится автоматически в другой модели. И исходя из данного кода, новая строка в маппере не появляется.

                Arrow
                • 20 марта 2017 г. 10:33

                Пробовал с одной моделью modelMain - в lineEdit не отображаются данные при переходе с одной строки на другую.

                Если пробовать добавлять запись в model, а не modelMain запись по прежнему при попытке сохранения не добавляется.

                  Evgenii Legotckoi
                  • 20 марта 2017 г. 11:23

                  Да. Ещё, без этого участка кода проверяли?

                  QSqlRecord record = modelMain->record();
                      record.setValue("Shifr", "");
                      mapper->toLast();
                      int row = mapper->currentIndex() + 1;
                      modelMain->insertRecord(row, record);

                  Если быть точным без всего, что касается QSqlRecord . В статье этот класс вообще не применяется. А то получается, что и строку добавили и запись добавили. И дважды маппер двинули на последнюю запись, но при этом всё в главной модели. Масло масляное получается.

                  Плюсом идёт ещё, что при сохранении данных делаете mainModel->select() , но не делаете того же самого для model . В результате данные для маппера устаревшие получается, и в случае попыток добавить запись, он может пытаться добавить запись с id, который уже существует, а как результат ничего не происходит.

                    Arrow
                    • 21 марта 2017 г. 3:58

                    Убрал код:

                        QSqlRecord record = modelMain->record();
                        record.setValue("Shifr", "");
                        mapper->toLast();
                        int row = mapper->currentIndex() + 1;
                        modelMain->insertRecord(row, record);

                    При сохранении добавил model->select().

                    Новая запись создается, mapper переходит на нее и можно вносить данные, но при нажатии на кнопку сохранения запись в базу данных не сохраняется. Никаких ошибок или предупреждений не выдает.

                      Evgenii Legotckoi
                      • 21 марта 2017 г. 6:37
                      • Ответ был помечен как решение.

                      Уже хорошо. Уже прогресс. Но это проблема скорее всего в том, что в mapper мапятся не все поля.

                      mapper = new QDataWidgetMapper();
                          mapper->setModel(model);
                          mapper->addMapping(ui->reg_numEdit, 1);
                          mapper->addMapping(ui->shifrEdit, 2);
                          mapper->addMapping(ui->nameEdit, 3);
                          mapper->addMapping(ui->dateEdit, 4);
                          mapper->addMapping(ui->listEdit, 5);
                          // 6 - Path
                          mapper->addMapping(ui->uzelEdit, 7);
                          // 8 - Pict_path
                          mapper->addMapping(ui->primEdit, 9);

                      Полагаю, что проблема в поле Path и Pict_path, которые вы объявили как NOT NULL, естественно, что запись не создаётся, поскольку они должны быть ненулевыми, а маппер ими вообще не оперирует. Либо делайте в маппере скрытые поля ввода, из которых будет хоть что-то браться, пускай даже мусор. Либо попробуйте разрешить быть этим полям NULL

                        Arrow
                        • 21 марта 2017 г. 7:08

                        Спасибо, все работает. А я об объявлении полей как NOT NULL даже и не вспомнил.

                          Arrow
                          • 21 марта 2017 г. 9:39

                          Есть еще один маленький вопрос - как мапперу передать определенную строку (путь получаемый с диалога открытия файла), чтобы он внес ее в БД или это проще сделать без его использования конструкцией типа:

                              QSqlRecord record = modelMain->record();
                              record.setValue("Pict_path", "");

                          И что удобнее и правильнее - хранить в базе данных само изображение, или путь к нему? И если хранится путь, то при переходе на определенную запись в БД используя путь выполнять вставку изображения в QLabel.

                            Evgenii Legotckoi
                            • 21 марта 2017 г. 10:05

                            Добавьте в mapper ещё один QLineEdit , который будет отвечать за путь к файлу. Когда диалог возвращает этот путь, то установите путь в данный QLineEdit . Если не хотите, чтобы пользователь мог его редактировать, то установите для QLineEdit режим setReadOnly(true) . Или вообще сделайте его скрытым setHidden(true)

                            Лучше хранить путь к файлу: Во-первых - это будет быстрее, Во-вторых база данных распухнет очень быстро, если в ней файлы хранить.

                              Arrow
                              • 21 марта 2017 г. 14:03

                              Спасибо!

                                Комментарии

                                Только авторизованные пользователи могут публиковать комментарии.
                                Пожалуйста, авторизуйтесь или зарегистрируйтесь
                                d
                                • dsfs
                                • 26 апреля 2024 г. 11:56

                                C++ - Тест 004. Указатели, Массивы и Циклы

                                • Результат:80баллов,
                                • Очки рейтинга4
                                d
                                • dsfs
                                • 26 апреля 2024 г. 11:45

                                C++ - Тест 002. Константы

                                • Результат:50баллов,
                                • Очки рейтинга-4
                                d
                                • dsfs
                                • 26 апреля 2024 г. 11:35

                                C++ - Тест 001. Первая программа и типы данных

                                • Результат:73баллов,
                                • Очки рейтинга1
                                Последние комментарии
                                k
                                kmssr9 февраля 2024 г. 2:43
                                Qt Linux - Урок 001. Автозапуск Qt приложения под Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
                                АК
                                Анатолий Кононенко5 февраля 2024 г. 9:50
                                Qt WinAPI - Урок 007. Работаем с ICMP Ping в Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
                                EVA
                                EVA25 декабря 2023 г. 18:30
                                Boost - статическая линковка в CMake проекте под Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
                                J
                                JonnyJo25 декабря 2023 г. 16:38
                                Boost - статическая линковка в CMake проекте под Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
                                G
                                Gvozdik19 декабря 2023 г. 5:01
                                Qt/C++ - Урок 056. Подключение библиотеки Boost в Qt для компиляторов MinGW и MSVC Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
                                Сейчас обсуждают на форуме
                                PS
                                Peter Son4 мая 2024 г. 0:57
                                Best Indian Food Restaurant In Cincinnati OH Ready to embark on a gastronomic journey like no other? Join us at App india restaurant and discover why we're renowned as the Best Indian Food Restaurant In Cincinnati OH . Whether y…
                                Evgenii Legotckoi
                                Evgenii Legotckoi2 мая 2024 г. 21:07
                                Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Добрый день. По моему мнению - да, но то, что будет касаться вызовов к функционалу Андроида, может создать огромные трудности.
                                IscanderChe
                                IscanderChe30 апреля 2024 г. 11:22
                                Во Flask рендер шаблона не передаётся в браузер Доброе утро! Имеется вот такой шаблон: <!doctype html><html> <head> <title>{{ title }}</title> <link rel="stylesheet" href="{{ url_…
                                G
                                Gar22 апреля 2024 г. 12:46
                                Clipboard Как скопировать окно целиком в clipb?
                                Павел Дорофеев
                                Павел Дорофеев14 апреля 2024 г. 9:35
                                QTableWidget с 2 заголовками Вот тут есть кастомный QTableView с многорядностью проект поддерживается, обращайтесь

                                Следите за нами в социальных сетях