Эта статья о генерации Update команд в FireDAC. Она основана на официальной документации
FireDAC по разному обрабатывает следующие команды
Insert / Edit / Post / Delete – моментальное обновление
ApplyUpdates – применяется в режиме “Cached Updates”
Генератор команд FireDAC знает о ключевых полях, запросах, триггерах, специальных типах данных (Oracle BLOB / CLOB / BFILE, и так далее) и генерирует эффективные SQL команды в зависимости от соединения с БД. Это облегчает ручной труд. Также, дополнительно может быть использован компонент TFDUpdateSQL, который позволяет переписать (override) update команды.
Далее приводится пример для базы Oracle, где ключевое поле заполняется триггером, а также есть BLOB поле
1 2 3 |
INSERT INTO OracleTab (NAME, DT, IMAGE) VALUES (:NEW_NAME, :NEW_DT, EMPTY_BLOB()) RETURNING :NEW_ID, :NEW_IMAGE |
FROM, INTO, и UPDATE
FireDAC использует для обновления главную таблицу во фразе SELECT … FROM …. Также эта таблица будет использована для того, чтобы получить главные ключи mkPrimaryKeyFields. Используйте UpdateOptions.UpdateTableName чтобы явно задать имя обновляемой таблицы. Это требуется когда
-датасет берется из хранимой процедуры TFDStoredProc
–TFDQuery содержит не SELECT запрос
-FireDAC неправильно определяет имя главной таблицы
-приложению нужно перенаправить обновления в специальную таблицу
WHERE
UpdateOptions.UpdateMode контролирует выражение WHERE для отправки обновлений и удалений. Значение по умолчанию upWhereKeyOnly использует во фразе WHERE только уникальные идентификационные колонки unique identifying columns и обеспечивает эффективный и безопасный путь для поиска обновляемой строки. Когда такой колонки нет и невозможно определить обновляемый ряд, FireDAC переключит UpdateOptions.UpdateMode на upWhereAll. Следующие поля, включенные в WHERE могут привести к ошибке “no rows found”
-DOUBLE, FLOAT, TIME, and DATETIME поля и другие поля с плавающей точкой могут привести к потере точности при сравнении величин
-текстовые поля могут иметь неправильную кодировку или лишние пробелы, ведущие к неудачным сравнениям
В таких случаях приложение получает исключение
1 |
[FireDAC][DApt]-400. UPDATE command updated [0] instead OF [1] record. |
Если нет уникальных ключей, может выскочить такая ошибка
1 |
[FireDAC][DApt]-400. UPDATE command updated [4] instead OF [1] record. |
Решение проблемы может быть следующее
-создавайте корректные уникальные идентификационные колонки
-выключите некоторые поля при использовании WHERE, исключая pfInWhere из соответствующего свойства TField.ProviderFlags
-подавите эти ошибки, устанавливая UpdateOptions.CountUpdatedRecords в False
Учтите, чтобы избежать этих случаев с серверной таблицей SQL, которая также содержит триггеры, создавайте триггеры с инструкцией SET NOCOUNT ON в начале триггера, если это невозможно, тогда устанавливайте UpdateOptions.CountUpdatedRecords в False
SET и VALUES
Свойство UpdateOptions.UpdateChangedFields управляет полями, которые включаются во фразы UPDATE SET … or INSERT VALUES … Установка в TRUE включит только измененные поля, которые помогают
-минимизировать трафик
-обойти некоторые ограничения проверок
-обойти лишние запуски триггеров
-минимизировать генерацию лога
Установка в False, наоборот, включит все поля. Чтобы исключить обновления из колонок – исключите флаг pfInUpdate из соответствующего свойства TField.ProviderFlags.
RETURNING и Additional SELECTs
UpdateOptions.RefreshMode = rmOnDemand управляет автоматическим обновлением значений колонок, которое может быть изменено после вставки или обновления записи. Колонки, которые могут требовать обновления после вставки это
-автоинкрементные колонки
-калькулируемые
-колонки со значениями по умолчанию
-timestamp колонки
-колонки, обновляемые триггером
Колонки, которые могут требовать обновления после update инструкций
-калькулируемые
-timestamp
-обновляемые триггером
Кэширование Update команд
Иногда, установка UpdateChangedFields в False может улучшить производительность. И, скомбинированная с некоторыми другими настройками, такими как свойство UpdateOptions.FastUpdates, позволяет получить лучшую производительность при отправке обновлений, избегая дополнительных запросов и включая кэширование update команд.
Включение FastUpdates = True эквивалентно
- UpdateChangedFields = False;
- UpdateMode =
upWhereKeyOnly
; - LockMode =
lmNone
; - RefreshMode =
rmManual
; - CheckRequired = False.