Два года тому назад я писал о получении в программе значения первичного ключа, который сгенерирован СУБД при добавлении новой строки в таблицу. Мои примеры вызова INSERT с модификатором RETURNING (или OUTPUT в случае MS SQL Server) были с использованием библиотеки для доступа к базам данных UniDAC. Давайте посмотрим, как реализована эта возможность в библиотеке FireDAC, которая уже много лет входит в поставку Delphi и C++Builder.
Что бы не повторяться я воспользуюсь тестовыми таблицами из предыдущей статьи, а в этой только адаптирую код, написанный с использованием TUniQuery из UniDAC к использованию с TFDQuery из FireDAC.
28.07.2023 Новый способ получения OUTPUT-значения после DML операции MS SQL Server в FireDAC Delphi 12.
Что бы не повторяться я воспользуюсь тестовыми таблицами из предыдущей статьи, а в этой только адаптирую код, написанный с использованием TUniQuery из UniDAC к использованию с TFDQuery из FireDAC.
1. Oracle. Здесь у FireDAC мы имеем код аналогичный UniDAC – сгенерированный первичный ключ возвращается через параметр:
q := TFDQuery.Create(nil); q.Connection := dbOra; q.SQL.Text := 'insert into test(id, t) ' + 'values (test_id.nextval, ''test'') ' + 'returning id into :id'; q.Params[0].ParamType := ptResult;//ptOutput ptInputOutput q.Params[0].DataType := ftInteger; q.Execute; Writeln(q.Params[0].Name, ' ', q.Params[0].AsString);Тип этого параметра может принимать три значения: ptResult, ptOutput и ptInputOutput.
2. PostgreSQL. Применить для FireDAC код аналогичный UniDAC не получилось. Вызов метода Execute приводит к ошибке:
[FireDAC][Phys][PG]-310. Cannot execute command returning result sets. Hint: use Open method for SELECT-like commandsFireDAC, в отличие от UniDAC, при вызове метода Execute не определяет вид запроса (у UniDAC методы Execute и ExecSQL можно использовать вместо метода Open для запроса данных) и не учитывает то, что RETURNING у PostgreSQL возвращает DataSet. Поэтому для подобного случая у TFDQuery необходимо использовать метод Open:
q := TFDQuery.Create(nil); q.Connection := dbPG; q.SQL.Text := 'insert into public.test(t) values (''test'') returning id'; q.Open; Writeln(q.Fields[0].FieldName, ' ', q.Fields[0].AsString);Для тех, кому не нравится вставлять данные вызывая метод Open, разработчики FireDAC предусмотрели возможность добавить в текст запроса с RETURNING псевдопараметр "INTO" экранированный фигурными скобками "{INTO :PARAM_NAME}":
q := TFDQuery.Create(nil); q.Connection := dbPG; q.SQL.Text := 'insert into public.test(t) values (''test'') returning id {into :id}'; q.Params[0].ParamType := ptOutput;//ptInputOutput q.Params[0].DataType := ftInteger; q.Execute; Writeln(q.Params[0].Name, ' ', q.Params[0].AsString);Тип псевдопараметра "INTO" может принимать только два значения: ptOutput и ptInputOutput.
3. Firebird/InterBase. Работает аналогично как у PostgreSQL: или Open или Execute с псевдопараметром "INTO".
4. MS SQL Server. Про то, как у MS SQL Server обойти отсутствие RETURNING я писал прошлый раз. Учитывая мое предложение использовать для этого временную таблицу INSERTED, то для FireDAC сразу заменим метод Execute на Open:
q := TFDQuery.Create(nil); q.Connection := dbMS; q.SQL.Text := 'insert into test(t) output INSERTED.ID values (''test'')'; q.Open; Writeln(q.Fields[0].FieldName, ' ', q.Fields[0].AsString);То есть, если бы я в примере с UniDAC использовал Open, то код менять не пришлось бы.
Подведем итог.
- Обе библиотеки для получения значения первичного ключа новой строки работают одинаково – в зависимости от СУБД возвращают его через параметр (используя метод Execute/ExecSQL) или через поле (используя метод Open).
- У FireDAC есть одно небольшое преимущество – наличие псевдопараметра "INTO", который позволяет использовать INSERT с RETURNING одинаково на разных СУБД (Execute + Params).
28.07.2023 Новый способ получения OUTPUT-значения после DML операции MS SQL Server в FireDAC Delphi 12.
Комментариев нет:
Отправить комментарий