如何:获取 Dataverse 表的元数据(预览版)

表元数据包含应用于 Dataverse 中的表的自定义项。 当组织支持多种语言时,元数据还包含本地化标签。 在代码应用中使用元数据意味着应用可以适应自定义或本地化更改,而无需更改代码。

使用 getMetadata 函数在运行时检索 Dataverse 表(实体)元数据。 此函数轻量整合了通过 Web API 查询表定义的功能,提供对实体定义、属性及关系的强类型访问。

getMetadata 签名

getMetadata 函数需要定义要返回的数据的 GetEntityMetadataOptions 实例。

AccountsService.getMetadata(
  options?: GetEntityMetadataOptions<Account>
): Promise<IOperationResult<Partial<EntityMetadata>>>

注释

必须按照“连接到 Dataverse”中的“设置代码应用”中的步骤初始化 Power SDK 并导入服务文件,然后再调用getMetadata

GetEntityMetadataOptions 参数

设置 getMetadataoptions 参数以选择要检索的元数据:

interface GetEntityMetadataOptions {
  metadata?: Array<String>;
  schema?: {
    columns?: "all" | Array<String>;
    oneToMany?: boolean;
    manyToOne?: boolean;
    manyToMany?: boolean;
  };
}
  • metadata:要提取的实体级属性的数组,例如 ["Privileges","DisplayName","IsCustomizable"]。 有关可查询表属性的完整列表,请参阅 EntityMetadata 属性

  • schema:

    • columns:检索列(属性)元数据 - "all"或列逻辑名称数组(如 ["name","telephone1","createdon"])。 有关可查询属性的完整列表,请参阅 AttributeMetadata 属性。

      注释

      不能指定AttributeMetadata中未包含的属性。 派生类型定义的属性不可用。 这意味着无法访问诸如选项(picklist)列选项等属性,因为它们是由派生类型定义的。

    • oneToManymanyToOnemanyToMany:设置布尔值以包含关系元数据

响应在请求时包括名为 Attributes 类型为 AttributeMetadata 的数组,OneToManyRelationships 类型为 OneToManyRelationshipMetadata 的数组,ManyToOneRelationships 类型为 OneToManyRelationshipMetadata 的数组,以及 ManyToManyRelationships 类型为 ManyToManyRelationshipMetadata 的数组。

例子

以下示例显示了检索和使用表元数据的常见方法。

获取所有列的用户本地化标签

检索用户语言中的显示名称。 使用这些标签来生成表单标签、表格标题和无障碍文本。

async function getColumnDisplayNames() {
// Request all column metadata
const { data } = await AccountsService.getMetadata({
   schema: { columns: 'all' }
});

const columnDisplayNames: Record<string, string> = {};
if (data.Attributes) {
   for (const attr of data.Attributes) {
      const label = attr.DisplayName?.UserLocalizedLabel?.Label;
      if (label) {
      columnDisplayNames[attr.LogicalName] = label;
      }
   }
}

console.log(columnDisplayNames);
// Output: { "accountid": "Account", "name": "Account Name", ... }
return columnDisplayNames;
}

确定表单验证的必填字段

查找表单上生成基于元数据而不是硬编码的客户端验证规则所需的属性。

async function getRequiredFields() {
const { data } = await AccountsService.getMetadata({
   schema: { columns: 'all' }
});
if (!data.Attributes) return [];

// Filter attributes that are required for forms
const requiredColumns = data.Attributes
   .filter(attr => attr.IsRequiredForForm)
   .map(attr => ({
      logicalName: attr.LogicalName,
      displayName: attr.DisplayName?.UserLocalizedLabel?.Label,
      attributeType: attr.AttributeTypeName?.Value
   }));

console.log('Required fields:', requiredColumns);
// Output: [
//   { logicalName: "name", displayName: "Account Name", attributeType: "StringType" },
//   { logicalName: "ownerid", displayName: "Owner", attributeType: "OwnerType" }
// ]

return requiredColumns;
}

映射列类型用于客户端验证

获取属性类型以通知验证和 UI 控件。 选择正确的 UI 控件(例如:日期选取器、货币、选择)并一致地验证值。

async function getColumnTypes() {
  const { data } = await AccountsService.getMetadata({
    schema: { columns: 'all' }
  });

  if (!data.Attributes) return [];

  // Map attributes to their types for validation
  const columnTypes = data.Attributes.map(attr => ({
    logicalName: attr.LogicalName,
    attributeType: attr.AttributeTypeName?.Value,
  }));

  console.log('Column types:', columnTypes);
  // Output: [
  //   {
  //     logicalName: "accountid",
  //     attributeType: "UniqueidentifierType",
  //   },
  //   {
  //     logicalName: "name",
  //     attributeType: "StringType",
  //   },
  //   {
  //     logicalName: "revenue",
  //     attributeType: "MoneyType",
  //   },
  //   {
  //     logicalName: "createdon",
  //     attributeType: "DateTimeType",
  //   }
  // ]
  
  return columnTypes;
}

发现查找关系(多对一)

查找哪些查找字段指向其他表,以基于关系动态生成查找 UI 和导航。

async function getLookupRelationships() {
  const { data } = await AccountsService.getMetadata({
    metadata: ['LogicalName', 'DisplayName'],
    schema: { 
      manyToOne: true  // Get lookup relationships
    }
  });

  if (!data.ManyToOneRelationships) return [];

  // Get all lookup fields pointing to other tables
  const lookupRelationships = data.ManyToOneRelationships.map(rel => ({
    lookupField: rel.ReferencingAttribute,
    relatedTable: rel.ReferencedEntity,
    relatedTableAttribute: rel.ReferencedAttribute,
    relationshipName: rel.SchemaName,
  }));

  console.log('Lookup relationships:', lookupRelationships);
  // Output: [
  //   {
  //     lookupField: "primarycontactid",
  //     relatedTable: "contact",
  //     relatedTableAttribute: "contactid",
  //     relationshipName: "account_primary_contact",
  //   },
  //   {
  //     lookupField: "ownerid",
  //     relatedTable: "systemuser",
  //     relatedTableAttribute: "systemuserid",
  //     relationshipName: "owner_accounts",
  //   }
  // ]
  
  return lookupRelationships;

最佳做法

  • 缓存元数据 :元数据调用可能很大。 在应用启动或每个会话时缓存。
  • 仅请求所需内容:为了性能,请优先选择列列表而不是"all"
  • 防御性访问:在访问嵌套值之前检查属性是否存在(例如: DisplayName?.UserLocalizedLabel?.Label
  • 使用 TypeScript 类型 :依靠 Dataverse Web API 生成的类型来获得更安全的代码。