crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

> Не удается программно изменять значения модели БД, submitAll возвращает false после вызова setRecord
Rocky
  опции профиля:
сообщение 17.2.2009, 10:43
Сообщение #1


Старейший участник
****

Группа: Участник
Сообщений: 530
Регистрация: 22.12.2008
Из: Санкт-Петербург
Пользователь №: 463

Спасибо сказали: 22 раз(а)




Репутация:   7  


Всем привет! Помогите пожалуйста с проблемкой... Создаю таблицу БД SQLite 3 таким образом:
QSqlQuery oQuery;
//...
oQuery.exec("CREATE TABLE PIPES (id INTEGER, PipeType varchar(50), D_outside varchar(20), d_inside varchar(20), "
                                    "Roughness varchar(20), Lamda varchar(20))");

oQuery.prepare("INSERT INTO %1 VALUES(:id, :PipeType, :D_outside, :d_inside, :Roughness, :Lamda)");

char szBuf[128];
while (!file.eof())
{
    file.getline(szBuf, 128, ';');
    file.getline(szBuf, 128, ';'); oQuery.bindValue(":PipeType", szBuf);
    file.getline(szBuf, 128, ';'); oQuery.bindValue(":D_outside", szBuf);
    file.getline(szBuf, 128, ';'); oQuery.bindValue(":d_inside", szBuf);
    file.getline(szBuf, 128, ';'); oQuery.bindValue(":Roughness", szBuf);
    file.getline(szBuf, 128, ';'); oQuery.bindValue(":Lamda", szBuf);
    file.getline(szBuf, 128, ';'); oQuery.bindValue(":id", szBuf);
    oQuery.exec();
}

Таблица создана. Затем нужно сделать ее редактирование, и при этом вставлять записи в нужное место (не обязательно в конец). Вставку делаю так:
QModelIndex oInsertIndex = m_pDataTableView->currentIndex();
int nRow = oInsertIndex.row() == -1 ? 0 : oInsertIndex.row();
m_pModel->insertRow(nRow);

//и после вставки перенумеровываю все id по порядку (id - это столбец сортировки)
const int nRowNum = m_pModel->rowCount();
for (int i = 0; i < nRowNum; ++i)  //цикл по строкам таблицы
{
    QSqlRecord oSqlRecord = m_pModel->record(i);
    oSqlRecord.setValue("id", i + 1);
    m_pModel->setRecord(i, oSqlRecord);
}

После этого m_pModel->submitAll() возвращает false, т.е. ничего не сохраняется... Если цикл по строкам убрать, и оставить только саму вставку строки, то submitAll возвращает true (только вставленная строка перемещается в другое место). Пробовал через setRecord менять другие столбцы (не id), результат тот же. Пробовал менять данные через индексы и setData, результат тот же...

m_pDataTableView - это QTableView. Модель устанавливается в конструкторе класса через setModel(pModel); Сама модель:
QSqlTableModel *pModel = new QSqlTableModel();
if (!pModel) return;

pModel->setTable("PIPES");
pModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
pModel->select();


В чем могут быть грабли? Никто не пробовал менять данные таким образом? Как можно обойти это? QT 4.3.4. Заранее большое спасибо!

-----Добавлено------
Блин, удалите пожалуйста эту тему, инет сглючил, 2 темы создал случайно :(


Сообщение отредактировал Rocky - 17.2.2009, 10:46
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
 
Начать новую тему
Ответов
Rocky
  опции профиля:
сообщение 18.2.2009, 14:27
Сообщение #2


Старейший участник
****

Группа: Участник
Сообщений: 530
Регистрация: 22.12.2008
Из: Санкт-Петербург
Пользователь №: 463

Спасибо сказали: 22 раз(а)




Репутация:   7  


По-поводу двойной выборки. Если убрать select(), то данные во вьюхе не отображаются. Открываю assistant, читаю.
Цитата
void QSqlTableModel::setTable ( const QString & tableName ) [virtual]
Sets the database table on which the model operates to tableName. Does not select data from the table, but fetches its field information.

Так что выборка происходит все-таки один раз.

По-поводу автоинкремента. Добавил 2 поля в таблицу: SortID INTEGER и ID INTEGER PRIMARY KEY AUTOINCREMENT. Результат тот же. SubmitAll после программного изменения данных возвращает false. К тому же опять непонятность: да, при формировании таблицы, колонка ID сама заполняется. А при добавлении новой строки в QTableView - нет. Надо либо вручную, либо программно. Но программно не годится (см. выше) - просто не сохраняются данные и все.


А вообще бред какой-то...

Я не понимаю, почему после выполнения следующего кода, запись, которая идет после nRow не удаляется. Ни из моей программы, ни даже если открыть sqlbrowser и оттуда пытаться удалить.
QSqlRecord oSqlRecord = m_pModel->record();
oSqlRecord.setValue(0, QString("%1").arg(nRow + 1));
m_pModel->insertRecord(nRow, oSqlRecord);


Т.е. если писать потом
const int nRowNum = m_pModel->rowCount();
m_pModel->removeRows(0, nRowNum);
m_pModel->submitAll();


то одна строка остается по-любому... Если писать так
QSqlQuery(QString("DELETE FROM %1").arg(m_pModel->tableName()));
m_pModel->select();

то таблица стирается. причем намного быстрее, чем 1-м способом.

Я не понимаю, почему не работает
m_pModel->setSort(0, Qt::AscendingOrder);

Записи как есть в базе данных (например, 0-я колонка идет по убыванию номеров), так она и отображается во вьюхе в программе (хотя как я понимаю должна быть наоборот).

Попробовал заполнять как хотел QTableWidget вручную (т.е. уйти от модели вообще) - по скорости получается медленнее.

В общем, после 2-х дневного занятия любовью с этим делом, я написал такой код:
void CDataBrowserDialog::OnAddRowAfter()
{
    QSqlDriver *pDriver = QSqlDatabase::database().driver();
    if (pDriver && pDriver->hasFeature(QSqlDriver::Transactions)) QSqlDatabase::database().transaction();

    //добавляем новый ряд
    QModelIndex oInsertIndex = m_pDataTableView->currentIndex();
    int nRow = oInsertIndex.row() == -1 ? 0 : oInsertIndex.row() + 1;
    m_pModel->insertRow(nRow);
    
    oInsertIndex = m_pModel->index(nRow, 1);
    m_pDataTableView->setCurrentIndex(oInsertIndex);
    m_pDataTableView->edit(oInsertIndex);
    m_bRowNumberWasChanged = true;

    if (pDriver && pDriver->hasFeature(QSqlDriver::Transactions)) QSqlDatabase::database().commit();
}

void CDataBrowserDialog::OnDelRow()
{
    QSqlDriver *pDriver = QSqlDatabase::database().driver();
    if (pDriver && pDriver->hasFeature(QSqlDriver::Transactions)) QSqlDatabase::database().transaction();

    //удаляем выделенный ряд
    const int nRow = m_pDataTableView->currentIndex().row();
    m_roDeletedRows.insert(m_pModel->record(nRow).value(0).toInt());
    m_pModel->removeRow(nRow);
    m_bRowNumberWasChanged = true;

    if (pDriver && pDriver->hasFeature(QSqlDriver::Transactions)) QSqlDatabase::database().commit();
}

void InsertRows(const QSqlRecord& oSqlRecord)
{
    CDataBrowserDialog *pApp = CDataBrowserDialog::GetClassPtr();
    pApp->m_pModel->insertRecord(0, oSqlRecord);
}

void CDataBrowserDialog::submitAll2()
{
    //после закрытия диалога надо перезаполнить все коллекции объектов с обновленной базы данных
    m_bNeedToReReadDataBase = true;
    
    //если не были ни добавлены новые строки, ни удалены старые, то просто делаем так (к счастью это работает).
    if (!m_bRowNumberWasChanged)
    {
        m_pModel->submitAll();
        return;
    }

    //в вектор запихиваем все записи таблицы
    std::vector<QSqlRecord> roSqlRecords;
    const int nRowNum = m_pModel->rowCount();

    //предварительно резервируем память, чтобы не было лишнего перераспределения
    roSqlRecords.reserve(nRowNum);

    //начало транзакции
    QSqlDriver *pDriver = QSqlDatabase::database().driver();
    if (pDriver && pDriver->hasFeature(QSqlDriver::Transactions)) QSqlDatabase::database().transaction();

    //формируем вектор на основе таблицы
    int i = 0, j = 0;
    while (i < nRowNum)
    {
        QSqlRecord oSqlRecord = m_pModel->record(i++);
        if (m_roDeletedRows.find(oSqlRecord.value(0).toInt()) != m_roDeletedRows.end()) continue;

        oSqlRecord.setValue(0, QString("%1").arg(++j));
        roSqlRecords.push_back(oSqlRecord);
    }
    
    //сносим все записи таблицы
    QSqlQuery(QString("DELETE FROM %1").arg(m_pModel->tableName()));
    m_pModel->select();

    //а теперь заново формируем таблицу
    std::for_each(roSqlRecords.rbegin(), roSqlRecords.rend(), InsertRows);

    m_pModel->submitAll();

    //конец транзакции
    if (pDriver && pDriver->hasFeature(QSqlDriver::Transactions)) QSqlDatabase::database().commit();

    m_pDataTableView->resizeColumnsToContents();
    m_pDataTableView->resizeRowsToContents();
    m_roDeletedRows.clear();
    m_bRowNumberWasChanged = false;
}


Работает вобщем-то быстро, но таблицы у меня небольшие. Самое большее 300 записей. Но чесгря мне совсем не нравится такой код... Морального удовольствия я не получил :) Пока пусть работает так… надо программу сдавать уже скоро.. а я пока начну изучение sql :)

Всем спасибо за участие!
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

Сообщений в этой теме
- Rocky   Не удается программно изменять значения модели БД   17.2.2009, 10:43
- - Константин   О_о жесть какая первое, что в глаза бросается: p...   17.2.2009, 12:39
- - Rocky   0. Автоинкремент я до конца не понял как работает,...   17.2.2009, 13:38
- - SABROG   Цитата(Rocky @ 17.2.2009, 10:43) Затем ну...   17.2.2009, 13:50
- - Rocky   Цитатадобавить столбец сортировки Так ведь я и пыт...   17.2.2009, 14:07
- - Константин   0. обратиться к документации по склайт - прочитать...   17.2.2009, 14:36
- - Rocky   Стоп, не понял. 1. В каком месте происходит дважды...   17.2.2009, 16:37
- - Константин   извини, но у тебя с самого начала некрасиво и неиз...   17.2.2009, 17:24
- - Rocky   Цитатакстати, проблема вполне может расти как раз ...   17.2.2009, 20:03
- - Константин   /* от дурная башка */ ...сначала просто поинтересо...   17.2.2009, 20:44
- - Rocky   Не, критика это хорошо )) Правда если она здравая ...   17.2.2009, 21:31
- - SABROG   Цитата(Rocky @ 17.2.2009, 21:31) Но, боюс...   17.2.2009, 22:02
- - Rocky   Цитата50 миллионов записей Офигеть.....А как в ...   17.2.2009, 22:38
|- - trdm   Цитата(Rocky @ 17.2.2009, 22:38) .....или...   17.2.2009, 22:55
- - Константин   а зачем вообще сортировать данные непосредственно ...   17.2.2009, 22:48
- - Rocky   Хм... Если речь идет о таблице с этими трубами, то...   17.2.2009, 23:02
|- - trdm   Цитата(Rocky @ 17.2.2009, 23:02) trdm, се...   18.2.2009, 1:06
- - Litkevich Yuriy   Rocky, если у тебя такая вещь:Цитата(Rocky @ ...   18.2.2009, 2:09
- - Константин   Цитата|ГРУППА_1| | | | ...   18.2.2009, 14:06
- - Rocky   По-поводу двойной выборки. Если убрать select(), т...   18.2.2009, 14:27
- - Константин   Цитата(Rocky @ 18.2.2009, 14:27) Так что ...   18.2.2009, 15:01
- - Rocky   В смысле сабмит? Сабмит ручной. Коммит я не знаю к...   19.2.2009, 0:51
- - Константин   для ManualSubmit в этих методах просто с базой раб...   19.2.2009, 1:17


Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 27.4.2024, 8:59