2017-12-13 7 views
2

Microsoft Dynamics CRMでxlsxファイルからユーザー入力データを照合する必要があるプロジェクトで作業しています。1つのCRMコールで複数の別個のエンティティを照会することは可能ですか?

私は、マッチングを実行するメソッドを持っています。

public EntityViewModel Match(EntityViewModel inputEntity) 
{ 

    try 
    { 

     // Connect to the Organization service. 
     // The using statement assures that the service proxy will be properly disposed. 
     using (var serviceProxy = CrmServiceFactory.CreateNew()) 
     { 
      if (!string.IsNullOrEmpty(inputEntity.ClientName)) 
       CrmHelper.ClientMatch(serviceProxy, inputEntity); 

      var product = false; 

      if ((string.IsNullOrEmpty(inputEntity.Category) || inputEntity.Category != revenuecategoryos.Insurance.ToString()) 
       && !string.IsNullOrEmpty(inputEntity.ProductName) && !string.IsNullOrEmpty(inputEntity.ProductNumber) && inputEntity.ClientId != Guid.Empty) 
      { 

       product = CrmHelper.ClientAssetMatch(serviceProxy, inputEntity); 
      } 


      if (((string.IsNullOrEmpty(inputEntity.Category) && !product) || inputEntity.Category == revenuecategoryos.Insurance.ToString()) && !string.IsNullOrEmpty(inputEntity.ProductNumber) && !string.IsNullOrEmpty(inputEntity.ProductName)) 
      { 

       CrmHelper.InsuranceMatch(serviceProxy, inputEntity);     
      } 

      if (!string.IsNullOrEmpty(inputEntity.ProductProvider) && !string.IsNullOrEmpty(inputEntity.ProductNumber) && !string.IsNullOrEmpty(inputEntity.ProductName)) 
      { 

       CrmHelper.ProviderMatch(serviceProxy, inputEntity); 
      } 

      if (inputEntity.Type == revenuetypeos.Upfront.ToString() && !string.IsNullOrEmpty(inputEntity.Opportunity)) 
      { 

       CrmHelper.OpportunityMatch(serviceProxy, inputEntity); 
      } 

      return inputEntity; 
     } 
    } 
    catch (Exception ex) 
    { 
     //handle the exception 
    } 
} 

ご覧のとおり、5つのメソッドを呼び出して一致を確認します。彼らは5つの異なる、別々のエンティティを照会します。

internal static bool ClientMatch(IOrganizationService crm, EntityViewModel inputEntity) 
{ 
    #region Using Retrieve Multiple 

    // Create a column set holding the names of the columns to be retrieved. 
    var cols = new ColumnSet("fullname"); 

    // Create the query. 
    var query = new QueryExpression 
    { 
     EntityName = Xrm.Contact.EntityLogicalName, 
     ColumnSet = cols 
    }; 

    query.Criteria.AddCondition("fullname", ConditionOperator.Equal, inputEntity.ClientName); 
    query.Criteria.AddCondition("statecode", ConditionOperator.Equal, (int)ContactState.Active); 

    // Create the request object. 
    var clientList = crm.RetrieveMultiple(query); 

    // If there's not only one existing record in CRM with this key value 
    if (recordList == null || recordList.Entities == null || recordList.Entities.Count != 1) 
    { 
     // if we couldn't find only one record with same key value (maybe none, maybe multiple records) 
     query.Criteria.Conditions.Clear(); 

     query.Criteria.AddCondition("importmetadata", ConditionOperator.Like, 
      string.Format("%{0}, {1}, {2}%", inputEntity.ProductName, inputEntity.ProductNumber, inputEntity.ProductProvider)); 
     query.Criteria.AddCondition("statecode", ConditionOperator.Equal, (int)ContactState.Active); 

     recordList = crm.RetrieveMultiple(query); 
    } 

    if (recordList != null && recordList.Entities != null && recordList.Entities.Count == 1) 
    { 
     var client = recordList.Entities[0]; 

     inputEntity.ClientId = client.Id; 
     inputEntity.ClientName = client.Attributes.Contains("fullname") ? client.Attributes["fullname"].ToString() : string.Empty; 

     return true; 
    } 

    return false; 

    #endregion Using Retrieve Multiple 
} 

internal static bool ClientAssetMatch(IOrganizationService crm, EntityViewModel inputEntity) 
{ 
    #region Using Retrieve Multiple 

    // Create a column set holding the names of the columns to be retrieved. 
    var cols = new ColumnSet(new[] { "assetname", "accountnumber", "revenuecategory" }); 

    // Build the filter based on the condition. 
    var filter = new FilterExpression 
    { 
     FilterOperator = LogicalOperator.And 
    }; 
    filter.AddCondition("contactid", ConditionOperator.Equal, inputEntity.ClientId); 

    // Create a LinkEntity to link the owner's information to the account. 
    var link = new LinkEntity 
    { 
     LinkCriteria = filter, 
     LinkFromEntityName = clientasset.EntityLogicalName, 
     LinkFromAttributeName = "primaryclient", 
     LinkToEntityName = Xrm.Contact.EntityLogicalName, 
     LinkToAttributeName = "contactid" 
    }; 

    // Create the query. 
    var query = new QueryExpression 
    { 
     EntityName = clientasset.EntityLogicalName, 
     ColumnSet = cols 
    }; 

    query.LinkEntities.Add(link); 

    query.Criteria.AddCondition("statecode", ConditionOperator.Equal, (int)clientassetState.Active); 
    query.Criteria.AddCondition("assetname", ConditionOperator.Equal, inputEntity.ProductName); 
    query.Criteria.AddCondition("accountnumber", ConditionOperator.Equal, inputEntity.ProductNumber); 

    // Create the request object. 
    var recordList = crm.RetrieveMultiple(query); 

    if (recordList == null || recordList.Entities == null || recordList.Entities.Count != 1) 
    { 
     // if we couldn't find only one record with same key value (maybe none, maybe multiple records) 
     query.Criteria.Conditions.Clear(); 

     query.Criteria.AddCondition("importmetadata", ConditionOperator.Like, 
      string.Format("%{0}, {1}%", inputEntity.ProductName, inputEntity.ProductNumber)); 
     query.Criteria.AddCondition("statecode", ConditionOperator.Equal, (int)clientassetState.Active); 

     recordList = crm.RetrieveMultiple(query); 
    } 

    if (recordList.Entities.Count == 1) 
    { 
     var client = recordList.Entities[0]; 

     inputEntity.ProductId = client.Id; 
     inputEntity.ProductName = client.Attributes.Contains("assetname") ? client.Attributes["assetname"].ToString() : string.Empty; 
     inputEntity.ProductNumber = client.Attributes.Contains("accountnumber") ? client.Attributes["accountnumber"].ToString() : string.Empty; 
     inputEntity.IsClientAsset = true; 

     if (string.IsNullOrEmpty(inputEntity.Category) && client.Attributes.Contains("revenuecategory") && client.Attributes["revenuecategory"] != null) 
      inputEntity.Category = GetCategory(((OptionSetValue)client.Attributes["revenuecategory"]).Value); 

     return true; 
    } 

    return false; 

    #endregion Using Retrieve Multiple 
} 

internal static bool InsuranceMatch(IOrganizationService crm, EntityViewModel inputEntity) 
{ 
    #region Using Retrieve Multiple 

    // Create a column set holding the names of the columns to be retrieved. 
    var cols = new ColumnSet(new[] { "name", "policynumber" }); 

    // Build the filter based on the condition. 
    var filter = new FilterExpression 
    { 
     FilterOperator = LogicalOperator.And 
    }; 
    filter.AddCondition("contactid", ConditionOperator.Equal, inputEntity.ClientId); 

    // Create a LinkEntity to link the owner's information to the account. 
    var link = new LinkEntity 
    { 
     LinkCriteria = filter, 
     LinkFromEntityName = personalinsurance.EntityLogicalName, 
     LinkFromAttributeName = "individualowner", 
     LinkToEntityName = Xrm.Contact.EntityLogicalName, 
     LinkToAttributeName = "contactid" 
    }; 

    // Create the query. 
    var query = new QueryExpression 
    { 
     EntityName = personalinsurance.EntityLogicalName, 
     ColumnSet = cols 
    }; 

    query.LinkEntities.Add(link); 


    query.Criteria.AddCondition("statecode", ConditionOperator.Equal, (int)personalinsuranceState.Active); 
    query.Criteria.AddCondition("name", ConditionOperator.Equal, inputEntity.ProductName); 
    query.Criteria.AddCondition("policynumber", ConditionOperator.Equal, inputEntity.ProductNumber); 

    // Create the request object. 
    var recordList = crm.RetrieveMultiple(query); 

    if (recordList == null || recordList.Entities == null || recordList.Entities.Count != 1) 
    { 
     // if we couldn't find only one record with same key value (maybe none, maybe multiple records) 
     query.Criteria.Conditions.Clear(); 
     query.Criteria.AddCondition("importmetadata", ConditionOperator.Like, 
      string.Format("%{0}, {1}%", inputEntity.ProductName, inputEntity.ProductNumber)); 
     query.Criteria.AddCondition("statecode", ConditionOperator.Equal, (int)personalinsuranceState.Active); 

     recordList = crm.RetrieveMultiple(query); 
    } 

    if (recordList.Entities.Count == 1) 
    { 
     var client = recordList.Entities[0]; 

     inputEntity.ProductId = client.Id; 
     inputEntity.ProductName = client.Attributes.Contains("name") ? client.Attributes["name"].ToString() : string.Empty; 
     inputEntity.ProductNumber = client.Attributes.Contains("policynumber") ? client.Attributes["policynumber"].ToString() : string.Empty; 
     inputEntity.IsClientAsset = false; 

     // If it's a personal insurance, it's always an Insurance Revenue Category type 
     inputEntity.Category = revenuecategoryos.Insurance.ToString(); 

     return true; 
    } 

    return false; 

    #endregion Using Retrieve Multiple 
} 
internal static bool ProviderMatch(IOrganizationService crm, EntityViewModel inputEntity) 
{ 
    #region Using Retrieve Multiple 

    // Create a column set holding the names of the columns to be retrieved. 
    var cols = new ColumnSet("name"); 

    // Create the query. 
    var query = new QueryExpression 
    { 
     EntityName = Account.EntityLogicalName, 
     ColumnSet = cols 
    }; 

    query.Criteria.AddCondition("name", ConditionOperator.Equal, inputEntity.ProductProvider); 
    query.Criteria.AddCondition("statecode", ConditionOperator.Equal, (int)AccountState.Active); 

    // Create the request object. 
    var recordList = crm.RetrieveMultiple(query); 

    // If there's not only one existing record in CRM with this key value 

    if (recordList == null || recordList.Entities == null || recordList.Entities.Count != 1) 
    { 
     // if we couldn't find only one record with same key value (maybe none, maybe multiple records) 
     query.Criteria.Conditions.Clear(); 

     query.Criteria.AddCondition("importmetadata", ConditionOperator.Like, "%" + inputEntity.ProductProvider + "%"); 
     query.Criteria.AddCondition("statecode", ConditionOperator.Equal, (int)AccountState.Active); 

     recordList = crm.RetrieveMultiple(query); 
    } 

    if (recordList != null && recordList.Entities != null && recordList.Entities.Count == 1) 
    { 
     var client = recordList.Entities[0]; 

     inputEntity.ProductProviderId = client.Id; 
     inputEntity.ProductProvider = client.Attributes.Contains("name") ? client.Attributes["name"].ToString() : string.Empty; 

     return true; 
    } 

    return false; 

    #endregion Using Retrieve Multiple 
} 
internal static bool OpportunityMatch(IOrganizationService crm, EntityViewModel inputEntity) 
{ 
    #region Using Retrieve Multiple 

    // Create a column set holding the names of the columns to be retrieved. 
    var cols = new ColumnSet("name"); 

    // Create the query. 
    var query = new QueryExpression 
    { 
     EntityName = Opportunity.EntityLogicalName, 
     ColumnSet = cols 
    }; 

    query.Criteria.AddCondition("name", ConditionOperator.Equal, inputEntity.Opportunity); 
    query.Criteria.AddCondition("statecode", ConditionOperator.NotEqual, (int)OpportunityState.Lost); 

    // Create the request object. 
    var opportunityList = crm.RetrieveMultiple(query); 

    // If there's not only one existing record in CRM with this key value 
    if (opportunityList == null || opportunityList.Entities == null || opportunityList.Entities.Count != 1) 
    { 
     // if we couldn't find only one record with same key value (maybe none, maybe multiple records) 
     query.Criteria.Conditions.Clear(); 

     query.Criteria.AddCondition("importmetadata", ConditionOperator.Like, "%" + inputEntity.Opportunity + "%"); 
     query.Criteria.AddCondition("statecode", ConditionOperator.NotEqual, (int)OpportunityState.Lost); 

     opportunityList = crm.RetrieveMultiple(query); 
    } 

    if (recordList != null && recordList.Entities != null && recordList.Entities.Count == 1) 
    { 
     var opportunity = recordList.Entities[0]; 

     inputEntity.OpportunityId = opportunity.Id; 
     inputEntity.Opportunity = opportunity.Attributes.Contains("name") ? opportunity.Attributes["name"].ToString() : string.Empty; 

     return true; 
    } 

    return false; 

    #endregion Using Retrieve Multiple 
} 

通常、このコードは15行未満の小さなExcelファイルで正常に動作します。しかし、ユーザーが大きなファイルを入力すると、パフォーマンスが極端に遅くなります。特に、2人以上のユーザーが同時にファイルをアップロードした場合(マッチングプロセス全体がキューで起動されたwebjobによって管理されるため)私は複数の項目を同時にマッチングするためにマルチタスクを実装しようとしましたが、何も変わりませんでした。

おそらく私が必要とするのは、上の5つの機能を結合する方法を見つけることだと考えています。しかし、これまでのところ、私はそれを行う方法を見つけることができないようです。 インターフェイスIOrganizationServiceのRetrieveMultipleメソッドは、一度に1つのQueryExpressionオブジェクトしか処理できないようです。上記の5つのエンティティは別々です。私の質問は、1つのcrm呼び出しでそれらを照会することは可能ですか?もしそうなら、どうですか?そうでない場合は、パフォーマンスを改善する他の方法はありますか?当社の顧客は、マッチングプロセスを待つのに10分以上を費やしたくないことは確かです。彼らはより速いものが必要です。ありがとう。

答えて

1

はい、ExecuteMultipleRequestクラスを使用すると、パフォーマンスが向上するかどうかを確認できます。

ここでは、1つのマルチリクエスト内の4つのRetrieveMultipleRequestsをアカウントに、4つの連絡先を1つのマルチリクエストに送信し、結果の名前を出力する例を示します。必要なエンティティのクエリを処理するためにそれを適応させる必要がありますが、別々の5つのエンティティをクエリするとうまく動作します。

出力:

Ouput

using Microsoft.Xrm.Sdk; 
using Microsoft.Xrm.Sdk.Messages; 
using Microsoft.Xrm.Sdk.Query; 
using System; 
using System.Collections.Generic; 

namespace StackOverflow 
{ 
    public class App_ExecuteMultiple 
    { 
     private IOrganizationService svc; 

     public App_ExecuteMultiple(IOrganizationService svc) 
     { 
      this.svc = svc; 
     } 

     public void Run() 
     { 
      var multiReq = new ExecuteMultipleRequest() 
      { 
       Settings = new ExecuteMultipleSettings() 
       { 
        ContinueOnError = true, 
        ReturnResponses = true 
       },    
       Requests = new OrganizationRequestCollection() 
      }; 

      accountIds().ForEach(i => multiReq.Requests.Add(getAccountRequest(i))); 

      contactIds().ForEach(i => multiReq.Requests.Add(getContactRequest(i))); 

      var multiResponse = (ExecuteMultipleResponse)svc.Execute(multiReq); 

      foreach (var singleResponse in multiResponse.Responses) 
      { 
       var retrieveResponse = (RetrieveMultipleResponse)singleResponse.Response; 

       var attributeName = ""; 

       var logicalName = retrieveResponse.EntityCollection[0].LogicalName; 

       if (logicalName == "account") 
       { 
        attributeName = "name"; 
       } 
       else if (logicalName == "contact") 
       { 
        attributeName = "fullname"; 
       } 

       var name = retrieveResponse.EntityCollection[0].GetAttributeValue<string>(attributeName); 

       Console.WriteLine(name); 
      } 
     } 

     private RetrieveMultipleRequest getAccountRequest(Guid id) 
     { 
      return new RetrieveMultipleRequest 
      { 
       Query = getAccountQuery(id) 
      }; 
     } 

     private QueryExpression getAccountQuery(Guid id) 
     { 
      return new QueryExpression 
      { 
       EntityName = "account", 
       ColumnSet = new ColumnSet(true), 
       Criteria = new FilterExpression 
       { 
        FilterOperator = LogicalOperator.And, 
        Conditions = 
        { 
         new ConditionExpression 
         { 
          AttributeName = "accountid", 
          Operator = ConditionOperator.Equal, 
          Values = { id } 
         } 
        } 
       } 
      }; 
     } 

     private List<Guid> accountIds() 
     { 
      return new List<Guid> 
      { 
       new Guid("{04C82C07-98F1-E611-9438-00155D6FD706}"), 
       new Guid("{06C82C07-98F1-E611-9438-00155D6FD706}"), 
       new Guid("{08C82C07-98F1-E611-9438-00155D6FD706}"), 
       new Guid("{0AC82C07-98F1-E611-9438-00155D6FD706}") 
      }; 
     } 

     private RetrieveMultipleRequest getContactRequest(Guid id) 
     { 
      return new RetrieveMultipleRequest 
      { 
       Query = getContactQuery(id) 
      }; 
     } 

     private QueryExpression getContactQuery(Guid id) 
     { 
      return new QueryExpression 
      { 
       EntityName = "contact", 
       ColumnSet = new ColumnSet(true), 
       Criteria = new FilterExpression 
       { 
        FilterOperator = LogicalOperator.And, 
        Conditions = 
        { 
         new ConditionExpression 
         { 
          AttributeName = "contactid", 
          Operator = ConditionOperator.Equal, 
          Values = { id } 
         } 
        } 
       } 
      }; 
     } 

     private List<Guid> contactIds() 
     { 
      return new List<Guid> 
      { 
       new Guid("{6AC82C07-98F1-E611-9438-00155D6FD706}"), 
       new Guid("{6CC82C07-98F1-E611-9438-00155D6FD706}"), 
       new Guid("{6EC82C07-98F1-E611-9438-00155D6FD706}"), 
       new Guid("{70C82C07-98F1-E611-9438-00155D6FD706}") 
      }; 
     } 
    } 
} 
+0

感謝。私は問題を解決できるかどうかを試してみましょう。 – Anthony

+0

私はそれを統合しています。でも、まだ私を悩ませていることは、1つのクエリが別のクエリの出力結果に依存している場合です。 上記のコードでわかるように、メソッド "CrmHelper.MatchPersonalInsurance(serviceProxy、revenueEntity);"メソッド "CrmHelper.MatchClientAsset(serviceProxy、revenueEntity);"によって "product"の値が返された場合にのみ実行されます。偽です。 このRetrieveMultipleRequestオブジェクトが別のRetrieveMultipleRequestオブジェクトの結果に依存することを確認するにはどうすればよいですか? – Anthony

+0

最初に実行する必要がある扶養家族は、個別にまたは独自のバッチで作成してください。クエリが5つあっても、10分かかると思われます。照会している1つ以上のエンティティに多数のレコードがありますか?また、すぐに利用できる代替キーの機能を調べることもできます。 – Aron

関連する問題