Opération de masse sur une liste : SPWeb.ProcessBatchData

Dans le cadre d’un projet, j’ai besoin de mettre à jour une liste de référence de manière quotidienne à partir d’une source extérieure (non accessible par BCS). Nous parlons de quelques milliers éléments et ma source de données renvoie tout, sans possibilité de faire de l’incrémentiel.

Premier réflexe, utiliser le classique modèle objet :

//delete old data
int _nbItems = _cmdbList.Items.Count;
for (int idx = 0; idx < _nbItems; idx++)
{
   _cmdbList.Items.Delete(0);
}

// insert new data
foreach (var item in newData)
{
   SPListItem _newCmdbItem = _cmdbList.AddItem();
   _newCmdbItem[Constants.Fields.PROPERTY1] = item.Property1;
   _newCmdbItem.Update();
}

J’exécute le timerjob et regarde ce qu’il se passe sur le site. Ca fonctionne mais j’ai l’impression que c’est un peu lent, ce que me confirme le journal des timerjobs.

Après une recherche sur Internet, j’ai redécouvert SPWeb.ProcessBatchData. Il s’agit d’une méthode qui permet d’exécuter plusieurs requêtes en une seule transaction. Les requêtes sont écrites en CAML ce qui peut effrayer.

String tplBatch = "<xml version="1.0" encoding="UTF-8"?><Batch>{0}</Batch>";
// 0 : List ID
// 1 : list item ID
String tplDeleteItemById = "<Method><SetList Scope="Request">{0}</SetList><SetVar Name="ID">{1}</SetVar><SetVar Name="Cmd">Delete</SetVar></Method>";

StringBuilder _batchString = new StringBuilder();
_batchString.Append("<?xml version="1.0" encoding="UTF-8"?><Batch>");
//add each item to the batch string and give it a command Delete
foreach (SPListItem _item in _cmdbList.Items)
{
   _batchString.AppendFormat(tplDeleteItemById, Convert.ToString(_item.ParentList.ID), Convert.ToString(_item.ID));
}

String _batch = string.Format(tplBatch, _batchString.ToString());
_rootweb.ProcessBatchData(_batch);

StringBuilder _batchStringNew = new StringBuilder();

// 0 : List ID
// 1 : item title
// 2 : ItemProperty1
String tplAddItem = "<Method><SetList>{0}</SetList><SetVar Name="ID">New</SetVar><SetVar Name="Cmd">Save</SetVar><SetVar Name="urn:schemas-microsoft-com:office:office#Title">{1}</SetVar><SetVar Name="urn:schemas-microsoft-com:office:office#numProperty1">{2}</SetVar></Method>";
foreach (var _item in _model.data)
{
   _batchStringNew.AppendFormat(tplAddItem, _cmdbList.ID, _item.nom, _item.Property1);
}

String _batchNew = string.Format(tplBatch, _batchStringNew.ToString());
_rootweb.ProcessBatchData(_batchNew.ToString());

Déploiement de la nouvelle solution et éxecution du timerjob. Le temps d’exécution est bien plus raisonnable. La performance est remarquable vu qu’on diminue le temps par 5.

Références :

Le site areaprog propose les requêtes classiques (CRUD)

Batch Updating List Items in Windows SharePoint Services 3.0