Кеширование TSQLQuery - как отключить?
Модератор: Модераторы
Кеширование TSQLQuery - как отключить?
Подскажите пожалуйста как с ним (TSQLQuery) нормально работать с кешем или как его (кеш) отключить? Что-то я после Delphi слегка в шоке.
Поясню - есть форма с полями DBEdit. Хочу при изменении полей пользователем показывать кнопку Сохранить, а при сохранении убирать ее.
В Delphi это делалось в одном месте в TDataSource.OnChangeState, а-ля Button.Visible = Query.State = dsEdit; тут не получается, так как запись сохраняется в кеш, а применяется уже потом, а ошибку у меня выдает база данных.
Хорошо, делаю показ кнопки в TDataSource.OnChangeState, в TSQLQuery.OnAfterPost пишу Query.ApplyUpdates; Button.Visible := false;
Вроде работает, если не прошло сохранение, кнопка остается активной, но вот беда - теперь при ошибке Query в состоянии dsBrowse, повторное нажатие сохранения ничего не сохраняет (А очень хочется получить ту же ошибку повторно) и надо датасет вручную переключать в dsEdit (и я так понимаю слабая гарантия, что он остался на нужной записи) и что он вообще что-то будет сохранять, так как формально ничего не изменилось в записи б), то есть еще и желательно все поля пометить как измененные). Геморрой.
Вот как это делать правильно и проще, подскажите плиз? Пока пользы в кеше не вижу, зато вижу один вред.
Поясню - есть форма с полями DBEdit. Хочу при изменении полей пользователем показывать кнопку Сохранить, а при сохранении убирать ее.
В Delphi это делалось в одном месте в TDataSource.OnChangeState, а-ля Button.Visible = Query.State = dsEdit; тут не получается, так как запись сохраняется в кеш, а применяется уже потом, а ошибку у меня выдает база данных.
Хорошо, делаю показ кнопки в TDataSource.OnChangeState, в TSQLQuery.OnAfterPost пишу Query.ApplyUpdates; Button.Visible := false;
Вроде работает, если не прошло сохранение, кнопка остается активной, но вот беда - теперь при ошибке Query в состоянии dsBrowse, повторное нажатие сохранения ничего не сохраняет (А очень хочется получить ту же ошибку повторно) и надо датасет вручную переключать в dsEdit (и я так понимаю слабая гарантия, что он остался на нужной записи) и что он вообще что-то будет сохранять, так как формально ничего не изменилось в записи б), то есть еще и желательно все поля пометить как измененные). Геморрой.
Вот как это делать правильно и проще, подскажите плиз? Пока пользы в кеше не вижу, зато вижу один вред.
Неужто никто не пользуется TSQLQuery & Firebird? (
Попробую переформулировать: триггер базы данных (Firebird) не дает обновлять данные, если что-то в них ошибочно.
При этом в интерфейсе я хочу, чтобы человек не смог уйти с ошибочной записи (И даже не смог ее сохранить!) пока не исправит ошибку. Как это можно сделать?
Попробую переформулировать: триггер базы данных (Firebird) не дает обновлять данные, если что-то в них ошибочно.
При этом в интерфейсе я хочу, чтобы человек не смог уйти с ошибочной записи (И даже не смог ее сохранить!) пока не исправит ошибку. Как это можно сделать?
- Лекс Айрин
- долгожитель
- Сообщения: 5723
- Зарегистрирован: 19.02.2013 16:54:51
- Откуда: Волгоград
- Контактная информация:
Nick74,А можно ли изменять размер кеша? Тогда его можно попытаться сделать равным нулю (или, для самых умных, 1). Это наверняка вызовет необходимость его отключения. Или игнор. Вообще, можно посмотреть исходники и поискать есть ли подобный функционал в наличии.
Лекс Айрин
Сомнительно, нигде не видел размера кеша. Да и по коду ясно, что так не решишь.
Покопался в исходниках, нашел нужное место.
Как видно, TCustomSQLQuery.Post сначала вызывает TDataSet.Post, а только затем применяет ApplyUpdates (В режиме AutoApplyUpdates).
Внутри TDataSet.Post также видно, что идет запись в кеш, смена позиции курсора, изменение статуса датасета, и только после этого AfterPost.
При этом, я так понимаю, операции с БД выполняются в ApplyUpdates и откатить операцию ну никак не могут.
Блиииин, как я привык к ошибкам, возвращаемым SQL-базой ((( Неужели никто этим не пользуется? Пошел копаться в сторонних компонентах...
Сомнительно, нигде не видел размера кеша. Да и по коду ясно, что так не решишь.
Покопался в исходниках, нашел нужное место.
Как видно, TCustomSQLQuery.Post сначала вызывает TDataSet.Post, а только затем применяет ApplyUpdates (В режиме AutoApplyUpdates).
Внутри TDataSet.Post также видно, что идет запись в кеш, смена позиции курсора, изменение статуса датасета, и только после этого AfterPost.
При этом, я так понимаю, операции с БД выполняются в ApplyUpdates и откатить операцию ну никак не могут.
Блиииин, как я привык к ошибкам, возвращаемым SQL-базой ((( Неужели никто этим не пользуется? Пошел копаться в сторонних компонентах...
Код: Выделить всё
procedure TCustomSQLQuery.Post;
begin
inherited Post;
If (sqoAutoApplyUpdates in Options) then
ApplyUpdates;
end;
procedure TDataSet.Post;
begin
UpdateRecord;
if State in [dsEdit,dsInsert] then
begin
DataEvent(deCheckBrowseMode,0);
DoBeforePost;
If Not TryDoing(@InternalPost,OnPostError) then exit; // <-- Тут запись в кеш
cursorposchanged;
FreeFieldBuffers;
SetState(dsBrowse);
Resync([]);
DoAfterPost; // <-- Тут можно вызвать ApplyUpdates вручную, только поздно уже. Статус датасета изменен, курсор сдвинут и все такое
end
else if State<>dsSetKey then
DatabaseErrorFmt(SNotEditing, [Name], Self);
end; alexs
Если недопустимость данных - больше нуля или не пустое или в списке ('A','B'), то возможно.
А если недопустимость зависит от других таблиц? Скажем вы вводите операцию расхода в бухгалтерии, а программа должна проверить не превышают ли введенные данные наличную сумму на счету, что, естественно, хранится в другой таблице или таблицах. Ну не будете же вы на стороне клиента делать запросы к трем другим таблицам?
А если недопустимо повтор записи? То есть стоит уникальный индекс в базе данных? Что тогда?
Хотя я привык почти все делать в БД (Триггерах или структуре) независимо от проверки со стороны клиента. Допустим, какое-то поле в БД меняется с NULL на NOT NULL, а в программе я забыл в описании поля указать Required.
С TSQLQuery получается "замечательно" - запись сохранилась, и только потом по сути асинхронно где-то там ругнулось "Ой, апдейт то не прошел". А Датасет уже тю-тю, dsBrowse блин, да и запись может быть уже не та активная.
Пойду посмотрю ZEOS, спасибо за подсказку.
Если недопустимость данных - больше нуля или не пустое или в списке ('A','B'), то возможно.
А если недопустимость зависит от других таблиц? Скажем вы вводите операцию расхода в бухгалтерии, а программа должна проверить не превышают ли введенные данные наличную сумму на счету, что, естественно, хранится в другой таблице или таблицах. Ну не будете же вы на стороне клиента делать запросы к трем другим таблицам?
А если недопустимо повтор записи? То есть стоит уникальный индекс в базе данных? Что тогда?
Хотя я привык почти все делать в БД (Триггерах или структуре) независимо от проверки со стороны клиента. Допустим, какое-то поле в БД меняется с NULL на NOT NULL, а в программе я забыл в описании поля указать Required.
С TSQLQuery получается "замечательно" - запись сохранилась, и только потом по сути асинхронно где-то там ругнулось "Ой, апдейт то не прошел". А Датасет уже тю-тю, dsBrowse блин, да и запись может быть уже не та активная.
Пойду посмотрю ZEOS, спасибо за подсказку.
Nick74 передавайте привет транзакциям... Или они уже не могут делать "откат"?
программа? А я, почему то считал что это делается на стороне сервера. И программа как бы ничего и не должна.а программа должна проверить не превышают ли введенные данные наличную сумму на счету, что, естественно, хранится в другой таблице или таблицах.
pupsik
Под "Откатом" я имел ввиду откат состояния датасета и грида, то бишь чтобы они вернулись в режим редактирования. Откатывать в базе данных ничего не надо, так как операция редактирования прервана триггером/нарушением уникальности индекса.
По поводу "Программы" - я имел ввиду функционал, который программа должна выполнять. И как раз и ругался на то, что логика на сервере не может прервать POST кешированного датасета.
То есть: есть редактируемый TDBEdit (TDBGrid, неважно) с неким полем из таблицы БД, на которой на сервере уникальный индекс.
При редактировании этой колонки и нажатии "Сохранить" в TSQLQuery корректно происходит POST, смена состояния на dsBrowse, возможно смещение на следующую запись (В случае грида), и только потом происходит ApplyUpdates, который получает ошибку нарушения индекса. Логичное действие при этом в интерфейсе - не давать уходить с сохраняемой записи, пока не будет введено допустимое значение поля.
Для этого мне надо вручную: найти нужную запись в гриде (Мы ведь ушли с сохраненной, скажем стрелочкой), переместиться к ней, перейти в режим редактирования, возможно еще "изменить" ранее редактировавшиеся поля (в противном случае повторный Post, подозреваю, ничего не сохранит - впрочем не проверял, но допускаю, что работает именно так). Все это не нужно было бы, если бы не работало кеширование изменений.
Добавлено спустя 7 минут 43 секунды:
Re: Кеширование TSQLQuery - как отключить?
Посмотрел другие компоненты. Проблемы с кешированием больше нет нигде. Пока в процессе выбора.
UIB - нет совместимого с TDataSource редактируемого элемента. То бишь редактируемый грид не делается?
IBX - глюки с UTF8 даже в design режиме.
Zeos - пока тестирую..
Под "Откатом" я имел ввиду откат состояния датасета и грида, то бишь чтобы они вернулись в режим редактирования. Откатывать в базе данных ничего не надо, так как операция редактирования прервана триггером/нарушением уникальности индекса.
По поводу "Программы" - я имел ввиду функционал, который программа должна выполнять. И как раз и ругался на то, что логика на сервере не может прервать POST кешированного датасета.
То есть: есть редактируемый TDBEdit (TDBGrid, неважно) с неким полем из таблицы БД, на которой на сервере уникальный индекс.
При редактировании этой колонки и нажатии "Сохранить" в TSQLQuery корректно происходит POST, смена состояния на dsBrowse, возможно смещение на следующую запись (В случае грида), и только потом происходит ApplyUpdates, который получает ошибку нарушения индекса. Логичное действие при этом в интерфейсе - не давать уходить с сохраняемой записи, пока не будет введено допустимое значение поля.
Для этого мне надо вручную: найти нужную запись в гриде (Мы ведь ушли с сохраненной, скажем стрелочкой), переместиться к ней, перейти в режим редактирования, возможно еще "изменить" ранее редактировавшиеся поля (в противном случае повторный Post, подозреваю, ничего не сохранит - впрочем не проверял, но допускаю, что работает именно так). Все это не нужно было бы, если бы не работало кеширование изменений.
Добавлено спустя 7 минут 43 секунды:
Re: Кеширование TSQLQuery - как отключить?
Посмотрел другие компоненты. Проблемы с кешированием больше нет нигде. Пока в процессе выбора.
UIB - нет совместимого с TDataSource редактируемого элемента. То бишь редактируемый грид не делается?
IBX - глюки с UTF8 даже в design режиме.
Zeos - пока тестирую..
Упс..
Добавлено спустя 1 час 7 минут 33 секунды:
Я делал в Action1.Enabled:=Query.State in [dsEdit,dsInsert];
Добавлено спустя 10 минут 23 секунды:
А если попробывать так?
SQLQuery1.DisableControls;
.. сохраняем..
SQLQuery1.EnableControls;
Добавлено спустя 1 час 7 минут 33 секунды:
Nick74 писал(а):Поясню - есть форма с полями DBEdit. Хочу при изменении полей пользователем показывать кнопку Сохранить, а при сохранении убирать ее.
Я делал в Action1.Enabled:=Query.State in [dsEdit,dsInsert];
Добавлено спустя 10 минут 23 секунды:
А если попробывать так?
SQLQuery1.DisableControls;
.. сохраняем..
SQLQuery1.EnableControls;
- alexs
- долгожитель
- Сообщения: 4066
- Зарегистрирован: 15.05.2005 23:17:07
- Откуда: г.Ставрополь
- Контактная информация:
Nick74 писал(а):UIB - нет совместимого с TDataSource редактируемого элемента. То бишь редактируемый грид не делается?
Для него надо взять мой FBDataSet. Автор не стал развивать свой из за него.
Nick74 писал(а):Zeos - пока тестирую..
Хороший комбайн. Но для птицы там нет полного контроля над транзакциями.
Сам им пользуюсь для всего, кроме птицы.
olegy123 писал(а):Я делал в Action1.Enabled:=Query.State in [dsEdit,dsInsert];
А если попробывать так?
SQLQuery1.DisableControls;
.. сохраняем..
SQLQuery1.EnableControls;
А смысл? Состояние и текущую запись теряет именно датасет, контролы то тут при чем? Даже если и получится, потеряется возможность редактирования в гриде в Excel стиле - не будут работать кнопки перемещения между записями.
*Rik* писал(а):Какие IBX смотрел?
ibx4lazarus 2.0.2 с сайта MWA. При установке Character set UTF8 выдает Division by zero даже при попытке заполнить поля датасета.
alexs писал(а):Для него надо взять мой FBDataSet. Автор не стал развивать свой из за него.
Сейчас попробую. В принципе UIB мне понравился, удобный...
alexs писал(а):Хороший комбайн. Но для птицы там нет полного контроля над транзакциями.
Сам им пользуюсь для всего, кроме птицы.
Ну не сказать что мне оно сильно нужно, в основном планируется однопользовательский режим из-за Embedded FB.
- *Rik*
- постоялец
- Сообщения: 453
- Зарегистрирован: 19.04.2011 12:18:51
- Откуда: Урал
- Контактная информация:
Nick74 писал(а):*Rik* писал(а):Какие IBX смотрел?
ibx4lazarus 2.0.2 с сайта MWA. При установке Character set UTF8 выдает Division by zero даже при попытке заполнить поля датасета.
http://visual-t.ru/ibexpress.html
*Rik* писал(а):http://visual-t.ru/ibexpress.html
Попробовал. Разместил датасет, транзакцию, базу, грид. Почему то не находит fbclient.dll, ладно, указываю ручками.
Открывается норм. Меняю любое поле, при сохранении ошибка "SIGSEGV файл runtimeIBCustomDataSet.pas строка 3828 PRecordsData(Buffer)^.rdBookmarkFlag := bfBof", Buffer=nil...
ЧЯДНТ?
Добавлено спустя 26 минут 55 секунд:
Дальнейшие эксперименты:
ZEOS
Не знает pfRefreshOnInsert и как следствие не использует конструкцию returning KEYFIELD, поэтому единственный работающий метод для INSERT - создавать TZSequence объект и указывать ему правильный номер генератора (Который вытаскивается из RDB$RELATION_FIELDS, так как в Firebird3 при использовании конструкции AUTOGENERATE BY DEFAULT имя генератора неизвестно.) В принципе можно написать автоматическое создание такого объекта, хотя руки чешутся поправить ЗЕОС.
UIB + FBDataset
Открывает, редактирует нормально, но при возникновении ошибки от БД и повторной попытке что-то сохранить начинает ругаться на закрытый запрос и далее из ступора не выходит. Подозреваю что-то не так с режимами транзакций, победить не смог.
Задумался, это у меня руки кривые или запросы слишком большие? )))
Неужто никто не использует Firebird с редактированием и вставкой новых строк в гриде? Хмм.
- *Rik*
- постоялец
- Сообщения: 453
- Зарегистрирован: 19.04.2011 12:18:51
- Откуда: Урал
- Контактная информация:
Nick74 писал(а):*Rik* писал(а):http://visual-t.ru/ibexpress.html
Попробовал. Разместил датасет, транзакцию, базу, грид. Почему то не находит fbclient.dll, ладно, указываю ручками.
Открывается норм. Меняю любое поле, при сохранении ошибка "SIGSEGV файл runtimeIBCustomDataSet.pas строка 3828 PRecordsData(Buffer)^.rdBookmarkFlag := bfBof", Buffer=nil...
ЧЯДНТ?
Добавлено спустя 26 минут 55 секунд:
Дальнейшие эксперименты:
ZEOS
Не знает pfRefreshOnInsert и как следствие не использует конструкцию returning KEYFIELD, поэтому единственный работающий метод для INSERT - создавать TZSequence объект и указывать ему правильный номер генератора (Который вытаскивается из RDB$RELATION_FIELDS, так как в Firebird3 при использовании конструкции AUTOGENERATE BY DEFAULT имя генератора неизвестно.) В принципе можно написать автоматическое создание такого объекта, хотя руки чешутся поправить ЗЕОС.
UIB + FBDataset
Открывает, редактирует нормально, но при возникновении ошибки от БД и повторной попытке что-то сохранить начинает ругаться на закрытый запрос и далее из ступора не выходит. Подозреваю что-то не так с режимами транзакций, победить не смог.
Задумался, это у меня руки кривые или запросы слишком большие? )))
Неужто никто не использует Firebird с редактированием и вставкой новых строк в гриде? Хмм.
Скорее всего у тебя что-то с руками не так.. У меня целая контора на ibx сидит, приложение масштаба предприятия, работает с 2мя базами на FireBird > 50гб, уже несколько лет полет нормальный, редактируют по разному и в гриде и без. Сделаю тебе тестовое приложение. Какая версия FireBird?
