3

此博客中,展示了如何检索字段的元数据。

我想知道如何检查(除了上面结合try-catch-statement)一个字段是否存在。

这样做的原因是当我执行我的时QueryExpression,我需要知道在ColumnSet.

现在的问答代码是这样的。

private bool DoesFieldExist(String entityName, String fieldName)
{
  try
  {
    RetrieveAttributeRequest req = new RetrieveAttributeRequest();
    req.EntityLogicalName = entityName;
    req.LogicalName = fieldName;
    RetrieveAttributeResponse resp = (RetrieveAttributeResponse)service.Execute(req);
  }
  catch (Exception) { return false; }
  return true;
}
4

3 回答 3

5
private bool DoesFieldExist(String entityName, String fieldName)
{
  RetrieveEntityRequest request = new RetrieveEntityRequest
  {
    EntityFilters = Microsoft.Xrm.Sdk.Metadata.EntityFilters.Attributes,
    LogicalName = entityName
  };
  RetrieveEntityResponse response 
    = (RetrieveEntityResponse)service.Execute(request);
  return response.EntityMetadata.Attributes.FirstOrDefault(element 
    => element.LogicalName == fieldName) != null;
}
  1. 如果您不喜欢我的示例中的显式引用(并且您应该不喜欢它,因为它很难看) EntityFilters,您需要添加using Microsoft.Xrm.Sdk.Metadata;才能正常工作。

  2. 我更喜欢使用FirstOrDefault而不是SingleOrDefault. 虽然在这种情况下它不会给您带来任何问题(属性是否存在),但在其他情况下,如果有多个元素满足条件,您可能会遇到异常(您应该寻找多个属性的匹配项还是执行其他可能导致这种情况的东西)。

于 2013-01-15T16:20:22.193 回答
3

另一种可能性是为实体加载 EntityMetadata。

var request = new RetrieveEntityRequest
{
    EntityFilters = EntityFilters.Attributes,
    LogicalName = entityName
};

var  response = (RetrieveEntityResponse)_serviceProxy.Execute(request);

出于性能原因,您可以将其缓存在内存或磁盘上。为了检查是否定义了属性,您无法访问 attributes 属性

var defined = response.EntityMetadata
                      .Attributes
                      .SingleOrDefault(a => a.LogicalName == fieldName) != null;
于 2013-01-15T15:28:16.893 回答
2

我知道这对游戏来说有点晚了,但我想为其他想要这样做的人添加一个性能更好的替代方案。

除非您引入某种缓存,否则元数据调用速度非常慢。如果您将元数据调用放入定期执行的插件中,您可能会自找麻烦。(MS 真的需要看看为什么他们的元数据调用如此缓慢并修复它!)。

如果您只想检查一个字段的存在,我会强制异常。诚然,它看起来不太好,一些传道者会对此皱眉,但我发现它的执行速度比元数据调用快 3 倍。这至少将它放在可接受的括号中,以便更定期地执行插件。

这就是我所做的:

try
{
    var query = new QueryExpression("account");
    query.Criteria.AddCondition("accountid", ConditionOperator.Equal, "294450db-46c9-447e-a642-3babf913d800");
    query.NoLock = true;
    query.ColumnSet = new ColumnSet("xyz_fieldname");
    service.RetrieveMultiple(query);
}
catch
{
    // ignored
}

使用查询表达式有 2 个优点,您针对作为主键的 id 运行它(您不关心 id,如果该字段不存在,代码将抛出异常,或者返回 1 或成功则无记录)。简而言之,目的不是查找​​记录,而是查看包含列是否强制异常。

查询表达式的第二个优点是您可以使用 nolock 运行它。你真的不关心结果集,重点是强制异常。

我已经在 CRM 在线上运行了几个测试,在对元数据的多个/单个调用与多个/单个检索引发异常的多个调用之间变化(使用 C# 秒表和反转代码顺序等)。异常总是优于元数据。如果您在同一个代码中执行多个调用,它的速度会提高大约 3 倍(我猜优化会起作用)。无论哪种方式,瓶颈是对元数据服务的调用,除非您引入缓存和更高的代码复杂性,否则无法对其进行优化。此外,如果该字段存在,您将不会获得异常,这意味着另一个绩效奖金。

我没有测试过的唯一场景是针对一个大量使用的实体运行它......但是如果您对数据库的访问如此之大以至于 nolock 检索无法在可接受的时间范围内返回,那么您可能需要担心更大的问题!

于 2016-10-07T10:53:51.357 回答