如何从 TFS WorkItemTrackingHttpClient QueryByWiqlAsync 分页结果

问题描述 投票:0回答:2

我正在使用 WorkItemTrackingHttpClient.QueryByWiqlAsync 来检索查询结果。默认返回前 200 条记录。它有一个顶部参数,您可以使用它来指定小于 200 的值。

但是我查询的结果大于200条记录。有谁知道如何使用具有正确分页的 TFS 客户端执行查询。页面和页面大小?例如,返回第 10 页,其中页数为 50。

我环顾四周,但不知道如何使用客户端来执行此操作,这令人惊讶,因为该功能似乎非常基础。

我正在使用 Nuget 包 Microsoft.TeamFoundationServer.Client 16.153.0。我还连接到本地 TFS 2017。

tfs azure-devops
2个回答
2
投票

是的,我们只能通过调用 API 返回工作项列表,最多 200 个。这是设计使然,请参阅工作项 - 列表了解详细信息。

但是,我们可以使用 WIQL 查询从 Azure DevOps 检索数据。它非常灵活,可以在任何情况下使用。请参阅 WIQL 查询用于 WIQL 查询的 Azure DevOps Rest API

要获取所有工作项,我们可以尝试以下步骤:

  1. 使用工作项查询 API 执行存储的查询来检索 工作项 ID 列表
  2. 将工作项 ID 列表分成 200 个组,这是 工作项 API 支持的最大批量大小
  3. 对每200个工作项ID的列表调用工作项API即可获取 工作项目详细信息。

您可以参考此主题了解详细信息。

此外,下面的代码供您参考,它对我有用:

using Microsoft.TeamFoundation.WorkItemTracking.WebApi;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models;
using Microsoft.VisualStudio.Services.Client;
using Microsoft.VisualStudio.Services.Common;
using System;
using System.Collections.Generic;
using System.Linq;

namespace QueryWorkitems0619
{
    class Program
    {
        static void Main(string[] args)
        {
            Uri uri = new Uri("http://tfs2017:8080/tfs/DefaultCollection");

            //string PAT = "xxxx";
            string project = "SCRUM-TFVC";

            //VssBasicCredential credentials = new VssBasicCredential(user, PAT);

            VssCredentials credentials = new VssClientCredentials();
            credentials.Storage = new VssClientCredentialStorage();

        //create a wiql object and build our query
        Wiql wiql = new Wiql()
        {
            Query = "Select * " +
                    "From WorkItems " +
                    "Where [Work Item Type] = 'Product Backlog Item' " +
                    "And [System.TeamProject] = '" + project + "' " +
                    "And [System.State] <> 'Closed' " +
                    "Order By [State] Asc, [Changed Date] Desc"
        };

        //create instance of work item tracking http client
        using (WorkItemTrackingHttpClient workItemTrackingHttpClient = new WorkItemTrackingHttpClient(uri, credentials))
        {
            //execute the query to get the list of work items in the results
            WorkItemQueryResult workItemQueryResult = workItemTrackingHttpClient.QueryByWiqlAsync(wiql).Result;

            //Splict the query result (the list of work item IDs) into groups of 200.
            var QueryGroups = from i in Enumerable.Range(0, workItemQueryResult.WorkItems.Count())
                            group workItemQueryResult.WorkItems.ToList()[i] by i / 200;

            foreach (var QueryGroup in QueryGroups)
            {
                //some error handling                
                if (QueryGroup.Count() != 0)
                {
                    //need to get the list of our work item ids and put them into an array
                    List<int> list = new List<int>();
                    foreach (var item in QueryGroup.ToList())
                    {
                        list.Add(item.Id);
                    }
                    int[] arr = list.ToArray();

                    //build a list of the fields we want to see
                    string[] fields = new string[3];
                    fields[0] = "System.Id";
                    fields[1] = "System.Title";
                    fields[2] = "System.State";

                    //get work items for the ids found in query
                    var workItems = workItemTrackingHttpClient.GetWorkItemsAsync(arr, fields, workItemQueryResult.AsOf).Result;

                    Console.WriteLine("\n\n----------------------------------------------------------------");
                    Console.WriteLine("\nQuery Results: {0} items found for Group {1}", workItems.Count, QueryGroup.Key);
                    Console.WriteLine("\n----------------------------------------------------------------");

                    //loop though work items and write to console
                    foreach (var workItem in workItems)
                    {
                        Console.WriteLine("ID:{0} Title:{1}  State:{2}", workItem.Id, workItem.Fields["System.Title"], workItem.Fields["System.State"]);
                    }         
                }                 
            }
            Console.ReadLine();
        }
    }
}

}


0
投票

Andy 的代码 对于返回大约 300k 记录的查询来说太慢了。这是他的代码的稍微修改版本,在我这边表现更好:

using Microsoft.TeamFoundation.WorkItemTracking.WebApi;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models;
using Microsoft.VisualStudio.Services.Client;
using Microsoft.VisualStudio.Services.Common;
using System;
using System.Collections.Generic;
using System.Linq;

namespace QueryWorkitems0619
{
    class Program
    {
        static void Main(string[] args)
        {
            Uri uri = new Uri("http://tfs2017:8080/tfs/DefaultCollection");

            //string PAT = "xxxx";
            string project = "SCRUM-TFVC";

            //VssBasicCredential credentials = new VssBasicCredential(user, PAT);

            VssCredentials credentials = new VssClientCredentials();
            credentials.Storage = new VssClientCredentialStorage();

        //create a wiql object and build our query
        Wiql wiql = new Wiql()
        {
            Query = "Select * " +
                    "From WorkItems " +
                    "Where [Work Item Type] = 'Product Backlog Item' " +
                    "And [System.TeamProject] = '" + project + "' " +
                    "And [System.State] <> 'Closed' " +
                    "Order By [State] Asc, [Changed Date] Desc"
        };

        //create instance of work item tracking http client
        using (WorkItemTrackingHttpClient workItemTrackingHttpClient = new WorkItemTrackingHttpClient(uri, credentials))
        {
            //execute the query to get the list of work items in the results
            WorkItemQueryResult workItemQueryResult = workItemTrackingHttpClient.QueryByWiqlAsync(wiql).Result;

            //Cagin's modification starts here:
            List<WorkItemReference> workItems = workItemQueryResult.WorkItems.ToList();
            int count = workItems.Count;

            // Split the query result (the list of work item IDs) into groups of 200.
            var QueryGroups =
                from i in Enumerable.Range(0, count)
                group workItems[i] by i / 200;
            //Cagin's modification ends here.

            foreach (var QueryGroup in QueryGroups)
            {
                //some error handling                
                if (QueryGroup.Count() != 0)
                {
                    //need to get the list of our work item ids and put them into an array
                    List<int> list = new List<int>();
                    foreach (var item in QueryGroup.ToList())
                    {
                        list.Add(item.Id);
                    }
                    int[] arr = list.ToArray();

                    //build a list of the fields we want to see
                    string[] fields = new string[3];
                    fields[0] = "System.Id";
                    fields[1] = "System.Title";
                    fields[2] = "System.State";

                    //get work items for the ids found in query
                    var workItems = workItemTrackingHttpClient.GetWorkItemsAsync(arr, fields, workItemQueryResult.AsOf).Result;

                    Console.WriteLine("\n\n----------------------------------------------------------------");
                    Console.WriteLine("\nQuery Results: {0} items found for Group {1}", workItems.Count, QueryGroup.Key);
                    Console.WriteLine("\n----------------------------------------------------------------");

                    //loop though work items and write to console
                    foreach (var workItem in workItems)
                    {
                        Console.WriteLine("ID:{0} Title:{1}  State:{2}", workItem.Id, workItem.Fields["System.Title"], workItem.Fields["System.State"]);
                    }         
                }                 
            }
            Console.ReadLine();
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.