【问题标题】:CRM Dynamics 2013 How to Update Multiple Records From External Source Using ExecuteMultipleRequestCRM Dynamics 2013 如何使用 ExecuteMultipleRequest 从外部源更新多条记录
【发布时间】:2023-03-24 12:03:01
【问题描述】:

我在 CRM 中有一个场景,我需要使用来自外部 sql 数据库表的值更新多个帐户值(文本字段和选项集)。我该如何使用执行多个请求来执行此操作。要求是将 CRM 中的所有帐户数据与来自 sql 表的 ERP 数据同步。这个过程需要自动化,所以我选择使用每天运行的 Windows 服务来更新外部 sql 表中标记为更新的帐户。我正在努力寻找最好的方法,我在 DEV 上的控制台应用程序中测试了这个想法,下面是我的解决方案代码。我的问题是如何使用 ExecuteMultipleRequest 请求更好地做到这一点。

public static void UpdateAllCRMAccountsWithEmbraceAccountStatus(IOrganizationService service, CRM_Embrace_IntegrationEntities3 db)
        {


            List<C_Tarsus_Account_Active_Seven__> crmAccountList = new List<C_Tarsus_Account_Active_Seven__>();

            //Here I get the list from Staging table
            var crmAccounts = db.C_Tarsus_Account_Active_Seven__.Select(x => x).ToList();



            foreach (var dbAccount in crmAccounts)
            {
                CRMDataObjectFour modelObject = new CRMDataObjectFour()
                {
                    ID = dbAccount.ID,
                    Account_No = dbAccount.Account_No,
                    Account_Name = dbAccount.Account_Name,
                    Account_Status = Int32.Parse(dbAccount.Account_Status.ToString()),
                    Country = dbAccount.Country,
                    Terms = dbAccount.Terms
                };
            }


            var officialDatabaseList = crmAccounts;

            //Here I query CRM to
            foreach (var crmAcc in officialDatabaseList)
            {
                QueryExpression qe = new QueryExpression();
                qe.EntityName = "account";
                qe.ColumnSet = new ColumnSet("accountnumber", "new_embraceaccountstatus");
                qe.Criteria.AddCondition("statecode", ConditionOperator.Equal, 0);
                qe.Criteria.AddCondition("accountnumber", ConditionOperator.NotIn, "List of acconts for example"


);

                EntityCollection response = service.RetrieveMultiple(qe);

                //Here I update the optionset value
                foreach (var acc in response.Entities)
                {
                    if (acc.Attributes["accountnumber"].ToString() == crmAcc.Account_No)
                    {
                        if (acc.Contains("new_embraceaccountstatus"))
                        {
                            continue;
                        }
                        else
                        {
                            acc.Attributes["new_embraceaccountstatus"] = new OptionSetValue(Int32.Parse(crmAcc.Account_Status.ToString()));
                        }
                        service.Update(acc);
                    }

                }
            }


        }

我知道这可能不是正确的方法,请告诉我如何使用 ExecuteMultipleRequest 或完全不同的解决方案。

【问题讨论】:

    标签: c# sql dynamics-crm-2013


    【解决方案1】:

    这是我以前用来处理此问题的一些辅助方法:

    public static ExecuteMultipleRequest MultipleRequest { get; set; }
    private const int BatchSize = 250;
    public static long LastBatchTime { get; set; }
    
    private static void Batch(IOrganizationService service, OrganizationRequest request)
    {
        if (MultipleRequest.Requests.Count == BatchSize)
        {
            ExecuteBatch(service);
        }
        MultipleRequest.Requests.Add(request);
    }
    
    private static void ExecuteBatch(IOrganizationService service)
    {
        if (!MultipleRequest.Requests.Any())
        {
            return;
        }
        Log("Executing Batch size {0}.  Last Batch was executed in {1}",MultipleRequest.Requests.Count, LastBatchTime);
        var watch = new System.Diagnostics.Stopwatch();
        watch.Start();
        var response = (ExecuteMultipleResponse)service.Execute(MultipleRequest);
        watch.Stop();
        LastBatchTime = watch.ElapsedMilliseconds;
        Log("Completed Executing Batch in " + watch.ElapsedMilliseconds);
        WriteLogsToConsole();
    
    
        var errors = new List<string>();
        // Display the results returned in the responses.
        foreach (var responseItem in response.Responses)
        {
            // A valid response.
            if (responseItem.Fault != null)
            {
                errors.Add(string.Format(
                    "Error: Execute Multiple Response Fault.  Error Code: {0} Message {1} Trace Text: {2} Error Keys: {3} Error Values: {4} ",
                    responseItem.Fault.ErrorCode,
                    responseItem.Fault.Message,
                    responseItem.Fault.TraceText,
                    responseItem.Fault.ErrorDetails.Keys,
                    responseItem.Fault.ErrorDetails.Values));
            }
        }
        MultipleRequest.Requests.Clear();
        if (errors.Any())
        {
            throw new Exception(string.Join(Environment.NewLine, errors));
        }
    }
    

    然后您可以像这样从正常逻辑中调用它:

    public static void UpdateAllCRMAccountsWithEmbraceAccountStatus(IOrganizationService service, CRM_Embrace_IntegrationEntities3 db)
    {
        List<C_Tarsus_Account_Active_Seven__> crmAccountList = new List<C_Tarsus_Account_Active_Seven__>();
    
        //Here I get the list from Staging table
        var crmAccounts = db.C_Tarsus_Account_Active_Seven__.Select(x => x).ToList();
    
        foreach (var dbAccount in crmAccounts)
        {
            CRMDataObjectFour modelObject = new CRMDataObjectFour()
            {
                ID = dbAccount.ID,
                Account_No = dbAccount.Account_No,
                Account_Name = dbAccount.Account_Name,
                Account_Status = Int32.Parse(dbAccount.Account_Status.ToString()),
                Country = dbAccount.Country,
                Terms = dbAccount.Terms
            };
        }
    
        var officialDatabaseList = crmAccounts;
    
        //Here I query CRM to
        foreach (var crmAcc in officialDatabaseList)
        {
            QueryExpression qe = new QueryExpression();
            qe.EntityName = "account";
            qe.ColumnSet = new ColumnSet("accountnumber", "new_embraceaccountstatus");
            qe.Criteria.AddCondition("statecode", ConditionOperator.Equal, 0);
            qe.Criteria.AddCondition("accountnumber", ConditionOperator.NotIn, "List of acconts for example");
    
            EntityCollection response = service.RetrieveMultiple(qe);
    
            //Here I update the optionset value
            foreach (var acc in response.Entities)
            {
                if (acc.Attributes["accountnumber"].ToString() == crmAcc.Account_No)
                {
                    if (acc.Contains("new_embraceaccountstatus"))
                    {
                        continue;
                    }
                    else
                    {
                        acc.Attributes["new_embraceaccountstatus"] = new OptionSetValue(Int32.Parse(crmAcc.Account_Status.ToString()));
                    }
                    Batch(service, new UpdateRequest { Target = acc });
                }
    
            }
        }
    
        // Call ExecuteBatch to ensure that any batched requests, get executed.
        ExeucteBatch(service)
    }
    

    【讨论】:

    • 虽然 OP 已将问题标记为 2013,但对于 CRM 2016 上的其他人,2016 现在支持 ExecuteTransactionRequest msdn.microsoft.com/en-us/library/…),它将所有请求包装在事务中。
    • 2015 年也支持它@dotnetnetdot
    • 谁能给我一个用于executemultiplerequest的SOAP主体的例子?我不懂c#
    【解决方案2】:

    因为现在是 2013 年,并且您需要同步记录,所以您需要知道一些以前的记录是否已经在 CRM 中,因为根据这些记录,您需要发送一堆 Create's 或 Update's。我会分两批 ExecuteMultiple 来做:

    1) 一批执行查询以查找需要在 CRM 中创建/更新的帐户,具体取决于那里的某些匹配字段。

    2) 另一批次将使用前一个批次一次性生成所有创建/更新操作,具体取决于您从 1) 中获得的响应。

    问题是它们不会在同一个事务中运行,正如@Daryl 所说,这是 2016 年改进的东西。 2016 年还有一个新请求可能会进一步改进,因为您可以将 2 个批次合并为一个:Upsert,从而避免不必要的服务器往返。

    也许这是受到很久以前存在的Mongo Db's upsert 概念的启发?谁知道:)

    【讨论】:

    • 谁能给我一个用于executemultiplerequest的SOAP主体的例子?我不懂c#
    【解决方案3】:

    如果您现在只需要如何执行ExecuteMultipleRequest,则 MSDN 上有示例。 Sample: Execute multiple requests.

    【讨论】:

    • 谁能给我一个用于executemultiplerequest的SOAP主体的例子?我不懂c#
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多