Продолжаем разговор об API ClearQuest
Как обещал пишем запрос к базе данных CQ.
Как я говорил - любые действия с api начинаются с получения сессии.
В API предусмотрен специальный генератор запросов к базе дефектов. Сейчас я приведу несколько методов, которые я использовал для запроса:
Public Function GetDefectById(ByVal id As String) As DefectObject
Dim cqSession = GetSession()
Dim queryDef = PrepareQueryDef(cqSession)
Dim filterNode = queryDef.BuildFilterOperator(EBoolOp.BOOL_OP_OR)
filterNode.BuildFilter("id", ECompOp.COMP_OP_EQ, id)
Dim resultSet = cqSession.BuildResultSet(queryDef)
Return ExecuteAndParseResultSet(resultSet)(0)
End Function
Private Function PrepareQueryDef(ByVal session As SessionClass) As Object
Dim querydef = session.BuildQuery("defect")
querydef.BuildField("id")
querydef.BuildField("State")
querydef.BuildField("SubProject")
querydef.BuildField("Section")
querydef.BuildField("OriginalSource")
querydef.BuildField("Headline")
querydef.BuildField("Description")
querydef.BuildField("Severity")
querydef.BuildField("Owner")
querydef.BuildField("FoundInBuild")
querydef.BuildField("Type")
querydef.BuildField("Submit_Date")
Return querydef
End Function
Private Function ExecuteAndParseResultSet(ByVal resultSet As Object) As IList(Of DefectObject)
resultSet.EnableRecordCount()
resultSet.Execute()
Dim count = resultSet.RecordCount
If (count = 0) Then Return Nothing
Dim ListOfDefects As New List(Of DefectObject)
Dim i As Integer
For i = 1 To count
resultSet.MoveNext()
Dim defectObject As New DefectObject()
defectObject.Id = resultSet.GetColumnValue(1)
defectObject.State = resultSet.GetColumnValue(2)
defectObject.SubProject = resultSet.GetColumnValue(3)
defectObject.Section = resultSet.GetColumnValue(4)
defectObject.OriginalSource = resultSet.GetColumnValue(5)
defectObject.Headline = resultSet.GetColumnValue(6)
defectObject.Description = resultSet.GetColumnValue(7)
defectObject.Severity = resultSet.GetColumnValue(8)
defectObject.Owner = resultSet.GetColumnValue(9)
defectObject.FoundInBuild = resultSet.GetColumnValue(10)
defectObject.Type = resultSet.GetColumnValue(11)
defectObject.SubmitDate = resultSet.GetColumnValue(12)
ListOfDefects.Add(defectObject)
Next i
Return ListOfDefects
End Function Теперь разберём, что же мы делаем в данных функциях.
Функция
GetDefectById(ByVal id As String) входная функция, которая видна при использовании класса.
Две другие функции являются вспомогальными и служат просто для логического разделения кода. Функция
PrepareQueryDef(ByVal session As SessionClass) As Object настраивает запрос, т.е. в ней указывается какие поля необходимо получить, а функция
ExecuteAndParseResultSet(ByVal resultSet As Object) As IList(Of DefectObject) выполняет запрос и разбирает то что нам вернуло API.
Теперь по порядку... что же делается в функциях.
В API для создания запроса существует специальный объект
BuildQuery("defect"), который мы получаем из сессии. При его создании мы указываем для какой сущности будем генерировать запрос. Это может быть defect, Section или что-то ещё... в общем зависит от схемы, используемой в вашей базе.
Далее созданный объект запроса необходимо настроить. Настройка заключается как и в SQL в указании того, какие поля необходимы (то что пишется в SQL после ключевого слова
select) и какие фильтры мы накладываем на запрос (выражение
where).
Указание необходимых полей происходит через метод
BuildField("id") , как видно ему передаётся строковый параметр с названием поля.
Для формирования фильтра необходимо получить специальный объект
Dim filterNode = queryDef.BuildFilterOperator(EBoolOp.BOOL_OP_OR), у объекта запроса, что я сделал здесь. Передаваемое значение конструктору является указанием на то, что будет за оператор между выражениями. Фактически может быть два значения 1 или 2, соотвественно
OR или
AND. Далее нужно создать собтвенно выжение указывающее на то по какому полю ведётся фильтрация, делается это в этом выражении
filterNode.BuildFilter("id", ECompOp.COMP_OP_EQ, id) , первый параметр указывает по какому полю фильтруем, второй указывает по какому провилу (в данном случаем это правило
равенства (=)... и в последнем параметре указывается значение для фильтра. Всем правилам фильрации соответствует большая группа целочисленных констант. В моём примере это
COMP_OP_EQ которая в реале равна 1.
На сайте IBM есть более-менее пригодная документации по API,вот
тут указано как использовать фильтр. А вот
тут рассказано, какие константы правил понимает API.
Так... продолжаем.
Вас наверное уже интересует, а как же получить то, для чего мы формировали запрос. Тут всё классически. В этом смысле API CQ очень похожа на DataReader из стандартной библиотеки .NET. да-да.. всё как обычно экзекьют и получаем выборку :) Правда есть одна загвоздка: по умолчанию отключен каунтер записей, его надо включить :)
Но давайте обо всём по порядку.
Мы подготовили объект запроса. Теперь этот запрос нужно выполнить. Для этого в API существует специальный объект под названием ResultSet, его необходимо получить из объекта сессии вот так
Dim resultSet = cqSession.BuildResultSet(queryDef) . Объект получили... теперь включаем подсчёт записей и выполняем запрос:
esultSet.EnableRecordCount(), resultSet.Execute() . Всё, теперь результат запроса находится в нашем объекте.
Далее всё аналогично DataReader. Получаем каунт
Dim count = resultSet.RecordCount . Так же как и в DataReader есть специальный метод для последовательного перебора записей полученной выборки. Для того чтобы начать читать необходимо сместиться к первой записи
resultSet.MoveNext() . Для перевода "корретки" к следующей записи используем этот же метод. Для того чтобы получить доступ к значению поля в записи используем метод
GetColumnValue(1) . Параметр передаваемый в данный метод целочисленного типа и определяет номер столбца. Столбцы нумеруются в том же порядке, в котором мы их создавали при создании объекта запроса. Т.е. полная аналогия с DataReader.
Ещё хотелось бы сделать замечание. Если мы просим вернуть дефект со сложным полем (например, Section - т.е. дефект может быть сразу из нескольких областей), то мы получим несколько записей с одним и тем же дефектом, но с разным значеним сложного поля... Поэтому при перегоне выборки в более человеческий вид нужно это учитывать и соответственно обработать соответсвенным образом.
На этом пока всё. :) Потом расскажу как добавлять записи в CQ через API.