3

このブログでは、フィールドのメタデータを取得する方法を紹介しています。

フィールドが存在するかどうかを確認する方法(上記とtry-catchステートメントの組み合わせ以外)を知りたいのですが。

その理由は、を実行するときにQueryExpression、に含める列を知る必要があるためColumnSetです。

現在のQ&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;
}
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

Another possibility is to load the EntityMetadata for the entity.

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

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

You could cache this in memory or on disk for performance reasons. In order to check whether an attribute is defined you could no access the attributes property

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または成功した場合はレコードなし)。つまり、目的はレコードを見つけることではなく、列を含めると例外が強制されるかどうかを確認することです。

クエリ式の2番目の利点は、nolockを使用して実行できることです。あなたは本当に結果セットを気にしません、ポイントは例外を強制することです。

メタデータへの複数/単一の呼び出しと例外をスローする複数/単一の取得の複数の呼び出しの間で変化するCRMオンラインでいくつかのテストを実行しました(C#ストップウォッチを使用してコードの順序を逆にするなど)。例外は常にメタデータを上回りました。同じコード内で複数の呼び出しを実行している場合は、約3倍速くジャンプします(最適化が機能すると思います)。いずれにせよ、ボトルネックはメタデータサービスへの呼び出しであり、キャッシングとコードの複雑さを導入するまで最適化できません。また、フィールドが存在する場合、例外は発生しません。これは、さらに別のパフォーマンスボーナスを意味します。

私がテストしていない唯一のシナリオは、頻繁に使用されるエンティティに対して実行することです...しかし、データベースにアクセスしすぎて、nolockの取得が許容可能な時間枠で戻らない場合は、おそらくより大きな問題が発生する可能性があります。

于 2016-10-07T10:53:51.357 に答える