Kilka dni temu zupełnie przypadkiem przypomniałem sobie o dość ciekawej funkcjonalności zawartej w MOSS/WSS. Mianowicie wykonywania wielu operacji za pomocą pliku XML – Visual Ho Tos: Batch Updating List Items in Windows SharePoint Services 3.0.

Klasa SPWeb udostępnia metodę ProcessBatchData, która jako parametr przyjmuje element XML Batch, który odpowiedzialny jest za zgrupowanie metod, które powinny być wywołane na serwerze. Tag Batch, musi zawierać minimum jeden element Method, odpowiedzialny za określenie czynności jaka będzie wykonywana – New, Update, Delete. Tag Method może zaś zawierać element Field (uwaga w dokumentacji na MSDN, jest błąd i link przy opisie Method prowadzi do złego Field, link podany w tym postcie jest poprawny), SetList oraz SetVar.

Tag Field

odpowiedzialny jest za zwrócenie pola odpowiednio z formatowanego tak by można go było zawrzeć w definicji View. Osobiście z tego nigdy nie korzystałem, choć wiem, że dokumentacja mówi jedno a można zrobić coś zupełnie innego, na przykład poniższy kod, doda element do listy (nie ma ustawionego Batch):

<!-- ID musi byc unikatowe w danym batch -->
<Method ID="1" Cmd="New">
  <!-- ID elementu jest New jako ze to nowy element -->
  <Field Name="ID">New</Field>
  <Field Name="Title">My Title</Field>
  <!--
    Podanie type jest wymagane przy lookup,
    jak i podanie indexu elementu zamiast
    wartosci.
  -->
  <Field Name="Status" Type="Lookup">0</Field>
</Method>

To na co warto zwrócić uwagę w powyższym przykładzie to, to że atrybut Name określa internal field name a nie display name! Jest to bardzo ważne, w przeciwnym wypadku XML wam nie zadziała.

Dodatkowo, wykorzystując tag Field oraz metodę UpdateListItems na Lists Web Service można wykonywać te same operacje co zostały udostępnione w przykładach, np.: usunięcie elementu:

<Batch>
  <Method ID='1' Cmd='Delete'>
    <Field Name='ID'>1</Field>
    <Field Name='FileRef'>[URL Path - internal Name FileRef]</Field>
  </Method>
</Batch>

Tag SetList

jest odpowiedzialny za zdefiniowanie listy na której dana metoda będzie wykonywana. Jako wartość Tagu podaje się GUID listy:

<SetList>List_GUID</SetList>

<SetList Scope="Request">List_GUID</SetList>

Oczywiście, dokumentacja podaje, że atrybut Name jest wymagany, a nie jest :(

Tag SetVar

służy do określenia wartości danego atrybutu określonego przez atrybut Name. Wiem, dziwnie to brzmi, ale na przykładzie będzie to łatwiej wytłumaczyć:

<Method ID="A2">
  <!-- Okreslamy ID Listy -->
  <SetList>List_GUID</SetList>
  <!-- Okreslamy ze atrybut ID bedzie mial wartosc New -->
  <SetVar Name="ID">New</SetVar>
  <!-- Okreslamy ze wykonujemy operacje zapisu elementu na liscie -->
  <SetVar Name="Cmd">Save</SetVar>
  <!-- Okreslamy jakie pola beda aktualizowane -->
  <SetVar Name="urn:schemas-microsoft-com:office:office#Title">
    Sales rise by 10%
  </SetVar>
  <SetVar Name="urn:schemas-microsoft-com:office:office#Body">
    The accounting department has released its quarterly report.
    Check it out!
  </SetVar>
  <SetVar Name="urn:schemas-microsoft-com:office:office#Expires">
    2001-12-18T00:00:00Z
  </SetVar>
</Method>

Jak widać, powyższy kod stworzy nowy element na liście. Atrybut Name określa co ma mieć jaką wartość. Różnica pomiędzy Tagiem Field jest taka iż w tym wypadku jeżeli chcemy zaktualizować pole musimy podać urn do schematu, w przeciwnym wypadku nasz XML nie zadziała :( Po znaku specjalnym # podajemy oczywiście internal field name a nie display name. No i jak zauważyliście datę podajemy w standardzie ISO (pisałem o tym w Tips & Tricks 06: CAML Pobranie elementów po dacie z godziną).

Za pomocą odpowiednio z preparowanego XML, możemy w ten sam sposób rozmawiać z WebServices od WSS/MOSS. Dlatego poznanie konstrukcji dokumentów dodających elementy czy je kasujące jest dość przydatne.

Przykłady

Dodanie elementu do listy:

<Batch>
  <Method>
    <SetList Scope="Request">{0}</SetList>
    <SetVar Name="ID">New</SetVar>
    <SetVar Name="Cmd">Save</SetVar>
    <SetVar Name="urn:schemas-microsoft-com:office:office#Title">Praca zdalna</SetVar>
    <SetVar Name="urn:schemas-microsoft-com:office:office#Description">Jakis Opis</SetVar>
  </Method>
</Batch>

Usunięcie elementu z listy (o ID 1):

<Batch>
  <Method>
    <SetList Scope="Request">{0}</SetList>
    <SetVar Name="Cmd">DELETE</SetVar>
    <SetVar Name="ID">1</SetVar>
  </Method>
</Batch>

Dodanie WebPartPage do document library:

<Batch>
  <Method>
    <SetList Scope="Request">{0}</SetList>
    <SetVar Name="ID">New</SetVar>
    <SetVar Name="Cmd">NewWebPage</SetVar>
    <SetVar Name="Type">WebPartPage</SetVar>
    <SetVar Name="WebPartPageTemplate">1</SetVar>
    <SetVar Name="Title">TITLE</SetVar>
    <SetVar Name="Overwrite">true</SetVar>
  </Method>
</Batch>

Usunięcie pliku (o ID 1) z document library:

<Batch>
  <Method>
    <SetList Scope="Request">{0}</SetList>
    <SetVar Name="Cmd">DELETE</SetVar>
    <SetVar Name="ID">1</SetVar>
    <SetVar Name="owsfileref">[URL Path – internal name FileRef]</SetVar>
  </Method>
</Batch>

Więcej przykładów:

Windows SharePoint Services RPC Methods – strona zawiera przykłady pokazujące w jaki sposób dodać View, usunąć View, usunąć listę itp. itd.

Podsumowanie

Warto jest pamiętać, że WSS/MOSS udostępnia taką funkcjonalność. Nie jest ona przydatna zawsze, jednak zdarzają się sytuacje iż nie wiedza o niej może nałożyć kilka niepotrzebnych dni pracy.

Ja osobiście użyłem tego tylko raz w życiu, ale dzięki ProcessBatchData, całość napisałem w 30 minut wraz z umożliwieniem użytkownikom aktualizacji elementów – jeżeli chcieli mieć inne domyślne dane, modyfikowali Excel, klikali export i następnie uruchamiali feature.

Oczywiście zastosowanie tego zależy już tylko i wyłącznie od was :)

7 KOMENTARZE

  1. Szkoda tylko że elementy batch’a nie są wykonywane transakcyjnie :( Chyba że o czymś nie wiem..

  2. @woro

    nie, niestety SharePoint nie wspiera tranzakcyjnosci, ale dzieki wiedzy jak zrobic operacje w batch, mozna “latwo” zaimplementowac wlasny system tranzakcyjnosci – na przyklad podzielic wgrywania elementow na paczki, nastepnie sprawdzac na ktorej paczce sie wywalilo i w kodzie cofac o tyle paczek wykonanie kodu.

    Gutek

  3. Tak, tak wiem.. tyle że transakcyjnego ACID w proponowanym rozwiązaniu i tak nie będzie ..
    a grzebanie po bazie MOSS wydaje się być również kiepskim pomysłem. :)

  4. A masz jakiś sposób na to, żebe usuwane za pomocą CMD Delete elementy listy kasowały się całkowicie zamiast lądować w koszu? Wykonanie web.RecycleBin.DeleteAll() odpada bo w koszu moga być też inne elementy.

  5. @pepek

    mozesz sprawdzic takie rozwiazanie:
    // Przed operacja
    web.Site.WebApplication.RecycleBinEnabled = false;

    // Po operacji
    web.Site.WebApplication.RecycleBinEnabled = true;

    nie wiem czy zadziala – nie wiem czy jak sie wezmie = false to Ci nie sksuje juz wszystkiego co masz w koszu, ale watpie.

    Innym rozwiazaniem jest przeliterowanie elementow w koszu po item Id i listID i usuniecie tych ktore usunales za pomoca CMD Delete.

    Daj znacz czy cos z tego Ci zadzialalo – sam jestem ciekaw :)

  6. web.Site.WebApplication.RecycleBinEnabled = false;
    powoduje usunięcie zawartości kosza.
    A iterować mi się nie udało, bo wywala mi się błąd System.ArgumentException -“Wartość jest spoza oczekiwanego zakresu.” na RecycleBin.Delete(kolekcja) gdzie kolekcja to lista guidów usuwanych list.Item

Comments are closed.