我是微軟Dynamics 365 & Power Platform方面的工程師羅勇,也是2015年7月到2018年6月連續(xù)三年Dynamics CRM/Business Solutions方面的微軟最有價值專家(Microsoft MVP),歡迎關(guān)注我的微信公眾號 MSFTDynamics365erLuoYong ,回復(fù)377或者20191109可方便獲取本文,同時可以在第一間得到我發(fā)布的最新博文信息,follow me!
我前面的博文 Dynamics 365 Customer Engagement的標準導(dǎo)入不支持并行導(dǎo)入了嗎? 提供了多進程使用ExecuteMultipleRequest導(dǎo)入數(shù)據(jù)的程序,速度雖然挺快的,但是有一個問題,導(dǎo)入失敗的并不知道是哪些,沒有辦法統(tǒng)計,這里我改善一下。
關(guān)于ExecuteMultipleRequest,請參考官方文檔,Use ExecuteMultiple to improve performance for bulk data load ,官方代碼示例請參考 ExecuteMultipleRequest Class ,本博文參考了Magnetism 的Dynamics CRM ExecuteMultipleResponse – Analysing the Results 。
要做到成功的成功,失敗的失敗,記得要將 ExecuteMultipleSettings 的 ContinueOnError 設(shè)置為 true,要記錄失敗的原因記得要將 ExecuteMultipleSettings 的 ReturnResponses 設(shè)置為 true。
直接上代碼:
using Microsoft.Xrm.Sdk; using Microsoft.Xrm.Sdk.Client; using Microsoft.Xrm.Sdk.Messages; using System; using System.Collections.Generic; using System.Configuration; using System.IO; using System.ServiceModel; using System.Threading; namespace BulkImportRecords { class Program { public static IServiceManagement<IOrganizationService> sm; public static AuthenticationCredentials authCredentials; static int importsequencenumberstartat = Convert.ToInt32(ConfigurationManager.AppSettings["importsequencenumberstartat"]); static int threadcount = Convert.ToInt32(ConfigurationManager.AppSettings["threadcount"]); static string resultFile = ConfigurationManager.AppSettings["resultFile"]; static void Main(string[] args) { sm = ServiceConfigurationFactory.CreateManagement<IOrganizationService>(new Uri(ConfigurationManager.AppSettings["orgUrl"])); authCredentials = new AuthenticationCredentials(); authCredentials.ClientCredentials.UserName.UserName = ConfigurationManager.AppSettings["userName"]; authCredentials.ClientCredentials.UserName.Password = ConfigurationManager.AppSettings["passWord"]; authCredentials = sm.Authenticate(authCredentials); try { for (var i = 0; i < threadcount; i++) { Thread newThread = new Thread(new ParameterizedThreadStart(Work)); newThread.Start(i); } Console.ReadKey(); } catch (FaultException ex) { Console.WriteLine("程序出現(xiàn)異常:ex.Message=" + ex.Message); Console.ReadKey(); } } static void Work(object data) { ExecuteMultipleResponse multiRep; List<string> content = new List<string>(); try { Console.WriteLine("線程開始" + DateTime.Now.ToLongTimeString() + ";線程ID:" + Thread.CurrentThread.ManagedThreadId + ";接收的參數(shù)值為:" + data.ToString()); int importsequencenumber = importsequencenumberstartat + Convert.ToInt32(data); OrganizationServiceProxy orgSvc = new OrganizationServiceProxy(sm, authCredentials.ClientCredentials); string strReadFilePath = ConfigurationManager.AppSettings["filename"]; int i = 0; int j = 1; int z = 0; ExecuteMultipleRequest multiReqs = new ExecuteMultipleRequest() { Settings = new ExecuteMultipleSettings() { ContinueOnError = true, ReturnResponses = true }, Requests = new OrganizationRequestCollection() }; using (StreamReader srReadFile = new StreamReader(string.Format(strReadFilePath, (Convert.ToInt32(data) + 1).ToString("00")))) { while (!srReadFile.EndOfStream) { string strReadLine = srReadFile.ReadLine(); //讀取每行數(shù)據(jù) if (i != 0)//如果第一行包括標題的話要過濾掉 { content.Add(strReadLine); var arrLine = strReadLine.Split(','); CreateRequest req = new CreateRequest(); var createEntity = new Entity("ly_test"); createEntity["ly_name"] = arrLine[0]; createEntity["ly_singletext1"] = arrLine[1]; createEntity["ly_singletext2"] = arrLine[2]; createEntity["ly_singletext3"] = arrLine[3]; createEntity["importsequencenumber"] = Convert.ToInt32(importsequencenumber); req.Target = createEntity; if (j <= 1000) { multiReqs.Requests.Add(req); } else { multiReqs.Requests = new OrganizationRequestCollection(); multiReqs.Requests.Add(req); j = 1; } if (j == 1000) { multiRep = (ExecuteMultipleResponse)orgSvc.Execute(multiReqs); foreach(var Rep in multiRep.Responses) { if(Rep.Fault != null) { File.AppendAllText(string.Format(resultFile, (Convert.ToInt32(data) + 1).ToString("00")), $"{content[z*1000+Rep.RequestIndex+1]},FAIL,{Rep.Fault.Message}" + Environment.NewLine); } else { File.AppendAllText(string.Format(resultFile, (Convert.ToInt32(data) + 1).ToString("00")), $"{content[z * 1000 + Rep.RequestIndex+1]},OK,{((CreateResponse)Rep.Response).id}" + Environment.NewLine); } } z++; Console.WriteLine("線程:" + Thread.CurrentThread.ManagedThreadId + "-導(dǎo)入完畢" + z*1000 + "條" + DateTime.Now.ToString()); } j++; } else { content.Add($"{strReadLine},結(jié)果,消息"); File.AppendAllText(string.Format(resultFile, (Convert.ToInt32(data) + 1).ToString("00")), content[0] + Environment.NewLine); } i++; } } multiRep = (ExecuteMultipleResponse)orgSvc.Execute(multiReqs); foreach (var Rep in multiRep.Responses) { if (Rep.Fault != null) { File.AppendAllText(string.Format(resultFile, (Convert.ToInt32(data) + 1).ToString("00")), $"{content[z * 1000 + Rep.RequestIndex+1]},FAIL,{Rep.Fault.Message}" + Environment.NewLine); } else { File.AppendAllText(string.Format(resultFile, (Convert.ToInt32(data) + 1).ToString("00")), $"{content[z * 1000 + Rep.RequestIndex+1]},OK,{((CreateResponse)Rep.Response).id}" + Environment.NewLine); } } Console.WriteLine("線程結(jié)束" + DateTime.Now.ToLongTimeString() + ";線程ID:" + Thread.CurrentThread.ManagedThreadId); } catch(FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault> ex) { Console.WriteLine("執(zhí)行遇到異常:" + ex.Detail.ErrorCode + ex.Message + ex.StackTrace); } catch (Exception e) { Console.WriteLine("執(zhí)行遇到異常:" + e.Message + e.StackTrace); } } } }
配套的app.config內(nèi)容如下:
<?xml version="1.0" encoding="utf-8"?> <configuration> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2"/> </startup> <appSettings> <add key="userName" value="crmadmin@luoyong.me"/> <add key="passWord" value="Password"/> <add key="orgUrl" value="https://demo.luoyong.me/XRMServices/2011/Organization.svc"/> <add key="filename" value="D:\dataimport\data{0}.csv"/> <add key="importsequencenumberstartat" value="1000000"/> <add key="threadcount" value="2"/> <add key="resultFile" value="D:\ImportResult{0}.csv"/> </appSettings> </configuration>
為了看到測試效果,我對要導(dǎo)入的實體新建了一個實時工作流如下,如果測試實體的名稱字段包括5或者6就以【已取消】的狀態(tài)停止工作流,并設(shè)置好錯誤信息。
然后我就執(zhí)行后看到生成的執(zhí)行結(jié)果CSV文件如下,如果CSV文件用Excel打開中文是亂碼,就將CSV文件以 UTF-8 with BOM 編碼格式另存為一下就可以了。
可以看到有成功,有失敗的,失敗的告知的原因也是正確的,插入記錄成功的記錄了插入記錄后該記錄的主鍵ID。
聯(lián)系客服