Russian Qt Forum

Qt => Базы данных => Тема начата: xokc от Сентябрь 22, 2014, 20:47



Название: QSqlQueryModel и нормальный refresh
Отправлено: xokc от Сентябрь 22, 2014, 20:47
Как сделать нормальный, "обычный" refresh QTableVeiw, прицепленного к QSqlQueryModel?
Что имею ввиду под "нормальным":
1. собственно обновление изменившихся данных (новые/удаленные/изменившиеся строки) - это собственно сделано;
2. восстановление текущей позиции в QTableView - сделано, если текущая строка присутствует в обновленной модели;
3. если текущая строка в обновленной модели отсутствует - позиционироваться на следующую, если следующих нет тоже, то - на предыдущую.
Например, были такие строки:
1
2
3
4
5 - эта текущая
6
7

После обновления остались строки:
1
3
6 - эта должна стать текущей
7

Пока ничего лучшего придумать не могу кроме как, до обновления сохранять ключи для всех строки модели, перечитывать её, и потом в обновленной искать нужный индекс. Но, как-то этот из пушки по воробьям. Кто-нибудь предложит что-нибудь более совершенное?


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: Bepec от Сентябрь 23, 2014, 07:51
Запоминать номер строки? Если у вас нет удаления нескольких записей, то вполне можно по номеру строки ориентироваться.


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: xokc от Сентябрь 23, 2014, 19:26
С чего вы взяли, что нет удаления нескольких записей? Это самая обычная многопользовательская БД - пользователи творят, что хотят и добавляют сколько им вздумается и удаляют, соответственно. Так что вариант с номерам строки не проходит однозначно. Как-то же оно реализовано в том же delphi, например. Там никогда вообще не задумывался над этим - всё идеально работало "из коробки" на даже самой банальной связке из DataSource и Grid, не говоря уже о продвинутых комбинациях типа FIBPlus + DevExpress. Тут же, даже чтобы банально обновить изменившееся в БД значение приходится весь query переустанавливать. Лучше бы вместо своих qml свистоперделок нормальный DB MVC сделали, а не этот костыль. Накипело, блин.


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: Figaro от Сентябрь 23, 2014, 19:54
Первичный ключ запоминайте...


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: xokc от Сентябрь 23, 2014, 22:49
И что мне с этого ключа? Вы пример мой смотрели? Что делать если запись с этим ключом удалили?


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: Igors от Сентябрь 24, 2014, 07:18
Так что вариант с номерам строки не проходит однозначно.
Не понял почему. Если номера удаляемых/вставляемых строк известны - что мешает пересчитать номер после выполнения операции ?


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: xokc от Сентябрь 24, 2014, 08:04
Если номера удаляемых/вставляемых строк известны - что мешает пересчитать номер после выполнения операции ?
Дак откуда мне они известны? Да и что такое "номер строки"? Приложения работают на разных компах, пользователи сортируют таблицы как угодно. Строка номер 2 у одного пользователя может означать что угодно у другого!


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: Old от Сентябрь 24, 2014, 08:17
угодно. Строка номер 2 у одного пользователя может означать что угодно у другого!
Нужно уметь определять номер записи по уникальному id и id по номеру записи.
Перед рефрешем - определяете по номеру выбранной строки id записи, делаете рефрш, а после - находите по этому id номер строки.


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: xokc от Сентябрь 24, 2014, 08:31
Ну опять - посмотрите пример из первого поста. Перед рефреш у меня id текущей записи = 5, текущий № строки = 5. После рефреша получаю набор записей, в котором нет id=5 (кстати как именно мне это определить? на клиенте делать model->match() или на сервере в рамках транзакции исполнять ХП, которая перебирает записи в поиске номера строки?). И вот когда нет у меня после рефреш записи с запомненным id = 5 как мне встать на ту строку, которую я ожидаю увидеть (а именно № 4)?


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: Old от Сентябрь 24, 2014, 10:53
Ну опять - посмотрите пример из первого поста.
А для таких манипуляций, вам придется хранить табличку соответствий row - id до рефреша.

До:
1 - 62
2 - 63
3 - 91
4 - 43
5 - 12 - текущая
6 - 23
7 - 24

После:
1 - 62
2 - 91
3 - 23
4 - 24

Мы знаем, что до рефреша текущей была строка с id = 12, пытаемся найти такую запись в выборке после, такой записи нет.
Лезем в таблицу "До" и смотрим id следующей записи id = 23 - пытаемся найти ее в результирующей выборке - нашли, это row = 3.


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: OKTA от Сентябрь 24, 2014, 11:05
Что-то я понять не могу, в чем проблема сделать запрос, который будет искать запись с нужным id, а если такой записи нет, то брать следующую по возрастанию или предыдущую при отсутствии записей с большим id??


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: xokc от Сентябрь 24, 2014, 13:25
Мы знаем, что до рефреша текущей была строка с id = 12, пытаемся найти такую запись в выборке после, такой записи нет.
Лезем в таблицу "До" и смотрим id следующей записи id = 23 - пытаемся найти ее в результирующей выборке - нашли, это row = 3.
В чем проблема сделать запрос, который будет искать запись с нужным id, а если такой записи нет, то брать следующую по возрастанию или предыдущую при отсутствии записей с большим id??
Этот-то вариант понятен его я и имел ввиду когда говорил в первом посте про "до обновления сохранять ключи для всех строки модели, перечитывать её, и потом в обновленной искать нужный индекс".
Но при этом мне нужно:
1. Хранить результат выборки до обновления с учетом всех манипуляций, которые умудрился над запросом совершит пользователь (сортировки и фильтрации на клиенте). Допустим это QList<int> oldKeys с ключами записей.
2. После обновления проверять в ней наличие (и снова - как проверять: через model->match()?) ключа текущей записи. Если её там нет - крутить цикл по oldKeys вниз от текущей строки до обнаружения в новой модели очередного ключа. Если такой не найдется, то делать тоже самое вверх по oldKeys. Если опять ничего не найдется - то позиционироваться на первой записи.
Но это же трындец! А если у меня запрос возвращает не 20, а 2000 записей? Это же банальный обычный refresh!!! Кто-то (что-то) это же делает в других фреймворках! Почему в Qt это всё должен делать я сам? Требую метод refresh на уровне QTableView!!!


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: Old от Сентябрь 24, 2014, 13:39
А если у меня запрос возвращает не 20, а 2000 записей?
Список из 2000 64-битных id это 128Кб памяти. :)

Кто-то (что-то) это же делает в других фреймворках!
Да как-то так и делают, только спрятано это под капотом.

Почему в Qt это всё должен делать я сам? Требую метод refresh на уровне QTableView!!!
Можно требовать или сделать один раз свою модель для работы с БД. :)


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: xokc от Сентябрь 24, 2014, 17:08
Список из 2000 64-битных id это 128Кб памяти. :)
Дело то не в объемах памяти. А в том, что мне придется обновленную модель прогонять (кстати, так и никто и не предложил как это делать "правильно") достаточно большое количество раз на предмет поиска в ней "наиболее меня устраивающего" (в смысле "ближайшего") к искомому id. А если в модели присутствуют блобы? Боюсь тогда fetch для всех её записей в рамках исполнения model->match() может "несколько затянуться". Ну а если этих записей вдруг станет 20000?

Можно требовать или сделать один раз свою модель для работы с БД. :)
Можно и сделать. Но так можно и до собственной ОС докатиться. Хочется решать прикладные задачи, а не реализовывать такие свои модели, тем более что была надежда на то, что кто-то это сделает за (и лучше) меня.


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: Igors от Сентябрь 25, 2014, 10:30
Допустим это QList<int> oldKeys с ключами записей.
Напрашивается аналогичный newKeys считываемый после обновления, а дальше сравнение 2 массивов. И лучше напр QMap. После восстановления selection oldLКeys замещается на newKeys. Если модель обновляется извне - ничего лучшего не видно. В общем случае нет "ID записи", поэтому рассчитывать на сервис не приходится.

Но это же трындец! А если у меня запрос возвращает не 20, а 2000 записей? Это же банальный обычный refresh!!! Кто-то (что-то) это же делает в других фреймворках! Почему в Qt это всё должен делать я сам? Требую метод refresh на уровне QTableView!!!
Вот это и есть обратная сторона Qt :) Что-то сделать руками - уже западло. В конце-концов остаются "ручки", и это плохо. Считайте что Вы получили "заряд бодрости"  :)


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: GreatSnake от Сентябрь 25, 2014, 10:47
1. собственно обновление изменившихся данных (новые/удаленные/изменившиеся строки) - это собственно сделано;
Есть подозрение, что если нормально обновлять модель (испускать соответствующие сигналы), то вью сама должна нормально позиционировать текущий элемент и вьюпорт.


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: xokc от Сентябрь 25, 2014, 13:07
если нормально обновлять модель (испускать соответствующие сигналы), то вью сама должна нормально позиционировать текущий элемент и вьюпорт.
И ещё раз: есть 2 разных компа с моими приложениями. На PC1 пользователь удалил запись, которая является в этот момент текущей во вью на PC2. Кто, кому и какой должен испустить сигнал, чтобы при обновлении вью на PC2 текущей стала "ожидаемая строка"?


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: Old от Сентябрь 25, 2014, 13:10
И ещё раз: есть 2 разных компа с моими приложениями. На PC1 пользователь удалил запись, которая является в этот момент текущей во вью на PC2. Кто, кому и какой должен испустить сигнал, чтобы при обновлении вью на PC2 текущей стала "ожидаемая строка"?
У меня база посылает уведомление о изменении таблицы (добавление/изменение/удаление записи) и все модели на всех рабочих местах добавляют/перечитывают/удаляют нужную строку.
База postgresql.


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: GreatSnake от Сентябрь 25, 2014, 13:18
И ещё раз: есть 2 разных компа с моими приложениями. На PC1 пользователь удалил запись, которая является в этот момент текущей во вью на PC2. Кто, кому и какой должен испустить сигнал, чтобы при обновлении вью на PC2 текущей стала "ожидаемая строка"?
Каким образом обновляется модель на PC2?


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: Hellraiser от Сентябрь 25, 2014, 13:25
У меня база посылает уведомление о изменении таблицы (добавление/изменение/удаление записи) и все модели на всех рабочих местах добавляют/перечитывают/удаляют нужную строку.
База postgresql.
Таковым механизмом обладают далеко не все СУБД. В таком случае - либо кнопка рефреша, либо костыль с таймером.
У меня при выборе СУБД для проекта наличие механизма нотификации дало серьезное преимущество для Постгре.


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: xokc от Сентябрь 25, 2014, 13:26
Каким образом обновляется модель на PC2?
По нажатию кнопки "Refresh".

У меня база посылает уведомление о изменении таблицы.
Уходим в сторону от изначального вопроса, который заключался не в этом, а в том, как "ожидаемо" спозиционироваться на строку после рефреша, если предыдущая текущая запись была удалена. Плюс мне такой подход с автоматическим обновлением по уведомлению об изменении не подойдет: изменения происходят слишком часто - в этом режиме работать с таблицей будет невозможно. Кстати, как узнаёте, что инициатором изменения была текущая модель, и, следовательно, специально обновляться не надо?


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: GreatSnake от Сентябрь 25, 2014, 13:27
Таковым механизмом обладают далеко не все СУБД. В таком случае - либо кнопка рефреша, либо костыль с таймером.
Мало того, ни каждая система и клиент может выдержать нагрузку используя такой механизм.


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: GreatSnake от Сентябрь 25, 2014, 13:29
По нажатию кнопки "Refresh".
Ну что за ответ ???
Тебе хотят помочь, а ты кривляешься. Как-то даже не серьёзно.  :(


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: xokc от Сентябрь 25, 2014, 13:39
По нажатию кнопки "Refresh".
Ну что за ответ ???
Тебе хотят помочь, а ты кривляешься. Как-то даже не серьёзно.  :(
Ну какой вопрос, такой и ответ :). Ничуть не кривлялся. Если вопрос был о механизме обновления, а не о его инициаторе (а я его понял именно так :)), то - так, как это сделано в примере из состава Qt (examples\sql\querymodel\editablesqlmodel.cpp), а именно:
Код
C++ (Qt)
void EditableSqlModel::refresh()
{
   setQuery("select ...");
}
Тебе хотят помочь
От помощи не откажусь и буду благодарен - для того и вопрос задавал.


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: GreatSnake от Сентябрь 25, 2014, 13:56
Получается, что модель при обновлении полностью чистится. Поэтому вью тоже сбрасывается.
Тут есть 2 решения, либо написать свою модель с нормальным рефрешем либо держать 2 QSqlQueryModel-и.
Первая основная, а вторая временная для валидации первой.


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: Old от Сентябрь 25, 2014, 13:59
Кстати, как узнаёте, что инициатором изменения была текущая модель, и, следовательно, специально обновляться не надо?
У меня все действия с таблицей можно выполнять только через методы модели, поэтому внутримодельного флага достаточно.
Я не использую Qt-модели для работы с базами, сразу написал свои со всякими "плюшками".


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: Old от Сентябрь 25, 2014, 14:02
Получается, что модель при обновлении полностью чистится. Поэтому вью тоже сбрасывается.
Тут есть 2 решения, либо написать свою модель с нормальным рефрешем либо держать 2 QSqlQueryModel-и.
Первая основная, а вторая временная для валидации первой.
Достаточно хранить список с уникальными id записей. Перед рефрешем заполняем его, после смотрим что изменилось.


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: GreatSnake от Сентябрь 25, 2014, 14:07
Достаточно хранить список с уникальными id записей. Перед рефрешем заполняем его, после смотрим что изменилось.
Да, так будет ещё оптимальнее.


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: xokc от Сентябрь 25, 2014, 14:13
Спасибо за ответы, вижу, что простого решения нет - жаль. Ну и пользуясь случаем: у меня в модели есть "вычисляемое" поле, то есть то поле, которого нет в БД (значение из модели отдается через model::data()). Как мне при его изменении (не средствами View) наиболее правильно оповестить View о том, что надо бы это значение перерисовать без полного refresh (как сделано в примере editablemodel) модели?


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: GreatSnake от Сентябрь 25, 2014, 14:20
Код
C++ (Qt)
QTableVeiw::viewport()->update();
QTableVeiw::viewport()->update( QTableVeiw::visualRect( index ) );


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: Old от Сентябрь 25, 2014, 14:24
Как мне при его изменении (не средствами View) наиболее правильно оповестить View о том, что надо бы это значение перерисовать без полного refresh (как сделано в примере editablemodel) модели?
Модель должна послать сигнал:
void QAbstractItemModel::dataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight, const QVector<int> & roles = QVector<int> ()) [signal]


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: xokc от Сентябрь 25, 2014, 16:25
Ок, благодарю. Буду пробовать.


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: panAlexey от Сентябрь 30, 2014, 22:24
С чего вы взяли, что нет удаления нескольких записей? Это самая обычная многопользовательская БД - пользователи творят, что хотят и добавляют сколько им вздумается и удаляют, соответственно.

а вот это не гуд. лучше не удалять, а помечать на удаление и чистить с контролем ссылочной целкости.


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: panAlexey от Сентябрь 30, 2014, 22:27
1. собственно обновление изменившихся данных (новые/удаленные/изменившиеся строки) - это собственно сделано;
Есть подозрение, что если нормально обновлять модель (испускать соответствующие сигналы), то вью сама должна нормально позиционировать текущий элемент и вьюпорт.
На одном компе обновили, у другого вьюв отткрыт. Ваши действия?


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: xokc от Октябрь 01, 2014, 20:02
а вот это не гуд. лучше не удалять, а помечать на удаление и чистить с контролем ссылочной целкости.
Чем же это "не гуд"? Во-первых пометка к удалению вместо собственно удаления ну никак не решит мою проблему, а во-вторых пусть уж хоть этим занимается не приложение, а СУБД (с чем, общем он вполне успешно справляется).


Название: Re: QSqlQueryModel и нормальный refresh
Отправлено: GreatSnake от Октябрь 02, 2014, 09:50
а вот это не гуд. лучше не удалять, а помечать на удаление и чистить с контролем ссылочной целкости.
Во-первых пометка к удалению вместо собственно удаления ну никак не решит мою проблему
Ещё как решит, т.к. не будет полной перезаливки модели и вью в таком случае сама всё сделает.