Russian Qt Forum
Ноябрь 23, 2024, 21:10 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: QSqlTableModel - добавить строку не получается.  (Прочитано 15548 раз)
Alex_C
Гость
« : Июль 23, 2012, 11:22 »

Странная несколько проблема. Таких же вопросов в инене видел много - но ответа на них нет. Может тут подскажут.
Есть наследник от QSqlQueryModel. Работает с движком SQLite.
Необходимо редактировать данные - это я решил так

Код
C++ (Qt)
bool LogModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
   QSqlTableModel::setData(index, value, role);
 
   if (index.column() < 1)
       return false;
 
   return updateDataForColumn(getFieldNameByIndex(index.column()), index, value);
}
 
bool LogModel::updateDataForColumn(QString columnName, const QModelIndex &index,
                                  const QVariant &value)
{
   QModelIndex primaryKeyIndex = QSqlQueryModel::index(index.row(), 0);
   int id = QSqlQueryModel::data(primaryKeyIndex).toInt();
 
   QSqlQuery query;
   if (index.column() > 1)
   {
       query.prepare("UPDATE " + globalVariable->logName +
                     " SET " + columnName +
                     " = ? WHERE KeyField = ?");
       query.addBindValue(value.toString());
       query.addBindValue(id);
   }
   bool b = query.exec();
   emit dataChanged(index, index);
   return b;
}
 
 

и необходимо вставить строку. В документации написано, что для этого нужно переопределить виртуальную ф-цию insertRows. А вот как ее переопределить для QSqlTableModel - не понятно. Пытался типа так

Код
C++ (Qt)
bool LogModel::insertRows(int position, int rows, const QModelIndex &index)
{
   Q_UNUSED(index);
 
   beginInsertRows(QModelIndex(), position, position + rows - 1);
 
   QSqlQuery query;
   query.prepare("INSERT INTO " + globalVariable->logName +
                 " (Name) VALUES (:Name)");
   query.bindValue(":Name", "");
   for (int row = 0; row < rows; row++)
   {
       query.exec();
   }
 
   endInsertRows();
   return true;
}
 

Не работает.
Для других абстрактных моделях примеров много, а вот конкретно для этого ничего найти не смог.
Записан
fte
Гость
« Ответ #1 : Июль 23, 2012, 14:38 »

Цитировать
Есть наследник от QSqlQueryModel.
......
А вот как ее переопределить для QSqlTableModel - не понятно. Пытался типа так
дык все-таки наследник от кого? QSqlQueryModel или QSqlTableModel? это принципиально....
Записан
Alex_C
Гость
« Ответ #2 : Июль 23, 2012, 15:19 »

Наследник от QSqlTableModel - то, что принципиально понимаю. У наследников QSqlTableModel , как я понимаю, данные в памяти кешируются. И как я понимаю, данные отдельно ручками нужно вносить в базу на диске и в данные в самой модели.
Записан
fte
Гость
« Ответ #3 : Июль 23, 2012, 16:03 »

Тогда setData и InsertRows Вам НЕ нужно переопределять.....

читаем справку по QSqlTableModel
обращаем особое  внимание на InsertRecord,    setEditStrategy, revert, revertAll, submit, submitAll

метод setData, у Вас в корне неправильный, оригинальный и так сделает соответствующий update для таблицы, правильнее
переопределить метод flags
Код:
 
if(index.column()>=1)
      return Qt::ItemIsEditable;

Записан
Alex_C
Гость
« Ответ #4 : Июль 23, 2012, 16:26 »

Да я уже взад и вперед справку перечитал.
да есть у меня и

Код
C++ (Qt)
Qt::ItemFlags LogModel::flags(const QModelIndex &index) const
{
   Qt::ItemFlags flags = QSqlQueryModel::flags(index);
   if(isBoolField(index.column()))
       flags |= Qt::ItemIsUserCheckable;
   else if (index.column() >= 1)
       flags |= Qt::ItemIsEditable;
 
   return flags;
}
 

и

Код
C++ (Qt)
setEditStrategy(QSqlTableModel::OnManualSubmit);
 

убрал свои методы setData и insertRows.

Добавляю строку
Код
C++ (Qt)
   QSqlRecord record = logModel->record();
 
   record.setValue(... добавили все что надо);
   logModel->insertRecord(-1, record);
   logModel->submitAll();
 

в таблицу запись добавилась, но в вертикальном хедер около записи - *
Вышли из программы - зашли снова - записи нет.
И если редактируем - тоже изменения в базу на диск не вносятся.
Записан
fte
Гость
« Ответ #5 : Июль 23, 2012, 16:37 »

Код
C++ (Qt)
if( !logModel->insertRecord(-1,record) )
{
qDebug() << logModel->lastError().text();
logModel->revertAll();
}
 
Записан
Alex_C
Гость
« Ответ #6 : Июль 23, 2012, 16:46 »

Никаких сообщений....
Фантазии и меня закончились Улыбающийся
Перепробовал все варианты, что нашел.
Записан
fte
Гость
« Ответ #7 : Июль 23, 2012, 16:55 »

Пардон, вот так:
Код
C++ (Qt)
if( !logModel->submitAll())
{
qDebug() << logModel->lastError().text();
logModel->revertAll();
}
 
Записан
Alex_C
Гость
« Ответ #8 : Июль 23, 2012, 17:01 »

О!
Спасибо большое! Хоть ошибку выдало -
"near "(": syntax error Unable to execute statement"
Пока правда непонятна что за скобка.
Записан
fte
Гость
« Ответ #9 : Июль 23, 2012, 17:10 »

Код
C++ (Qt)
if( !logModel->submitAll())
{
qDebug() << logModel->lastError().text();
       qDebug() << logModel->query().lastQuery();
logModel->revertAll();
}
Записан
Alex_C
Гость
« Ответ #10 : Июль 24, 2012, 08:13 »

Вот что выдало (что собственно и должно было выдать)
"SELECT * FROM testtable ORDER BY DateIns ASC, TimeQIns ASC"
Пока подозрение только одно - я заполняю QSqlTableModel при помощи такого запроса:
 - это в ф-ции openModel моей модели:
Код
C++ (Qt)
qobject_cast<QSqlQueryModel*>(this)->setQuery(queryStr);
 
т.е. не средствами QSqlTableModel, а прямым запросом.
Может дело в этом?
Записан
Alex_C
Гость
« Ответ #11 : Июль 24, 2012, 09:26 »

Спасибо большое за указание, где ошибки смотреть!
Разобрался, почему были ошибки.
1. Я сначала создавал QSqlTableModel - а уж потом подсоединялся к базе. Но это чисто моя ошибка - пока экспериментировал с программой, не заметил как это произошло.
2. Я считывал данные
qobject_cast<QSqlQueryModel*>(this)->setQuery(queryStr);
- данные считываются, но вот setTable все равно нужно задавать. Вот по этому у меня и не добавлялась запись.

Однако появились другие проблемы:
1. При добавлении записи в таблицу, вся таблица перечитывается с диска, что долго. Есть возможность это как то обойти?
2. При выполнении операции

Код
C++ (Qt)
   while(canFetchMore())
   {
       fetchMore();
       QCoreApplication::processEvents();
   }
 

как сказать QTableView (да и всем другим компонентам) отключить вывод отображение данных из модели (наналог в Дельфи TTable.EnableControls/DisableControls)?
Записан
fte
Гость
« Ответ #12 : Июль 24, 2012, 11:32 »

Цитировать
2. Я считывал данные
qobject_cast<QSqlQueryModel*>(this)->setQuery(queryStr);
- данные считываются, но вот setTable все равно нужно задавать. Вот по этому у меня и не добавлялась запись.

А вот так делать не надо! если вы хотите получить в итоге запрос типа:
SELECT * FROM testtable ORDER BY DateIns ASC, TimeQIns ASC
нужно перекрыть метод orderByClause()..., а для задания условий запроса - setFilter();
нельзя использовать внутренний query на прямую! через него QSqlTableModel  читает и изменяет информацию, и соответственно текст sql-пердолжения в каждый момент разный в зависимости от операции!!!

setTable("testtable"); // вытаскивает всю нужную информацию из системных таблиц (например название полей их тип и т.д.)
select(); // выполнить запрос "select * from testtable" , QSqlTableModel формирует его динамически!

Цитировать
Однако появились другие проблемы:
1. При добавлении записи в таблицу, вся таблица перечитывается с диска, что долго. Есть возможность это как то обойти?
2. При выполнении операции

1. Может быть следствием вышесказанного, во всяком случае это в Вашем коде, QSqlTableModel - при вставке новой записи сама ничего не пересчитывает....
2. tableView->blockSignals(true);
Записан
Alex_C
Гость
« Ответ #13 : Июль 24, 2012, 16:31 »

Посмотрел исходники, поразберался.
Получается все немного не так:
Метод orderByClause() нельзя перекрыть - он virtual protected.
Да это и не надо. В принципе вполне пойдет и
qobject_cast<QSqlQueryModel*>(this)->setQuery(queryStr);
только перед этим нужно сделать
setTable - чтоб поля таблицы определились.
Ну вообще сортировка и выборка работают правильно - в интернете вроде как и советуют если нужна сложная сортировка напрямую setQuery вызывать.

Тут вот сейчас вопрос про вставку:
в таблице есть 10 тыс записей. При добавлении новой записи после submitAll происходит полное считывание записей с базы. Естественно медленно. Это так и должно быть? Специально для пробы все делаю по документации - открываю через select().
Записан
fte
Гость
« Ответ #14 : Июль 24, 2012, 16:49 »

Цитировать
Метод orderByClause() нельзя перекрыть - он virtual protected.
Да ну, с каких это пор....
вот кусок для PostgreSQL из реального проекта:
Код
C++ (Qt)
QString SqlTableModel::orderByClause() const
{
QString s = QSqlTableModel::orderByClause();
if(!s.isNull()) s.append(QLatin1String(" NULLS FIRST" ));
return s;
}

Цитировать
При добавлении новой записи после submitAll происходит полное считывание записей с базы. Естественно медленно. Это так и должно быть?
Да!
Код
C++ (Qt)
bool QSqlTableModel::submitAll()
{
   Q_D(QSqlTableModel);
.........
.........
..........
       d->clearCache();
       return select();
   }
   return false;
}
 

но можно перекрыть select()!
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.361 секунд. Запросов: 21.