使用 Web API 执行条件操作

Microsoft Dataverse支持使用称为 ETags 的标准 HTTP 资源版本控制机制的条件操作。 使用 Web API 使用条件操作来优化记录检索、限制更新插入操作,并应用乐观并发,以防止覆盖其他人所做的更改。

ETag 和资源版本控制机制

HTTP 协议为标识资源的特定版本定义了 实体标记,或简称为 ETag。 ETag 是不透明的标识符,其确切值取决于实现。 ETag 值分为两种:强验证和弱验证。 强验证表明,如果特定 URI 标识的唯一资源对应的 ETag 值未发生变化,则该资源在二进制级别上是相同的。 弱验证仅保证资源表示形式对于相同的 ETag 值在语义上等效。

Dataverse 为每个实体实例生成一个弱验证属性 @odata.etag,并为每个检索到的实体记录自动返回此属性。 有关详细信息,请参阅 使用 Web API 检索表行。

If-Match 和 If-None-Match 标头

使用带有 ETag 值的 If-Match 和 If-None-Match 标头检查当前版本的资源是否与上次检索的资源版本匹配、匹配任何以前的版本或不匹配任何版本。 这些比较构成了条件操作支持的基础。 Dataverse 提供 ETag 来支持条件检索、乐观并发和有限的 upsert 操作。

Warning

客户端代码不应对 ETag 的特定值赋予任何意义,也不应对 ETag 之间除相等或不相等外的任何明显关系赋予意义。 例如,不保证较新版本资源的 ETag 值大于早期版本的 ETag 值。 此外,用于生成新 ETag 值的算法可能会在某个服务的各个版本发布之间更改,而不会另行通知。

条件检索

Etag 有助于在多次访问同一记录时优化记录检索。 如果之前检索了记录,则使用 If-None-Match 标头传递 ETag 值,以便仅在该记录自上次检索以来发生更改时请求数据。 如果数据已更改,请求将返回 HTTP 状态 200 OK,并在正文中包含最新数据。 如果数据保持不变,请求将返回 HTTP 状态代码 304 Not Modified ,以指示记录未修改。

下面的示例消息对会在自你上次检索该数据以来数据未发生更改且 Etag 值为 00000000-0000-0000-0000-000000000001 时,返回一个其 accountid 等于 W/"468026" 的帐户记录的数据。

请求:

GET [Organization URI]/api/data/v9.2/accounts(00000000-0000-0000-0000-000000000001)?$select=accountcategorycode,accountnumber,creditonhold,createdon,numberofemployees,name,revenue   HTTP/1.1  
Accept: application/json  
OData-MaxVersion: 4.0  
OData-Version: 4.0  
If-None-Match: W/"468026"  

响应:

HTTP/1.1 304 Not Modified  
Content-Type: application/json; odata.metadata=minimal  
OData-Version: 4.0  

以下部分介绍使用条件检索的限制。

表必须已启用乐观并发

使用以下 Web API 请求检查表是否启用了乐观并发。 已启用乐观并发的表已将 EntityMetadata.IsOptimisticConcurrencyEnabled 属性设置为 true。 使用此 URL 检索值:

GET [Organization URI]/api/data/v9.2/EntityDefinitions(LogicalName='<Entity Logical Name>')?$select=IsOptimisticConcurrencyEnabled

此示例从联系人表中检索值:

请求:

GET [Organization URI]/api/data/v9.2/EntityDefinitions(LogicalName='contact')?$select=IsOptimisticConcurrencyEnabled  HTTP/1.1  
Accept: application/json  
OData-MaxVersion: 4.0  
OData-Version: 4.0  

响应:

HTTP/1.1 200 OK  
Content-Type: application/json; odata.metadata=minimal  
OData-Version: 4.0

{
   "@odata.context": "[Organization URI]/api/data/v9.2/$metadata#EntityDefinitions(IsOptimisticConcurrencyEnabled)/$entity",
   "MetadataId": "608861bc-50a4-4c5f-a02c-21fe1943e2cf",
   "IsOptimisticConcurrencyEnabled": true
}

查询不得包含$expand

Etag 只能检测要检索的单个记录是否已更改。 $expand在查询中使用时,可能会返回更多记录,并且无法检测其中是否有任何记录已更改。 如果查询包含 $expand,则请求永远不会返回 304 Not Modified。

查询不得包含批注

在 GET 请求中包含 Prefer: odata.include-annotations 标头时,服务器永远不会返回 304 Not Modified。 批注的值可以引用相关记录中的值。 这些记录可能已更改,服务器无法检测到此更改,因此指示未发生任何更改会不正确。

限制 upsert 操作

upsert 操作创建记录(如果不存在);否则,它会更新现有记录。 但是,可以使用 ETag 进一步限制 upsert 操作,以防止创建或阻止更新。

防止在 upsert 中创建

如果要更新数据,并且有可能有意删除该记录,则你可能不想重新创建记录。 若要防止出现此情况,请在请求中添加值为 * 的 If-Match 标头。

请求:

PATCH [Organization URI]/api/data/v9.2/accounts(00000000-0000-0000-0000-000000000001) HTTP/1.1  
Content-Type: application/json  
OData-MaxVersion: 4.0  
OData-Version: 4.0  
If-Match: *  
  
{  
    "name": "Updated Sample Account ",  
    "creditonhold": true,  
    "address1_latitude": 47.639583,  
    "description": "This is the updated description of the sample account",  
    "revenue": 6000000,  
    "accountcategorycode": 2  
}  

响应:

如果服务器找到记录,则会收到状态 204 No Content正常的响应。 如果服务器找不到记录,则会收到以下响应,状态为 404 Not Found。

HTTP/1.1 404 Not Found  
OData-Version: 4.0  
Content-Type: application/json; odata.metadata=minimal  
  
{  
 "error": {  
  "code": "",  
  "message": "account With Id = 00000000-0000-0000-0000-000000000001 Does Not Exist"
 }  
}  

在 upsert 中阻止更新

如果要插入数据,系统中可能已存在具有相同 id 值的记录。 你可能不想更新此现有记录。 若要防止更新记录,请向请求添加一个值为“*”的 If-None-Match 标头。

请求:

PATCH [Organization URI]/api/data/v9.2/accounts(00000000-0000-0000-0000-000000000001) HTTP/1.1  
Content-Type: application/json  
OData-MaxVersion: 4.0  
OData-Version: 4.0  
If-None-Match: *  
  
{  
    "name": "Updated Sample Account ",  
    "creditonhold": true,  
    "address1_latitude": 47.639583,  
    "description": "This is the updated description of the sample account",  
    "revenue": 6000000,  
    "accountcategorycode": 2  
}  

响应:
如果未找到记录,则会收到状态为 204 No Content 的正常响应。 如果找到记录,则会收到以下状态为 412 Precondition Failed 的响应。

HTTP/1.1 412 Precondition Failed  
OData-Version: 4.0  
Content-Type: application/json; odata.metadata=minimal  
  
{  
  "error":{  
   "code":"",  
   "message":"A record with matching key values already exists."
  }  
}  

应用乐观并发

使用乐观并发来检测记录自上次检索后是否已被修改。 如果要更新或删除的记录自您检索后已在服务器上发生更改,则可能不希望完成更新或删除操作。 使用以下模式可以检测这种情况、检索记录的最新版本,并应用任何必要的条件来重新评估是否再次尝试该操作。

在删除时应用乐观并发

以下针对具有 accountid 和 00000000-0000-0000-0000-000000000001 的帐户的删除请求失败,因为随 If-Match 标头发送的 ETag 值与当前值不同。 如果值匹配,则状态为 204 No Content。

请求:

DELETE [Organization URI]/api/data/v9.2/accounts(00000000-0000-0000-0000-000000000001) HTTP/1.1  
If-Match: W/"470867"  
Accept: application/json  
OData-MaxVersion: 4.0  
OData-Version: 4.0  

响应:

HTTP/1.1 412 Precondition Failed  
Content-Type: application/json; odata.metadata=minimal  
OData-Version: 4.0  
  
{  
  "error":{  
    "code":"","message":"The version of the existing record doesn't match the RowVersion property provided." 
  }  
}  

在更新时应用乐观并发

由于随 00000000-0000-0000-0000-000000000001 标头发送的 ETag 值不同于当前值,因此针对具有 If-Match 的 accountid 帐户的以下更新请求失败。 如果值匹配,则状态为 204 No Content。

请求:

PATCH [Organization URI]/api/data/v9.2/accounts(00000000-0000-0000-0000-000000000001) HTTP/1.1  
If-Match: W/"470867"  
Accept: application/json  
OData-MaxVersion: 4.0  
OData-Version: 4.0  
  
{"name":"Updated Account Name"}  

响应:

HTTP/1.1 412 Precondition Failed  
Content-Type: application/json; odata.metadata=minimal  
OData-Version: 4.0  
  
{  
  "error":{  
    "code":"","message":"The version of the existing record doesn't match the RowVersion property provided."
  }  
}  

另请参阅

Web API 条件作示例 (PowerShell)
Web API 条件作示例 (C#)
Web API 条件作示例 (客户端 JavaScript)
使用 Web API 执行操作
撰写 Http 请求并处理错误