Microsoft的WSS(Windows Sharepoint Services)公开了很多用于访问和管理Sharepoint站点的方法,在调用这些方法时可以通过CAML(Collaborative Application Markup Language)进行一些操作。其中Lists.UpdateListItems()方法提供了用于向Sharepoint List增、删、改数据的方法,但是需要通过CAML语句告诉Sharepoint如何更新数据,有关如何使用CAML以及如何编写CAML进行List数据更新,读者可以参考微软的MSDN文档。
顺便再给出调用Sharepoint站点的Web Service的地址:
http://Sitename/_vit_bin/lists.asmx?op=UpdateListItems
在使用Lists.UpdateListItems方法时,所使用的用于更新数据的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" > < Field Name ="Title" > World </ Field > < Field Name ="Document" > 5 </ Field > </ Method > </ Batch > 也就是说我们可以在同一段CAML中批量操作数据。不过最近在实际应用中遇到了一个问题,那就是当我要更新的记录太多,比如20000行,可能我需要写一段特别长的CAML,这个时候当我们在程序中调用Web Service时WSS会给出这样的错误。
Some part of your SQL statement is nested too deeply. Rewrite the query or break it up into smaller queries.
就是说你所使用的CAML语句太长而被自动截断了。细心观察一下,发现被截断的CAML的前半部分已经成功执行到List中了,而后半部分没有被执行,看来我们需要自己动手来处理这个Bug了。最好的办法就是将过长的CAML分批进行处理,一部分一部分地执行。
1 /// <summary> 2 /// Breaks a larg CAML query into smaller batches to avoid the error "Some part of your SQL statement is nested too deeply. Rewrite the query or break it up into smaller queries." 3 /// </summary> 4 /// <param name="listService"> The SharePoint list service to execute the CAML against. </param> 5 /// <param name="listName"> The name of the list to execute the CAML against. </param> 6 /// <param name="elementLargeBatch"> The CAML batch list of commands to be broken up. </param> 7 /// <param name="intBatchSize"> The size of batches to use. If unsure use 300, it seems to work fairly well. </param> 8 /// <returns> Returns the status of each method block posted through the updates parameter and can 9 /// be assigned to a System.Xml.XmlNode object. </returns> 10 public static XmlNode UpdateListItems(SqlClrSharePointSynchronizer.Lists.Lists listService, string listName, XmlElement elementLargeBatch, int intBatchSize) 11 { 12 // calculate useful information 13 int intMethodCount = elementLargeBatch.ChildNodes.Count; 14 int intBatchCount = ( int )Math.Ceiling(( double )intMethodCount / ( double )intBatchSize); 15 16 // prepare xml documents for batches and results 17 XmlDocument xmlDocBatch = new XmlDocument(); 18 XmlDocument xmlDocResults = new XmlDocument(); 19 XmlElement elementResults = xmlDocResults.CreateElement( " Results " ); 20 21 try 22 { 23 // for each batch 24 for ( int intCurrentBatch = 0 ; intCurrentBatch < intBatchCount; intCurrentBatch ++ ) 25 { 26 int intMethodStart = intCurrentBatch * intBatchSize; 27 int intMethodEnd = Math.Min(intMethodStart + intBatchSize - 1 , intMethodCount - 1 ); 28 29 XmlElement elementSmallBatch = CreateBatch(xmlDocBatch); 30 31 // for each method in the batch 32 for ( int intCurrentMethod = intMethodStart; intCurrentMethod <= intMethodEnd; intCurrentMethod ++ ) 33 { 34 XmlElement element = (XmlElement)elementLargeBatch.ChildNodes[intCurrentMethod]; 35 elementSmallBatch.AppendChild(xmlDocBatch.ImportNode(element, true )); 36 } 37 38 // execute the batch 39 XmlNode nodeBatchResult = listService.UpdateListItems(listName, elementSmallBatch); 40 41 // add the results of the batch into the results xml document 42 foreach (XmlElement elementResult in nodeBatchResult.ChildNodes) 43 { 44 elementResults.AppendChild(xmlDocResults.ImportNode(elementResult, true )); 45 } 46 47 // clean up 48 xmlDocBatch.RemoveAll(); 49 } 50 } 51 catch (SoapException ex) 52 { 53 if (ex.Detail == null ) 54 { 55 throw ; 56 } 57 58 // copy the exception detail into the Message so it will be available to SQL. 59 throw new SoapException(ex.Detail.InnerText, ex.Code, ex.Actor, ex.Detail, ex); 60 } 61 62 return (XmlNode)elementResults; 63 } 64 65 /// <summary> 66 /// Create the batch element. e.g. <Batch OnError="Continue"></Batch> 67 /// </summary> 68 /// <param name="xmlDoc"> The object of XmlDocument. </param> 69 /// <returns> Return the Batch element. </returns> 70 private static XmlElement CreateBatch(XmlDocument xmlDoc) 71 { 72 XmlElement elementBatch = xmlDoc.CreateElement( " Batch " ); 73 elementBatch.SetAttribute( " OnError " , " Continue " ); 74 return elementBatch; 75 } 我在使用的过程中发现超过600行的数据更新就会出现CAML被截断的情况,所以我干脆将intBatchSize设置为300,超过300行的CAML将会被分批执行。在Web Service中使用CAML经常会遇到这样或那样的问题,查询用的CAML问题更多,不过Microsoft在SP对象中对CAML的支持还是不错的,毕竟是经过封装的,使用起来要顺手许多。
本文转自Jaxu博客园博客,原文链接:http://www.cnblogs.com/jaxu/archive/2009/03/20/1417792.html,如需转载请自行联系原作者