В недавнем обсуждении на форуме разработчиков Delphi поднимался интересный вопрос: почему код, который годами работал в обработчике FormCreate, перестал корректно функционировать в Delphi 12.3 Athens. В этой статье мы разберём причины этой проблемы, предложим несколько решений и рассмотрим лучшие практики работы с формами и SQL-запросами в Delphi.
Проблема в том, что в Delphi 12.3 обработчик FormCreate вызывается сразу при создании формы (вызове конструктора Create), до того как будут установлены свойства sQuery, sTitle и iQty.
Почему это работало раньше?
Это действительно интересный вопрос. Как отмечали участники обсуждения, такой код в принципе не должен был работать, так как свойства устанавливаются после создания формы, а FormCreate вызывается в процессе создания. Возможные объяснения:
В предыдущих версиях Delphi мог быть другой порядок инициализации
Возможно, использовался флаг OldCreateOrder, который меняет порядок событий
В коде мог быть переопределён конструктор или использованы методы BeforeConstruction/AfterConstruction
Решения проблемы
1. Перенос кода в FormShow (простое решение)
Самый простой вариант - перенести код из FormCreate в FormShow:
procedure TStatsGridForm.FormShow(Sender: TObject);
begin
Caption := sTitle + ' - Total records..' + IntToStr(iQty);
JobTickets.SQL.Clear;
JobTickets.SQL.Add(sQuery);
JobTickets.Prepare;
JobTickets.Open;
end;
Плюсы: - Минимальные изменения кода - Гарантированно выполняется после установки всех свойств
Минусы: - Может вызываться несколько раз (если форма скрывается и показывается) - Не совсем логичное место для инициализации данных
2. Использование пользовательского конструктора (рекомендуемое решение)
Более правильный подход - создать специальный конструктор:
Плюсы: - Чёткий контроль порядка инициализации - Все параметры задаются в одном месте - Более безопасный и предсказуемый код
Минусы: - Требует больше изменений в существующем коде
3. Использование параметризованных запросов (лучшая практика)
Как отметил один из участников обсуждения, лучше использовать параметризованные запросы:
procedure TStatsGridForm.FormCreate(Sender: TObject);
begin
JobTickets.SQL.Text := 'SELECT ... WHERE BusCode = :BusCode AND DateIn BETWEEN :StartDate AND :FinishDate';
JobTickets.ParamByName('BusCode').AsString := AUD.BusCode;
JobTickets.ParamByName('StartDate').AsDate := edtStartDate.AsDate;
JobTickets.ParamByName('FinishDate').AsDate := edtFinishDate.AsDate;
JobTickets.Prepare;
JobTickets.Open;
end;
Преимущества: - Безопасность от SQL-инъекций - Более чистый код - Автоматическое экранирование и форматирование параметров
Дополнительные рекомендации
Проверка активности запроса: Убедитесь, что в дизайнере запрос не активен (как советовал Uwe Raabe)
Использование AfterConstruction: Если нужно сохранить текущую архитектуру, можно использовать метод AfterConstruction:
procedure TStatsGridForm.AfterConstruction;
begin
inherited;
if not (csDesigning in ComponentState) then
begin
Caption := sTitle + ' - Total records..' + IntToStr(iQty);
JobTickets.SQL.Text := sQuery;
JobTickets.Prepare;
JobTickets.Open;
end;
end;
Сеттеры свойств: Можно использовать сеттеры свойств для автоматического обновления:
property sQuery: string read FsQuery write SetQuery;
procedure TStatsGridForm.SetQuery(const Value: string);
begin
FsQuery := Value;
if not (csDesigning in ComponentState) and (Value <> '') then
begin
JobTickets.SQL.Text := Value;
JobTickets.Prepare;
JobTickets.Open;
end;
end;
Заключение
Проблема, с которой столкнулся разработчик, связана с порядком инициализации формы в Delphi. Хотя перенос кода в FormShow решает проблему, более правильными подходами являются:
Использование специального конструктора для передачи параметров
Применение параметризованных запросов
Использование AfterConstruction или сеттеров свойств
Выбор конкретного решения зависит от архитектуры вашего приложения и личных предпочтений. Главное - понимать порядок выполнения кода при создании и отображении форм в Delphi.
Для старых проектов, которые переходят на Delphi 12.3, рекомендуется провести аудит всех подобных случаев и выбрать единый подход для модернизации кода.
Статья описывает проблему с кодом SQL-запроса в Delphi 12.3, который перестал работать в обработчике FormCreate из-за изменения порядка инициализации формы, и предлагает различные способы её решения.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS