我正在使用 WorkItemTrackingHttpClient.QueryByWiqlAsync 来检索查询结果。默认返回前 200 条记录。它有一个顶部参数,您可以使用它来指定小于 200 的值。
但是我查询的结果大于200条记录。有谁知道如何使用具有正确分页的 TFS 客户端执行查询。页面和页面大小?例如,返回第 10 页,其中页数为 50。
我环顾四周,但不知道如何使用客户端来执行此操作,这令人惊讶,因为该功能似乎非常基础。
我正在使用 Nuget 包 Microsoft.TeamFoundationServer.Client 16.153.0。我还连接到本地 TFS 2017。
是的,我们只能通过调用 API 返回工作项列表,最多 200 个。这是设计使然,请参阅工作项 - 列表了解详细信息。
但是,我们可以使用 WIQL 查询从 Azure DevOps 检索数据。它非常灵活,可以在任何情况下使用。请参阅 WIQL 查询 和 用于 WIQL 查询的 Azure DevOps Rest 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();
}
}
}
}
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();
}
}
}