如何检查是否定义了字段?

时间:2013-01-15 11:13:47

标签: c# metadata dynamics-crm-2011

this blog中,展示了如何检索字段的元数据。

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

原因是当我执行 QueryExpression 时,我需要知道要包含在 ColumnSet 中的列。< / p>

现在的Q&amp; D代码就是这个。

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;
}

3 个答案:

答案 0 :(得分: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。虽然在这种情况下它不能给你任何问题(属性 在那里),在其他情况下,如果有多个元素满足条件,你可能会得到一个异常(如果你寻找匹配多个属性或做其他可能导致这种情况的事情。

答案 1 :(得分:3)

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

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

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

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

var defined = response.EntityMetadata
                      .Attributes
                      .SingleOrDefault(a => a.LogicalName == fieldName) != null;

答案 2 :(得分: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
}

使用查询表达式有两个优点,你可以针对作为主键的id运行它(你不关心id,如果字段不是&#,代码将抛出异常# 39; t存在,或者如果成功则返回1或没有记录)。简而言之,目的不是找到记录,而是要查看列中是否强制例外。

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

我已经在CRM上进行了多次测试,在多次/单次调用元数据与多次/单次检索多次调用之间发生异常(使用C#秒表和反转代码顺序等)。例外总是优于元数据。如果您在同一代码中执行多个调用,它的跳转速度会快3倍(我猜测优化会发挥作用)。无论哪种方式,瓶颈都是对元数据服务的调用,在您引入缓存和更多代码复杂性之前,无法对其进行优化。此外,如果该字段存在,您将无法获得异常,这意味着还有另一个性能奖励。

我没有经过测试的唯一情况是针对一个使用频繁的实体运行...但是如果你的数据库如此难以使用,那么nolock检索无法在可接受的时间范围内返回更大的问题值得担心!