Номер статьи: KB000016
Связанные блоки:
Есть несколько вариантов выполнения запросов к БД в пользовательском приложении: через стандартные программные интерфейсы или через объекты репозитория «Запрос» или «Процедура».
Первый вариант предполагает выполнение запроса через интерфейсы сборки Dal. Если используется сложный по структуре запрос, то данный метод имеет ряд недостатков:
увеличивается трудоемкость редактирования запроса;
ухудшается читаемость кода пользовательского приложения.
Рассмотрим пример выполнения параметрического запроса, которые добавляет запись в какую-либо таблицу базы данных. Значения полей передаются посредством входных параметров функции. Для выполнения примера предполагается наличие в репозитории объекта «База данных» с идентификатором «OBJ_DB». Результатом работы функции будет количество добавленных записей:
Function ChangeData(Value1: Variant; Value2: Variant): Integer;
Var
Mb: IMetabase;
DbIns: IDatabaseInstance;
Command: IDalCommand;
CommandParams: IDalCommandParams;
SQL: String;
Result: Integer;
Begin
Mb := MetabaseClass.Active;
DbIns := Mb.ItemById("OBJ_DB").Open(Null) As IDatabaseInstance;
SQL := "Insert into ... values (:Val1, :Val2)";
Command := DbIns.Connection.CreateCommand(SQL);
Command.Parse;
CommandParams := Command.Params;
CommandParams.Item(0).Value := Value1;
CommandParams.Item(1).Value := Value2;
Result := Command.Execute;
Command.Close;
Return Result;
End Function ChangeData;
Пример извлечения значений. Результатом работы функции будет являться курсор с результирующим набором данных:
Function ReadData: IDalCursor;
Var
Mb: IMetabase;
DbIns: IDatabaseInstance;
Command: IDalCommand;
SQL: String;
Result: IDalCursor;
Begin
Mb := MetabaseClass.Active;
DbIns := Mb.ItemById("OBJ_DB").Open(Null) As IDatabaseInstance;
SQL := "Select ...";
Command := DbIns.Connection.CreateCommand(SQL);
Result := Command.CreateCursor;
Command.Close;
Return Result;
End Function ReadData;
Второй вариант предполагает использование объектов репозитория «Запрос» или «Процедура» с необходимыми наборами параметров. В приложении должна быть функция, позволяющая получать результат выполнения этого запроса. Преимущества данного способа:
объект репозитория хранится в определенном месте и его можно легко его редактировать;
уменьшается количество кода прикладного приложения, увеличивается эффективность его отладки.
Пример получения данных путем выполнения объекта «Запрос». Идентификатор запроса в репозитории передается в параметре функции QueryId, идентификатор параметра запроса - ParamId, значение параметра - ParamValue. Результатом работы функции будет открытый экземпляр объекта, предоставляющий доступ к кэшированным данными:
Public Function RunQueryWithParam(QueryId: String; ParamId: String; ParamValue: Variant): IDatasetInstance;
Var
Mb: IMetabase;
QueryKey: Integer;
Desc: IMetabaseObjectDescriptor;
Pars: IMetabaseObjectParamValues;
Begin
Mb := MetabaseClass.Active;
QueryKey := Mb.GetObjectKeyById(QueryId);
If QueryKey = -1 Then
Return Null;
End If;
Desc := Mb.Item(QueryKey);
Pars := Desc.Params.CreateEmptyValues;
Pars.FindById(ParamId).Value := ParamValue;
Return Desc.Open(Pars) As IDatasetInstance;
End Function RunQueryWithParam;
В приложении код будет выглядеть следующим образом:
Var
Tasks: IDatasetInstance;
Begin
Tasks := RunQueryWithParam(< Идентификатор запроса >, "ID", < Значение параметра >);
Для получения доступа к данным можно использовать свойство IDatasetInstance.Fields, либо обратиться к кэшу источника посредством метода IDatasetInstance.OpenCached:
Var
Tasks: IDatasetInstance;
TasksData: ICachedDataset;
Begin
Tasks := RunQueryWithParam(< Идентификатор запроса >, "ID", < Значение параметра >);
TasksData := Tasks.OpenCached;
Для передачи параметру множественного значения можно использовать следующую конструкцию:
Var
Tasks: IDatasetInstance;
Ls: ArrayList;
Begin
Ls := New ArrayList.Create;
For i := 1 To 2 Do
Ls.Add(i);
End For;
Tasks := RunQueryWithParam(< Идентификатор запроса >, "ID", Ls.ToArray);
После завершения работы с данными закройте экземпляр объекта и кэш:
Var
Tasks: IDatasetInstance;
TasksData: ICachedDataset;
Begin
Tasks := RunQueryWithParam(< Идентификатор запроса >, "ID", < Значение параметра >);
TasksData := Tasks.OpenCached;
//...
// Работа с данными
//...
TasksData.Close;
Tasks.Close;
Настройки серверов СУБД накладывают ограничение на количество одновременно открытых курсоров, поэтому необходимо своевременно закрывать неиспользуемые курсоры с помощью метода Close.
Также стоит учитывать рекомендации по разработке приложений, функционирующих в режиме MARS. Данные рекомендации представлены в MSDN.
При формировании запросов необходимо учитывать синтаксис, который используется при работе с конкретной СУБД. Объекты репозитория «Запрос» и «Процедура» позволяют указывать синтаксис сразу для нескольких СУБД, это может использоваться при переносе объектов между репозиториями, развернутыми на различных СУБД.
Важным аспектом являются параметры объектов «Запрос» и «Процедура», которые в SQL-запросах используются для возврата значений. Такие параметры необходимо явно приводить к типу возвращаемого значения. Это связано с возможностями преобразования данных различных СУБД, а также с особенностями работы драйверов платформы. Пример запроса с преобразованием типа параметра:
select cast(:param as <type>) as param
См. также: