C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
Редактирование записи, полученной запросом TQuery, Не все гладко...
iAlexander
Отправлено: 26.11.2004, 14:18


Дежурный стрелочник

Группа: Участник
Сообщений: 70



Привет всем. Заранее извиняюсь за возможное повторение, но найти подобного не смог.
Проблема вот в чем: делаю добавление записи из таблицы (Paradox) следующим способом:
CODE

ClientQuery->SQL->Clear();
ClientQuery->SQL->Add("SELECT * FROM clients WHERE Num = -1;");
ClientQuery->Open();
ClientQuery->Append();

Объясню:
Если не открыть TQuery запрос — Open, то невозможно будет сделать Append.
Для того, чтобы открыть запрос, пишу строку запроса, которая явно ничего не вернет (чтобы не тратить ресурсы)
После этих манипуляций можно редактировать поля записи, а для сохранения делаю ClientQuery->UpdateObject->Apply(ukInsert)
Свойства ClientQuery:
CachedUpdate = true;
RequestLive = false;
Работает. Прилично. Но:
после ClientQuery->Open()
в каталоге программы появляется файл Del2.MB размером 4096 байт, заполненный почти сплошь нулями (только первая сотня немного содержит данные). Либо DEL15.MB, ... Короче, DELxx.MB.
При некорректном завершении программы он остается.
А удаляется после ClientQuery->Close().

В чем причина возникновения этого файла и можно ли ее устранить?
Gedeon
Отправлено: 26.11.2004, 14:34


Ветеран

Группа: Модератор
Сообщений: 1742



Я маленько не в тему, но нахера Вам, извините, Query, да еще и Open, если Вам не надо возвращать заведомо ни одной записи? Используйте для вставки записи(ей) инструкцию ISERT языка SQL. И юзайте для этого метод ExecSQL TQuery или компонент StoredProcudure, в ADO есть еще такой CommandText.
iAlexander
Отправлено: 26.11.2004, 15:21


Дежурный стрелочник

Группа: Участник
Сообщений: 70



"Нахера" — это что-то новенькое. Раньше я такого не встречал. Извиняю, однако...

Объясняю:
для единства интерфейса для трех операций (добавление, просмотр, редактирование) используется один TQuery c TDataSource и Контролами.

В зависимости от вида операции над этим Query и производится то или иное действие:
1) Open(); Append()
2) Open();
3) Open(); Edit()

Здесь задача заключается в том, чтобы реализовать однородные действия с минимальными различиями — то есть редактировать данные, используя как можно меньше конкретных разнородных конструкций типа заведения еще Query для выполнения им действий... для этого как раз и служит TUpdateSQL

А задача Query — в том, чтобы дать возможность редактирования и просмотра данных.

И, кстати, если даже делать "SELECT * FROM clients" — этот файл DELxx.MB все равно создается. Так что возвращаются, или нет данные, не имеет значения.

Почему я не использую INSERT — да потому, что при этом придется конструировать SQL — выражение вручную, а при множестве полей различных типов в таблице это становится несколько утомительно. Представим, что набор полей периодически изменяется. Тогда поддержка программы превращается в муку. А для TQuery — достаточно просто перестроить TUpdateSQL и добавить контрол.

Отредактировано iAlexander — 26/11/2004, 17:16
AVC
Отправлено: 26.11.2004, 15:46


Ветеран

Группа: Модератор
Сообщений: 1583



А я размещаю на форме два компонента класса Query и спокойно решаю все вопросы единства интерфейса. Один Query для Select'a другой для разных мелких проблем, в том числе и для выполнения команд SQL не возвращающих наборов данных.

Отредактировано AVC — 26/11/2004, 15:59
iAlexander
Отправлено: 26.11.2004, 15:58


Дежурный стрелочник

Группа: Участник
Сообщений: 70



AVC
А каким образом Вы реализуете добавление?
То есть где пользователь может заполнять поля, и как потом введенные значения используются?
AVC
Отправлено: 26.11.2004, 16:02


Ветеран

Группа: Модератор
Сообщений: 1583



По обстановке. Иногда прямо в гриде — тогда работает основной Query иногда через дополнительную опросную форму тогда рботает дополнительный Query.

SELECT * FROM clients WHERE Num = -1 как мне кажется возвращает пустой набор, или я не прав?
iAlexander
Отправлено: 26.11.2004, 16:05


Дежурный стрелочник

Группа: Участник
Сообщений: 70



Да, Вы правы.
Смотрите мое исправление (2-е сообщение) .
А дополнительная опросная форма — она содержит TDBEdit или TEdit?
Если DB, то на какой TDataSet они завязаны?
AVC
Отправлено: 26.11.2004, 16:34


Ветеран

Группа: Модератор
Сообщений: 1583



QUOTE
А дополнительная опросная форма — она содержит TDBEdit или TEdit?

Обратно-же когда как, но чаще TEdit.
QUOTE
Если DB, то на какой TDataSet они завязаны

На основной.

Если ваша форма предназначена для работы по одной записи то можно работать и так как вы предлагаете в 1м посте. В моих терминах это и есть вспомогательная опросная форма.
iAlexander
Отправлено: 26.11.2004, 16:42


Дежурный стрелочник

Группа: Участник
Сообщений: 70



Мы друг друга поняли smile.gif
У меня это как раз и есть опросная форма. Она вызывается при редактировании/добавлении/просмотре, с найденным id для просмотра/редактирования.
Однако вопрос-то остается: DELxx.MB. Кстати, посмотрите на свою реализацию — возможно во время редактирования записей на опросной форме с TDB у Вас то же самое происходит.
AVC
Отправлено: 26.11.2004, 17:10


Ветеран

Группа: Модератор
Сообщений: 1583



QUOTE
возможно во время редактирования записей на опросной форме с TDB у Вас то же самое происходит

Нет. Я работаю не с Paradox.

Для создания пустой записи я пользуюсь непосредственно основным Query
т.е. командой Insert. Получаю пустышку, заполняю начальными значениями и передаю DataSet в опросную форму (эта вместо той части которая справедливо возмутила Gedeon). По возврату автоматически, по информации о полях из DataSet, строю SQL Insert и выполняю его через вспомогательный запрос. Сопровождение UpdateSql считаю слишком муторным. Автоматический Insert сам сделает все что надо (примерно как это делает DataSet)
iAlexander
Отправлено: 26.11.2004, 17:53


Дежурный стрелочник

Группа: Участник
Сообщений: 70



Можно поподробнее?
Я несколько запутался smile.gif
Что есть пустышка, как она получается и после чего редактируется начальными значениями? Что передается и по чему автоматически строится Insert? Как он строится?
Если не лень, пожалуйста, отредактируйте Ваш ответ, при этом соблюдая последовательность вызовов и поименовав TDataSet'ы для ясности.
AVC
Отправлено: 26.11.2004, 18:21


Ветеран

Группа: Модератор
Сообщений: 1583



Просматриваем QryMain и считаем что пора добавить запись.
QryMain->Insert() порождает пустую строку в памяти и DataSet спозиционирован на ней.
Вызов формы редактирования, один из параметров QryMain.
Заполнение полей формой.
В зависимости от сложности запроса либо просто Post и Refresh.
Либо построение текста запроса Insert типа AnsiString sqltext = "Insert Into aaa.bbb (ff1, ff2, ...) Values (vv1, vv2 ...)";
QryWork->SQL->Text = sqltext; QryWork->Execute(); QryMain Refresh
После Refresh — QryMain позиционирую на новую запись.

Если нужно просто редактировать то QryMain->Insert() заменяется на QryMain->Edit() а дальше см. выше.

Дальше (если нужно) в понедельник. smile.gif
AVC
Отправлено: 26.11.2004, 18:38


Ветеран

Группа: Модератор
Сообщений: 1583



Кстати. Мы несколько уклонились от основного вопроса топика.
"В чем причина возникновения этого файла" — рабочий файл для BDE SQL. В конце концов это просто имитатор нормального сервера бд.
"можно ли ее устранить?" — я не знаю, но предлагаю обойти эту проблему. Почему бы при старте приложения не вызвать чистильщика — удалить файлы del??.mb ?
iAlexander
Отправлено: 26.11.2004, 19:07


Дежурный стрелочник

Группа: Участник
Сообщений: 70



1)ОК, спасибо. ответ на основной вопрос я получил. Насчет чистильщика — хорошая идея!

2)А такой путь, который описан Вами, кажется мне не менее трудоемким, чем мой.
Основное же отличие — в том, что у меня нет QryMain (кстати, что это, Table, Query, или без разницы). И я могу добавлять новое поле с ходу, не вызывая перед этим список имеющихся (и это для меня необходимо). (еще раз скажу, что открывать Query мне приходится лишь постольку, поскольку закрытый он не может сделать Append(), и всего лишь)

3) Формат Insert я знаю smile.gif . Способ его выполнения тоже.
Вопрос был — автоматически ли Вы генерируете эту строку (допустим, обходом всех полей датасета). Я, например, таким образом делаю, когда генерирую строку поиска (это, кстати, еще одна форма использования моего Query — наряду с добавлением/редактированием/просмотром).
AVC
Отправлено: 27.11.2004, 14:59


Ветеран

Группа: Модератор
Сообщений: 1583



QUOTE
А такой путь, который описан Вами, кажется мне не менее трудоемким, чем мой.
Основное же отличие — в том, что у меня нет QryMain (кстати, что это, Table, Query, или без разницы).

Хозяин барин smile.gif
QryMain это без разницы (TDataSet), хотя в силу специфики СУБД с TTable не работаю.

QUOTE
Вопрос был — автоматически ли Вы генерируете эту строку (допустим, обходом всех полей датасета).

Да автоматически. Не пивел в примере код, думал это и так очевидно в свете нашего диалога.

Наша разница состоит в том, что когда пользователь принимает решение о необходмисти добавления строки у меня уже есть открытый DataSet (именно просмотрев его он и пришел к такой необходимости)("просмотр с редактированием"). Для вашего случая, как мне кажется, более характерна следующая схема — заполнение опросной формы, сохранение результата ("циклический ввод").

Мой опыт подсказывает, что в случае циклического воода (конечно если речь идет не о простом редакторе таблиц) создание универсальной опросной формы на таком уровне не оправдано. Вывод — делать для каждого класса вводимой в цикле информации свою форму и после опроса выполнять SQL'евский Insert.
(Но обратно же — все по желанию разработчика).

Если вы помните, то наш диалог начался с того, что нет ничего страшного в двух DataSet'ах на форме. smile.gif
AVC
Отправлено: 27.11.2004, 15:10


Ветеран

Группа: Модератор
Сообщений: 1583



Уф. Все стало на свое место. Простите, что не сразу понял smile.gif
Как то сразу зацепился за фразу "... используя как можно меньше конкретных разнородных конструкций типа заведения еще Query для выполнения им действий ..." smile.gif

Ваш метод совершенно оправдан, если вы делаете универсальную, самонастраивающуюся форму для добавления, изменения, поиска (удаления?) строк, из любой, заранее не известной, таблицы. Тот самый редактор таблицы.
smile.gif (с моей точки зрения вещь, более менее удобная для админа, но мало пригодная для пользователя).


Отредактировано AVC — 27/11/2004, 15:18
iAlexander
Отправлено: 29.11.2004, 13:18


Дежурный стрелочник

Группа: Участник
Сообщений: 70



AVC
если вы делаете универсальную, самонастраивающуюся форму для добавления, изменения, поиска (удаления?) строк, из любой, заранее не известной, таблицы
Да, это хорошая идея, но, как Вы правильно заметили, малопригодная для конечного пользователя. Я так не делаю — у меня отдельные формы под разные таблицы. Однако, поскольку их (форм и таблиц) много, очень хорошо, когда для реализации требуется минимум компонентов — тогда единообразие все же сохраняется, и потом легче это сопроводить и изменить все синхронно.
Циклический ввод я использовал раньше, потом отказался по просьбам пользователей.
Сейчас, после нашего диалога, я уже могу сформулировать мысль в том виде, в котором она и была задумана, а впоследствии реализована.
Моя цель — редактирование данных в TDBEdit-подобных контролах — с тем, чтобы каждый контрол был сразу связан с полем таблицы, которому он соответствует (в этом также случае отпадает необходимость обхода полей датасета с целью создания оператора INSERT/UPDATE). При этом отсутствуют какие-либо предварительные манипуляции с датасетами — и поэтому Query под этими контролами сам предоставляет возможность редактирования данных в контролах (посредством Append, из-за которого необходимо делать Open)
Единственный, на мой взгляд, недостаток такого решения — это присутствие и необходимость своевременного обновления TUpdateSQL. Выходом для себя я вижу создание собственного компонента, реализующего вся эту функциональность в себе одном. И для начинки здесь уже можно использовать либо компот TQuery с TUpdateSQL, либо способ, предложенный Вами (с еще одним Query). Вообще разницы здесь никакой — и там, и тут нужно будет конструировать SQL выражения. Но коль уж TUpdateSQL имеет три поля под это дело — можно и воспользоваться. ;-)

(добавлено: да, обход полей — не контролов. сорри)

Отредактировано iAlexander — 29/11/2004, 16:28
AVC
Отправлено: 29.11.2004, 15:20


Ветеран

Группа: Модератор
Сообщений: 1583



QUOTE
в этом также случае отпадает необходимость обхода контролов с целью создания оператора INSERT/UPDATE

Вообще-то я имел ввиду обход полей датасета.
Действительно я предпочитаю иметь второй Query вместо UpdateSql, при динамической генерации команд sql достаточно иметь один QryWork на приложение (такой у меня то же есть).

Могу отдать еще одну идею (реализована у меня в последнем проекте). В специальной таблице хранится описание фомы — какие и как элементы опрашивать и что потом с эти делать. Приложение зачитывает это описание, настраивает свои контролы и предлагает пользователю заполнить поля ввода. По нажатию "сохранить" проверяется что там пользователь понавводил и, если все правильно, выполняются действия. При изменении структур таблиц или добавлении новых требований достаточно просто поменять тест описания а не лезть в исходники. Плюс все нововведения доступны сразу всем без ожидания обновления.
iAlexander
Отправлено: 29.11.2004, 15:36


Дежурный стрелочник

Группа: Участник
Сообщений: 70



Я тоже приходил к этой идее. Несколько с другой целью, правда — мне нужно было настроить для каждого контрола уровень доступа для каждого типа пользователя. (Виден/Доступен/Редактируем).
Это действительно очень удобно:
1) экономия ресурсов при отсутствии DB контролов не хилая
2) обращение к БД можно организовывать вообще через один компонент.

Только у меня мало времени для реализации таких удачных идей.
Обычно все приходится по-дедовски делать smile.gif
AVC
Отправлено: 29.11.2004, 16:08


Ветеран

Группа: Модератор
Сообщений: 1583



Удачи smile.gif

Вернуться в Работа с базами данных в C++Builder