В этой статье:

Общие сведения

Описание

Использование интерфейсов сборки Dal

Использование объекта репозитория

Ограничения

Использование запросов в пользовательских приложениях

Номер статьи: KB000016

Общие сведения

Связанные блоки:

Описание

Есть несколько вариантов выполнения запросов к БД в пользовательском приложении: через стандартные программные интерфейсы или через объекты репозитория «Запрос» или «Процедура».

Использование интерфейсов сборки Dal

Первый вариант предполагает выполнение запроса через интерфейсы сборки 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(NullAs 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(NullAs 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);

Ограничения

Настройки серверов СУБД накладывают ограничение на количество одновременно открытых курсоров, поэтому необходимо своевременно закрывать неиспользуемые курсоры с помощью метода Close.

При реализации поддержки драйверов Microsoft SQL Server 2008 был задействован режим работы MARS (Multiple Active Result Set). Использование данного режима позволяет в рамках одного соединения иметь более одного открытого результирующего набора данных. Однако, пока данные одного результирующего набора не дочитаны до конца, то невозможно начать новую транзакцию в рамках этого соединения. Для решение данной проблемы существует два варианта решения:

Также стоит учитывать рекомендации по разработке приложений, функционирующих в режиме MARS. Данные рекомендации представлены в MSDN.

При формировании запросов необходимо учитывать синтаксис, который используется при работе с конкретной СУБД. Объекты репозитория «Запрос» и «Процедура» позволяют указывать синтаксис сразу для нескольких СУБД, это может использоваться при переносе объектов между репозиториями, развернутыми на различных СУБД.

Важным аспектом являются параметры объектов «Запрос» и «Процедура», которые в SQL-запросах используются для возврата значений. Такие параметры необходимо явно приводить к типу возвращаемого значения. Это связано с возможностями преобразования данных различных СУБД, а также с особенностями работы драйверов платформы. Пример запроса с преобразованием типа параметра:

select cast(:param as <type>) as param

См. также:

База знаний разработчиков | Сборка Dal | Объект «Запрос»