Windows SharePoint Services (WSS) 的 Lists.UpdateListItems 方法支援透過 CAML 批量新增/修改/刪除列表項目。但當批量資料過大(約超過 600 筆)時,CAML XML 過長會導致伺服器端 SQL 解析錯誤:
"Some part of your SQL statement is nested too deeply. Rewrite the query or break it up into smaller queries."
且前半部資料已寫入、後半部失敗,造成資料不一致。本文提供分批處理的通用解決方案。
典型批量 CAML 結構:
<Batch OnError="Continue">
<Method ID="1" Cmd="New">
<Field Name="Title">Hello</Field>
<Field Name="Document">5</Field>
</Method>
<Method ID="2" Cmd="New"> ... </Method>
</Batch>
當 <Method> 節點過多,WSS 內部 SQL 產生超過巢狀層級限制,導致 XML 被截斷執行。
將大型 <Batch> 依指定批次大小 (建議 300) 拆分為多個小批次,循環呼叫 Web Service,最後合併結果。
/// <summary>
/// 將大型 CAML 批次拆分執行,避免 SQL 巢狀過深錯誤
/// </summary>
public static XmlNode UpdateListItems(Lists listService, string listName, XmlElement elementLargeBatch, int batchSize) {
// 1. 計算分批資訊
int methodCount = elementLargeBatch.ChildNodes.Count;
int batchCount = (int)Math.Ceiling((double)methodCount / batchSize);
// 2. 準備結果文檔
XmlDocument xmlDocResults = new XmlDocument();
XmlElement elementResults = xmlDocResults.CreateElement("Results");
try {
for (int currentBatch = 0; currentBatch < batchCount; currentBatch++) {
int methodStart = currentBatch * batchSize;
int methodEnd = Math.Min(methodStart + batchSize - 1, methodCount - 1);
// 3. 建立小批次 Batch 元素
XmlDocument xmlDocBatch = new XmlDocument();
XmlElement elementSmallBatch = CreateBatch(xmlDocBatch);
// 4. 複製 Method 節點到小批次
for (int i = methodStart; i <= methodEnd; i++) {
XmlElement methodNode = (XmlElement)elementLargeBatch.ChildNodes[i];
elementSmallBatch.AppendChild(xmlDocBatch.ImportNode(methodNode, true));
}
// 5. 執行批次呼叫
XmlNode nodeBatchResult = listService.UpdateListItems(listName, elementSmallBatch);
// 6. 合併結果
foreach (XmlElement resultNode in nodeBatchResult.ChildNodes) {
elementResults.AppendChild(xmlDocResults.ImportNode(resultNode, true));
}
}
} catch (SoapException ex) {
if (ex.Detail == null) throw;
// 保留原始異常詳情
throw new SoapException(ex.Detail.InnerText, ex.Code, ex.Actor, ex.Detail, ex);
}
return elementResults;
}
/// <summary> 建立標準 Batch 元素 </summary>
private static XmlElement CreateBatch(XmlDocument xmlDoc) {
XmlElement batch = xmlDoc.CreateElement("Batch");
batch.SetAttribute("OnError", "Continue");
return batch;
}
ImportNode(node, true) 深度複製,否則會拋出「節點屬於不同文檔」異常。<Results> 根元素包裹所有批次返回的 <Result> 節點,保持呼叫端介面一致。SoapException 重新拋出時攜帶原始 Detail,便於上層診斷。xmlDocBatch.RemoveAll() 釋放臨時文檔資源。batchSize 設為可配置參數,適應不同 WSS 版本/補丁限制。GetListItems) 同樣存在長度限制,可複用此分頁邏輯。此方案已在生產環境穩定運行處理 20,000+ 筆資料同步,有效規避 WSS CAML 長度硬傷,是 SharePoint Web Service 批量操作的標準最佳實踐。