MS Dynamics Web API 怪癖:多态字段的奇异案例

发布: (2026年3月16日 GMT+8 06:43)
7 分钟阅读
原文: Dev.to

Source: Dev.to

请提供您希望翻译的正文内容,我将按照要求将其翻译为简体中文,并保留原有的格式、Markdown 语法以及技术术语。谢谢!

如果您曾经与 Microsoft Dynamics 365 / Dataverse 集成,您可能几乎立刻注意到一些奇怪的现象。

当您读取记录时,会看到类似下面的字段:

{
  "_ownerid_value": "151F639c-1c73-eb11-b1ab-000d3a253b40"
}

但在创建或更新记录时,API 突然要求使用类似下面的格式:

{
  "ownerid@odata.bind": "/systemusers(151F639c-1c73-eb11-b1ab-000d3a253b40)"
}

如果该字段是多态的,有时属性名称会再次变化:

{
  "parentcustomerid_account@odata.bind": "/accounts(ce9eaaef-f718-ed11-b83e-00224837179f)"
}

欢迎来到 Dynamics Web API 中最令人困惑的部分之一:查找和多态字段。让我们来拆解一下其中的原理。

Source:

什么是 Dynamics 中的多态字段?

Dynamics 中的某些关系可以指向多种实体类型。

示例元数据:

{
  "LogicalName": "ownerid",
  "Targets": [
    "systemuser",
    "team"
  ]
}

这意味着记录的所有者可以是:

  • 系统用户
  • 团队

其他多态查找的示例包括:

字段可能的目标
owneridsystemuser, team
customeridaccount, contact
regardingobjectid多个实体

从概念上讲,这非常强大:模式允许一个关系字段指向多个表。但它也会导致一些有趣的 API 行为。

同一字段的 3 种不同名称

1️⃣ 元数据名称

在模式或元数据中:ownerid

2️⃣ 读取记录

检索记录时,字段会变为 __value

示例响应:

{
  "_ownerid_value": "151F639c-1c73-eb11-b1ab-000d3a253b40"
}

额外的注释通常会出现:

{
  "_ownerid_value": "GUID",
  "_ownerid_value@Microsoft.Dynamics.CRM.lookuplogicalname": "systemuser",
  "_ownerid_value@OData.Community.Display.V1.FormattedValue": "John Smith"
}

含义:

属性含义
_ownerid_valueGUID
lookuplogicalname(注释)实体类型
FormattedValue(注释)显示值

因此在读取数据时,需要解释这三条信息才能了解关系。

3️⃣ 写入记录

创建或更新记录时,Dynamics 期望 OData 绑定@odata.bind

示例:

{
  "ownerid@odata.bind": "/systemusers(151F639c-1c73-eb11-b1ab-000d3a253b40)"
}

模式:

@odata.bind : "/<entityset>(GUID)"

(其中实体集合名称使用复数形式。)

当多态字段变得更加奇怪时

某些多态查找需要在属性中嵌入实体名称。

示例

{
  "parentcustomerid_account@odata.bind": "/accounts(GUID)"
}
{
  "parentcustomerid_contact@odata.bind": "/contacts(GUID)"
}

模式:

<field>_<entity>_@odata.bind

属性名称本身会根据目标实体而变化,这可能特别令人困惑。

特殊情况:ownerid

ownerid 的行为略有不同。与其他多态字段不同,不需要在属性后添加实体后缀。以下两种写法都可以:

{
  "ownerid@odata.bind": "/systemusers(GUID)"
}
{
  "ownerid@odata.bind": "/teams(GUID)"
}

实体类型是从 URL 中的实体集合推断的,而不是从属性名称推断的。正是这个例外导致开发者常觉得 Dynamics 集成难以预测。

开发者对此的看法

如果你搜索 StackOverflow 或 Dynamics 论坛,你会反复看到相同的问题:

  • 为什么 API 返回 _ownerid_value 而不是 ownerid
  • 为什么某些查找需要 @odata.bind,而其他则需要 field_entity@odata.bind
  • 为什么字段名称会根据是读取还是写入而变化?

在讨论中常见的模式是,开发者通过 反复试验 而非明确的文档来发现正确的格式。API 体现了多年演变的平台架构,这种复杂性渗透到了集成层。

为什么这对集成很重要

如果您正在构建与 Dynamics 的集成——尤其是同步引擎、SaaS 连接器或数据管道——这种复杂性会迅速累积。您的集成代码最终需要处理:

  • 多态查找检测
  • 实体类型解析
  • OData 绑定格式
  • 多种命名约定
  • 响应注释

Source:

更简洁的方法:规范化 CRM 模型

Aurinko,我们正在完成对 canonical CRM API 的 MS Dynamics 支持。主要目标之一是消除开发者体验中的平台特定怪癖。

开发者不再需要处理 _ownerid_valueownerid@odata.bind,只需使用:

  • owner.id
  • owner.type
  • owner.name

Aurinko 在后台处理繁重的工作:

  • 多态查找解析
  • 实体类型检测
  • OData 绑定逻辑
  • Dynamics 命名约定
  • 架构不一致性

其结果是跨 CRM 平台的干净、一致的模型,这样你的集成代码就不必了解每个单独 API 的怪癖。

最后思考

Microsoft Dynamics 是一个功能极其强大的平台,但其 API 也反映了大型企业系统的复杂性。

上下文字段名称
元数据ownerid
读取_ownerid_value
写入ownerid@odata.bind

添加多态后缀规则和注释,就很容易理解为什么开发者常常感到不堪重负。通过抽象这些细节,你可以专注于业务逻辑,而不是底层实现。

我们对 Aurinko 的目标很简单:让 CRM 集成再次变得可预测——有时这需要永远隐藏 _ownerid_value

0 浏览
Back to Blog

相关文章

阅读更多 »