Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Не удается программно изменять значения модели БД
Форум на CrossPlatform.RU > Библиотеки > Qt > Qt Разработка баз данных
Rocky
Всем привет! Помогите пожалуйста с проблемкой... Создаю таблицу БД 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 темы создал случайно :(
Константин
О_о жесть какая :)

первое, что в глаза бросается:
pModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
pModel->setTable("PIPES");


второе: зачем вообще m_pDataTableView ?

третье: зачем QModelIndex oInsertIndex = m_pDataTableView->currentIndex(); ?

и, пожалуй, нулевое: почему не расставить индексы автоинкрементом сразу при создании таблицы?
Rocky
:)

0. Автоинкремент я до конца не понял как работает, а файл из которого таблицу формирую - это выгруженная база из MS Access (там счетчик уже есть), поэтому дописать одну строку несложно :)
1. хм... а в чем вопрос? ((

2. Таблиц несколько, чтобы каждому редактор не писать, я написал класс на основе формы, на которую положил QTableView. m_pDataTableView - это как раз экземпляр QTableView (которому я передаю указатель на свою модель).

//ф-я вызываемая для просмотра таблицы (класс CPipeDatabase, файл PipeDatabase.cpp)
void CPipeDatabase::ShowContent()
{
    QSqlTableModel *pModel = new QSqlTableModel();
    if (!pModel) return;

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

    pModel->setHeaderData(0, Qt::Horizontal, qApp->tr("ID"));
    //...
      pModel->setHeaderData(5, Qt::Horizontal, qApp->tr("..."));

    CDataBrowserDialog *pDataBrowserDialog = new CDataBrowserDialog(pModel);
    pDataBrowserDialog->exec();
}

//файл DataBrowserDialog.cpp
CDataBrowserDialog::CDataBrowserDialog(QSqlTableModel *pModel, QWidget* pParent) : QDialog(pParent)
{
    setupUi(this);

    m_pModel = pModel;
    m_pModel->setSort(0, Qt::AscendingOrder);

    m_pDataTableView->setModel(pModel);

    m_pDataTableView->setSelectionBehavior(QAbstractItemView::SelectRows);
    m_pDataTableView->setSelectionMode(QAbstractItemView::SingleSelection);
    
    //... - тут коннекты для кнопок
}


3. oInsertIndex затем, что я узнаю выделенную пользователем строку, чтоб затем добавить после нее новую строку
//файл DataBrowserDialog.cpp
//обработчик нажатия кнопки "добавить строку после выделенной строки"
void CDataBrowserDialog::OnAddRowAfter()
{
    QModelIndex oInsertIndex = m_pDataTableView->currentIndex();
    int nRow = oInsertIndex.row() == -1 ? 0 : oInsertIndex.row() + 1;
    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);
    }
}
SABROG
Цитата(Rocky @ 17.2.2009, 10:43) *
Затем нужно сделать ее редактирование, и при этом вставлять записи в нужное место (не обязательно в конец).


Нельзя запись вставить в нужное место, стандарт SQL этого не поддерживает. Максимум, что можно сделать:
- добавить столбец сортировки
- создавать каждый раз заново таблицу предварительно рассортировав элементы в нужном порядке где-то в памяти
Rocky
Цитата
добавить столбец сортировки

Так ведь я и пытаюсь добавить столбец сортировки (который id - целые числа), а при добавлении перенумеровывать эти id таким образом, чтобы вставленная запись оказалась в нужном месте...
Константин
0. обратиться к документации по склайт - прочитать про автоинкемент и не изобретать колеса
1. дважды происходит выборка данных, что чревато
2. индекс модели через вьюху и с ним дальнейшая работа - в данном случае не ах
3. обрабатывается с setValue("id", ...) не одна запись, а все - не пойму смысла вставки строки в произвольное место модели

советую уделить внимание пункту 0. и радоваться, что здесь не скл.ру )
Rocky
Стоп, не понял.
1. В каком месте происходит дважды выборка? когда назначаю таблицу (setTable) и когда назначаю модель (setModel)? Или где?
2. Что не так? Сами тролли в примере sqlbrowser примерно так и делают.
3. Насчет того что, не одна запись, а все. В смысле строка таблицы? Ну, а как тогда правильно изменить одно поле в одной строке? Так описано и в 2-х имеющихся у меня книгах по QT и в самой документации по QT (assistant).
Цитата
не пойму смысла вставки строки в произвольное место модели

Так мне надо перенумеровать все id... Если было по id 1 2 3 4 5 и мне нужно вставить между 2 и 3, сразу после вставки будет 1 2 _ 3 4 5
На месте "_" - пустое поле. Далее я перенумеровываю так, чтобы было 1 2 3 4 5 6. Т.е. вставленная запись получает номер 3, а записи после нее инкрементируются на 1 (3 4 5 становятся 4 5 6). Здесь я согласен от первой до последней записи нет смысла перенумеровывать, а только от вставленной и до последней. Но это как я понимаю должно только на производительность повлиять.

Ок, посмотрю че такое склайт, надеюсь это решение проблемы... Мне просто не понятно, весь код, который я привел взят из книг + assistant + исходник sqlbrowser... Никакой "отсебятины" вроде как нет... В то же время, при работе с этой самой таблицей PIPES даже sqlbrowser далеко не всегда удаляет или добавляет новые записи, а как-то через раз. Нихрена не понимаю. Я чувствую проще забить на модели, а просто сделать QTableWidget, который заполнять своей таблицей из БД напрямую, а при сохранении удалять старую таблицу в БД и формировать новую, из QTableWidget. Но это будет имхо некрасиво, не так быстро и изящно, чем простой вызов submitAll().
Константин
извини, но у тебя с самого начала некрасиво и неизящно :) т.к. вместо тривиального автоинкремента по PK (PRIMARY KEY), изобретаешь колесо.
кстати, проблема вполне может расти как раз из отсутствия PK, т.к. вместо поиска по уникальному ключу у тебя выполняется поиск по полному совпадению всех полей строки. а если таких строк больше одной? впрочем, не берусь утверждать об истоках проблемы, о которой знаю по трём сниппетам :)

ладно, вот твоя таблица:
QSqlQuery oQuery;
oQuery.exec("CREATE TABLE PIPES (id INTEGER PRIMARY KEY AUTOINCREMENT, PipeType varchar(50), D_outside varchar(20), d_inside varchar(20), "
                                    "Roughness varchar(20), Lamda varchar(20))");

лобызай :)
и упаси тебя божа снова пересчитывать уники таблицы в базе через вьюху - модель - запрос - таблицу в базе :)

ой-ой...чуть не попался! если тебе исходный ид из файла _действительно_ нужен, то используй дальше как раньше. но из описания того, что и как тебе хочется менять при добавлении строки, делаю вывод, что к уникам ты пока не привязываешься, а используешь их только для сортировки или чего-то подобного...в таком случае ид лучше не копировать из файла:
QSqlQuery oQuery;
oQuery.exec("CREATE TABLE PIPES (id INTEGER PRIMARY KEY AUTOINCREMENT, PipeType varchar(50), D_outside varchar(20), d_inside varchar(20), "
                                    "Roughness varchar(20), Lamda varchar(20))");

oQuery.prepare("INSERT INTO TABLE PIPES (PipeType, D_outside, d_inside, Roughness, Lamda) VALUES(: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);
    oQuery.exec();
}

...и тут бы ещё неплохо транзакцию добавить

ну, что? по возможности используй максимально короткие имена полей и таблиц скл; используй ключи для полей, по которым наиболее часто будет производиться поиск и сортировка...и не забывай, что кроме форума имеется множество полезных поисковых систем :)

ага, вот что ещё забыл:

Цитата(Rocky @ 17.2.2009, 16:37) *
1. В каком месте происходит дважды выборка? когда назначаю таблицу (setTable) и когда назначаю модель (setModel)? Или где?

pModel->setTable("PIPES"); // раз
pModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
pModel->select(); // два


Цитата(Rocky @ 17.2.2009, 16:37) *
2. Что не так? Сами тролли в примере sqlbrowser примерно так и делают.

переиндексирование таблицы через вьюху? не верю.
Rocky
:)
Цитата
кстати, проблема вполне может расти как раз из отсутствия PK, т.к. вместо поиска по уникальному ключу у тебя выполняется поиск по полному совпадению всех полей строки. а если таких строк больше одной?

Я так понимаю поиск по полному совпадению всех полей строки где-то внутри? Потому что явно я вроде как нигде не ищу ничего. Взятие i-й записи это ведь не поиск. Больше одной одинаковой строки в таблице быть не может. Ни физически, ни программно. Не может быть 2 трубы с одинаковыми маркировками (названиями) и характеристиками... но речь не об этом. По-поводу AUTOINCREMENT заватра на работу приеду, попробую так сделать.
Цитата
делаю вывод, что к уникам ты пока не привязываешься, а используешь их только для сортировки или чего-то подобного

Именно :). Мне "уники" вообще чесгря не нужны.... Мне сама БД-то нужно просто чтоб где-то хранить инфу, которую иногда придется изменять в удобной форме. В данном случае таблица труб (PIPES) - это просто таблица труб. Тут нет никаких соотношений один ко многим и пр (все намного проще, да и здесь это ни к чему - есть просто список труб, все.). Ну, если по правилам хорошего тона )) нужны именно ключи к каждой строке таблицы, ок, пусть будут. Я не программист Баз Данных, и никогда им не был. SQL и все что с ним связано знаю на уровне домохозяйки :)

Цитата
...и тут бы ещё неплохо транзакцию добавить

Она есть, спасибо. Тут опустил, т.к. она вроде как не имеет отношения к теме.

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

ок. Только вот поиска у меня не будет никакого по таблице. БД - это просто хранилище информации, которую программа считывает при запуске и хранит ее в своих внутренних структурах/классах/контейнерах (в основном std::set). И поиск ведется уже средствами самого std::set, и здесь есть уникальное поле.

2.
Цитата
индекс модели через вьюху и с ним дальнейшая работа - в данном случае не ах

//файл browser.cpp      QTDIR/demos/sqlbrowser
//table - объект QTableView
void Browser::insertRow()
{
    QSqlTableModel *model = qobject_cast<QSqlTableModel *>(table->model());
    if (!model)
        return;

    QModelIndex insertIndex = table->currentIndex();
    int row = insertIndex.row() == -1 ? 0 : insertIndex.row();
    model->insertRow(row);
    insertIndex = model->index(row, 0);
    table->setCurrentIndex(insertIndex);
    table->edit(insertIndex);
}
Константин
/* от дурная башка */ ...сначала просто поинтересовался "почему так?", потом, не глядя на код выше, три перекочевало в два, а теперь уже хрен знает отчего я это ляпнул...дожно быть, что-то показалось )

Цитата(Rocky @ 17.2.2009, 20:03) *
Ну, если по правилам хорошего тона )) нужны именно ключи к каждой строке таблицы, ок, пусть будут.

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

ок. Только вот поиска у меня не будет никакого по таблице. БД - это просто хранилище информации, которую программа считывает при запуске и хранит ее в своих внутренних структурах/классах/контейнерах (в основном std::set). И поиск ведется уже средствами самого std::set, и здесь есть уникальное поле.

тут не просто правила хорошего тона. поиска может и не будет, а редактировать записи предполагается - склтаблмодель будет работать значительно эффективнее с таблицами, имеющими PK, чем с таблицами, таковых не имеющими. в частности ведь гораздо проще и быстрее обработать `WHERE id=5`, чем `WHERE id=5 AND PipeType=uhpoiuhfp AND D_outside=hopwojdpeo AND d_inside=joifjweoq AND Roughness=idjidj AND Lamda=lamda`
Rocky
:) Не, критика это хорошо )) Правда если она здравая :)

Цитата
...в частности ведь гораздо проще и быстрее обработать `WHERE id=5`, чем `WHERE id=5 AND...

Абсолютно согласен. Да, и спасибо за замечание насчет двойной выборки данных... Действительно косяк.
Вобщем, поробую добавить 2 столбца. 1 pm с автоинкрементом, а 2-й просто целые числа для сортировки записей таблицы. Но, боюсь, это ничего не изменит... Утром будет видно...
SABROG
Цитата(Rocky @ 17.2.2009, 21:31) *
Но, боюсь, это ничего не изменит


Я так и делал и все работало нормально. Но тут надо четко понимать, что количество записей в таблице не должно быть слишком много, иначе кирдык. Например у меня на работе MSSQL сервер, где 50 миллионов записей в каждой из 6 таблиц. Если я буду делать такие update'ы пересортировочные, то бизнес загнется :)
Rocky
Цитата
50 миллионов записей

:wacko:
Офигеть.....А как в таких случаях быть? Просто интересно, или там новые записи достаточно в конец добавлять?
Константин
а зачем вообще сортировать данные непосредственно в таблице бд? в данном конкретном случае это действительно нужно?
trdm
Цитата(Rocky @ 17.2.2009, 22:38) *
.....или там новые записи достаточно в конец добавлять?

Кажись понял в чем проблема.
Тебе необходимо поштудировать доки по проектированию ИС.
По теории баз данных.
Тут пара полезных курсов: http://www.intuit.ru/catalog/database/
Начни с этого: http://www.intuit.ru/department/database/dbmdi/
Я нечто подобное в колледже проходил. Несмотря на занудные и порою непонятные названия, эта фигня до сих пор значительно помогает.
Rocky
Хм... Если речь идет о таблице с этими трубами, то нет... Но есть таблицы, например с материалами разными.... Там есть группа, есть подгруппа, а есть сами материалы с разными физическими свойствами. Может быть по-хорошему имеет смысл делать отдельно таблицу групп, таблицы подгрупп, таблицы свойств и связывать их через ключи и соотношения 1:N и пр (помню только примерно, базовый курс в универе тока был давно). Но я делаю так (строки таблицы):
|ГРУППА_1|           |               |
|        |ПОДГРУППА_1|               |
|        |           | свойство_1    |
|        |           | свойство_2    |
|        |           | свойство_3    |
|        |ПОДГРУППА_2|               |
|        |           | свойство_1    |
|        |           | свойство_2    |
|        |           | свойство_3    |
|ГРУППА_2|           |               |
|        |ПОДГРУППА_1|               |
|        |           | свойство_1    |
|        |           | свойство_2    |

.......

И пользователю может понадобиться добавить новое свойство для подгруппы 2 например. Если не делать сорировку, то это добавленное свойство перенесется в самый конец, и будет относится не к подгруппе2, а к подгуппе10, например, что будет полной чушью.


---Добавлено позже---
trdm
:)
спасибо, сейчас посмотрим.
trdm
Цитата(Rocky @ 17.2.2009, 23:02) *
trdm, сейчас посмотрим.


ага, судя по тому, что ты написал тебе надо хорошо поработать с сущностями этих групп, подгрупп.
я таки и не понял, свойства группы являются так-же и свойствами подгрупп, у которых эта группа - владелец. Или нет.
это вопрос надо выяснить очень внимательно.
Litkevich Yuriy
Rocky, если у тебя такая вещь:
Цитата(Rocky @ 18.2.2009, 2:02) *
Там есть группа, есть подгруппа, а есть сами материалы с разными физическими свойствами.
то лучше всетаки замарочится изучением SQL/СУБД, хранить это в памяти ты можешь сегодня, но завтра уже не сможешь.
Цитата(Rocky @ 18.2.2009, 1:38) *
Просто интересно, или там новые записи достаточно в конец добавлять?
всегда в БД ПРОСТО ДОБАВЛЯЮТ записи, а место положение записи в таблицы значения не имеет, значение имеет результат выборки, тут место будет определятся запросом.

То что ты пытался сделать - вставить запись в определенное место - есть внутренняя механника СУБД под названием индексация, по конкретному полю (столбцу).
Константин
Цитата
|ГРУППА_1| | |
| |ПОДГРУППА_1| |
| | | свойство_1 |

разделить таблицу на три (группа, подгруппа, свойство) и связать их по foreign keys. такой структуры будет достаточно для линейной вложенности - это простой способ.
для вложенности подгрупп в разные группы; для вложенности групп в группы и подгрупп в группы/подгруппы нужен совсем другой подход с таблицами отношений и ограничений. но кажется, тебе подходит простой вариант.
Rocky
По-поводу двойной выборки. Если убрать 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 @ 18.2.2009, 14:27) *
Так что выборка происходит все-таки один раз.

аха, я уже освежил память. это было по поводу двойной выборки для уже подготовленной модели (http://www.prog.org.ru/topic_7459_0.html)

Цитата(Rocky @ 18.2.2009, 14:27) *
да, при формировании таблицы, колонка ID сама заполняется. А при добавлении новой строки в QTableView - нет.

заполнится после внесения в базу (submitAll)

политика ведь на ручной коммит? зачем тогда QSqlDatabase::database().transaction()/QSqlDatabase::database().commit() в каждом методе?
Rocky
В смысле сабмит? Сабмит ручной. Коммит я не знаю какой... может тоже ручной :(. При ручном сабмите не нужны транзкции?
Константин
для ManualSubmit в этих методах просто с базой работа не происходит - чтение в select и запись в submit
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2024 IPS, Inc.