如何在TFS 2017中跨项目查询对比Integration#字段?
解决TFS 2017跨项目匹配Integration#的实用方案
嘿,针对你在TFS 2017里需要找出两个关联项目中共同存在的Integration#(UDF字段里的INT-XXX)的需求,我给你整理了几个实用的方案,你可以根据自己的技术偏好和场景来选:
方案1:用WIQL编写跨项目关联查询(TFS原生方案,最直接)
TFS的工作项查询语言(WIQL)支持子查询和跨项目筛选,刚好能满足你的需求。你可以直接在TFS查询编辑器里切换到“WIQL”模式来编写以下查询:
SELECT [System.Id], [System.Title], [Custom.IntegrationNumber] FROM WorkItems WHERE [System.TeamProject] = '你的项目A名称' AND EXISTS ( SELECT [System.Id] FROM WorkItems WHERE [System.TeamProject] = '你的项目B名称' AND [Custom.IntegrationNumber] = [Custom.IntegrationNumber] OF PARENT ) AND [Custom.IntegrationNumber] <> '' ORDER BY [Custom.IntegrationNumber]
关键注意点:
- 替换
你的项目A名称和你的项目B名称为实际的项目名 - 一定要把
Custom.IntegrationNumber换成你这个UDF字段的引用名称(不是显示名称!):你可以在查询编辑器的字段选择弹窗里,查看字段的“引用名称”,比如如果显示名称是“Integration#”,引用名称可能是IntegrationNumber或者Custom.IntegrationNumber - 这个查询会返回项目A中所有Integration#在项目B也存在的工作项,你可以把结果里的Integration#去重,就是两边都有的目标值;如果需要看项目B的对应记录,只要调换两个项目的位置即可
方案2:Excel导出对比(适合快速验证或非技术人员)
如果觉得WIQL有点复杂,用Excel来做交集对比更直观:
- 分别创建两个简单查询:每个查询对应一个项目,筛选条件设为「Integration#不为空」,只保留
Integration#这一个字段 - 将两个查询的结果分别导出到Excel的两个工作表(比如Sheet1存项目A的数据,Sheet2存项目B的)
- 在Sheet3里用公式找出交集:
- 把Sheet1的Integration#复制到Sheet3的A列
- 在Sheet3的B列输入公式:
=IF(ISNA(VLOOKUP(A2, Sheet2!A:A, 1, FALSE)), "", "存在于项目B"),下拉填充 - 筛选B列有内容的行,就是两边都存在的Integration#
- 也可以用Excel的Power Query来合并两个列表,直接生成交集结果,操作更便捷
方案3:TFS API脚本自动化(适合定期批量处理)
如果需要定期做这个对比,或者处理大量工作项,用TFS的.NET API写个脚本会更高效:
using Microsoft.TeamFoundation.Client; using Microsoft.TeamFoundation.WorkItemTracking.Client; using System.Linq; using System.Collections.Generic; var tfsServerUri = new Uri("http://你的TFS服务器地址:8080/tfs/你的集合名称"); var tfsCollection = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(tfsServerUri); var workItemStore = tfsCollection.GetService<WorkItemStore>(); // 获取项目A的所有非空Integration# string queryProjectA = @"SELECT [Custom.IntegrationNumber] FROM WorkItems WHERE [System.TeamProject] = '你的项目A名称' AND [Custom.IntegrationNumber] <> ''"; var integrationNumbersA = workItemStore.Query(queryProjectA) .Cast<WorkItem>() .Select(wi => wi.Fields["Custom.IntegrationNumber"].Value.ToString().Trim()) .Distinct() .ToList(); // 获取项目B的所有非空Integration# string queryProjectB = @"SELECT [Custom.IntegrationNumber] FROM WorkItems WHERE [System.TeamProject] = '你的项目B名称' AND [Custom.IntegrationNumber] <> ''"; var integrationNumbersB = workItemStore.Query(queryProjectB) .Cast<WorkItem>() .Select(wi => wi.Fields["Custom.IntegrationNumber"].Value.ToString().Trim()) .Distinct() .ToList(); // 找出两个列表的交集 List<string> commonIntegrations = integrationNumbersA.Intersect(integrationNumbersB).ToList(); // 输出结果 foreach (var num in commonIntegrations) { System.Console.WriteLine(num); }
注意事项:
- 确保你的开发环境安装了对应TFS 2017的客户端组件,或者通过NuGet安装
Microsoft.TeamFoundationServer.Client包(注意版本要匹配TFS 2017) - 同样要替换代码中的服务器地址、集合名称、项目名和字段引用名称
通用注意事项
- 确保两个项目中的Integration#字段是一致的:最好是通过共享工作项类型或字段模板创建的,避免因字段引用名称不同导致查询失效
- 如果Integration#存在格式不一致的情况(比如大小写、多余空格),记得在查询或Excel处理前做标准化(比如转大写、去掉空格)
- 如果工作项数量很大,建议在查询中添加时间范围筛选(比如「创建日期在最近6个月内」),提升查询速度
内容的提问来源于stack exchange,提问作者Amit Pandey
相关产品推荐
相关产品推荐

