4. Windchill查询与检索接口

在Windchill的接口开发中,单对象按OID读取只能解决“已知目标”的场景。真正高频的需求是按条件批量获取对象数据:例如“取出某产品下最近30天修改过的所有CAD文档”“列出某项目库中处于Released状态且版本为最新的一次性部件”。这类需求依赖Windchill的查询与检索接口体系,其核心构件是QuerySpec、SearchCondition,以及围绕导航器(Navigator)和高级搜索(Advanced Search)构建的检索能力。

QuerySpec:把“查什么”结构化

QuerySpec(查询规格)描述一次查询的完整意图,它至少包含三部分信息:目标类型(如WTPart、WTDocument、EPMDocument)、检索条件集合、以及返回属性与排序。在Windchill API中,通常通过QuerySpec的子类或工厂方法构造,例如面向部件的PartQuerySpec、面向文档的DocumentQuerySpec。它决定了查询走哪张业务视图、是否展开版本、是否包含工作副本。

一个关键参数是查询范围:是只查最新版本(Latest),还是查所有版本(All Versions),或是查某个基线/配置上下文内的对象。这个选择直接决定结果集大小和后续处理逻辑。若接口用于“同步最新BOM”,应限定Latest;若用于“审计历史变更”,则需放开版本并配合时间条件。

SearchCondition:条件的表达与组合

SearchCondition负责表达单个或一组过滤条件。常见形式包括:

  • 属性条件:如name LIKE 'PMP-%'、state = 'RELEASED'、modifyTimestamp >= 2024-01-01。
  • 关系条件:如“属于某容器”“被某部件使用”“引用某文档”。
  • 逻辑组合:通过AND、OR、NOT把多个条件组合成条件树。

实际开发中,条件往往不是单一属性,而是“容器 + 状态 + 时间 + 名称模式”的组合。此时应使用条件树而非字符串拼接,避免注入风险并保证类型正确。例如:

SearchCondition cond = new SearchCondition();
cond.addCondition("state", "RELEASED");
cond.addCondition("modifyTimestamp", ">=", startDate);
cond.addCondition("name", "LIKE", "PMP-%");
QuerySpec spec = new PartQuerySpec();
spec.setSearchCondition(cond);
spec.setVersionScope(Latest);

注意:不同Windchill版本的属性名可能不同,如状态字段可能是state或lifeCycleState,开发前应通过类型定义或元数据确认,不能凭经验硬编码。

导航器与高级搜索:从“点”到“面”

导航器(Navigator)解决的是沿关系遍历的问题。典型场景:从某个部件出发,沿BOM结构向下展开所有子件,或沿文档引用关系找到关联的CAD模型。导航器通常提供navigate()方法,接受起始对象、关系类型和深度参数。深度控制非常重要:深度为1只取直接子级,深度为-1表示无限展开,实际接口中应设置上限防止递归爆炸。

高级搜索(Advanced Search)则是面向用户的组合检索能力,接口层通常对应AdvancedSearch或SearchService。它支持跨类型、跨容器、多条件组合,并返回分页结果。与QuerySpec相比,高级搜索更偏向“交互式检索”,而QuerySpec更适合“程序化批量拉取”。

Windchill 查询与检索接口:从条件到结果集 查询意图 目标类型:WTPart 版本范围:Latest 容器:Product-A QuerySpec 类型 + 版本 + 排序 返回属性列表 分页参数 SearchCondition 条件树 state = RELEASED AND modifyTimestamp >= T0 AND name LIKE 'PMP-%' Navigator 起始对象 + 关系类型 深度:1 / -1(限深) Advanced Search 跨类型 / 跨容器 分页 + 排序 结果集(批量对象) List<WTPart> / WTDocument 分页游标 + 总数 结果处理与判断 遍历对象 → 读取属性 → 校验状态/版本 → 写入下游系统 空结果 / 超时 / 权限不足 → 记录日志并降级处理

批量获取的工程要点

批量查询最容易踩的坑是结果集过大。假设某产品下有12万个部件,若一次性拉取全部对象,接口会因内存和超时失败。正确做法是分页:设置pageSize(如500),循环调用直到游标耗尽。同时,只请求必要属性,避免把大文本、缩略图等字段带入结果集。

另一个要点是权限过滤。Windchill的查询结果会自动受访问控制约束,接口返回的对象数量可能少于数据库实际匹配数。开发时不能假设“查得到就等于有权限读”,应在结果处理阶段对每个对象做AccessControlHelper校验,或直接依赖平台过滤并记录被过滤数量用于对账。

对于导航器遍历,建议设置最大深度和最大节点数双阈值。例如深度不超过5层、节点总数不超过2000,超出时截断并返回警告。这样既满足常规BOM展开,又避免异常数据导致接口挂死。

实践建议:先用高级搜索在Windchill界面中验证条件组合能否命中预期对象,再把相同条件翻译为QuerySpec + SearchCondition代码。界面验证能快速暴露属性名错误、状态值大小写、日期格式等问题。
注意:modifyTimestamp等时间字段在不同数据库和时区配置下行为可能不同。接口中应统一使用UTC或平台配置时区,并在文档中明确说明,避免“查不到当天数据”这类边界问题。

一个可参考的批量查询片段

// 示例:查询Product-A下所有Released且最近修改的部件(最新版本)
QuerySpec spec = new PartQuerySpec();
spec.setContainer("Product-A");
spec.setVersionScope(VersionScope.LATEST);
spec.setPageSize(500);

SearchCondition cond = new SearchCondition();
cond.addCondition("state", "RELEASED");
cond.addCondition("modifyTimestamp", ">=", "2024-01-01");
spec.setSearchCondition(cond);

QueryResult result = QueryService.query(spec);
while (result.hasMore()) {
    List<WTPart> parts = result.getNextPage();
    for (WTPart p : parts) {
        // 读取编号、名称、版本、状态
        String number = p.getNumber();
        String name   = p.getName();
        String state  = p.getLifeCycleState().toString();
        // 写入下游或做业务处理
    }
}

这段代码体现了批量查询的基本骨架:规格定义 → 条件组合 → 分页循环 → 逐对象处理。实际项目中还需加入异常捕获、日志记录、事务边界控制和幂等处理。若下游系统要求“只同步变更”,可在条件中增加时间窗口,并用上次同步时间作为起点,形成增量拉取。

总结来看,QuerySpec决定“查什么类型、什么范围、返回什么”,SearchCondition决定“过滤哪些对象”,导航器解决“沿关系找关联”,高级搜索提供“交互式组合检索”。四者配合,才能稳定实现按条件批量获取Windchill对象数据,并为后续集成提供可靠的数据源。