CAML-Abfragen in SharePoint

In diesem Beitrag soll gezeigt werden, wie CAML-Abfragen in SharePoint gemacht werden können. Er gilt gleichermaßen für SharePoint 2007 und SharePoint 2010. Die offizielle Referenz zum verwendeten XML-Schema findet sich hier auf MSDN (für SharePoint 2010).

Die Motivation zu diesem Beitrag entstand dadurch, daß ich selbst etwas zum Nachschlagen brauchte. Die Methoden zum Abfragen unterschiedlicher Feldtypen und die verwendbaren Token und Vergleichsoperatoren habe ich auch nicht immer auswendig parat. Ich werde die Sammlung im Laufe der Zeit ergänzen, wenn mir selbst etwas Neues unterkommt oder wenn ich auf Fehlendes hingewiesen werde.

Als Entwickler kommt man mit CAML wahrscheinlich am Häufigsten beim Abfragen von Listenelementen per Code in Kontakt. Man gibt für die Abfrage ein oder mehrere Kriterien an, nach denen die Ergebnismenge gefiltert wird, und optional ein oder mehrere Felder, nach denen die Ergebnisse sortiert werden sollen.

Eine einfache Abfrage kann z.B. so aussehen:

SPQuery query = new SPQuery();
query.Query = @“<Where>
                  <Eq>
                    <FieldRef Name=’Title’/>
                    <Value Type=’Text‘>Hallo</Value>
                  </Eq>
                </Where>
                <OrderBy>
                  <FieldRef Name=’ID’/>
                </OrderBy>“;
SPListItemCollection items = myList.GetItems(query);

Diese Abfrage liefert alle Listenelemente, deren Titel Hallo entspricht, aufsteigend sortiert nach ID. Beim Zusammenstellen der Query kann man auch auf System.Xml.Linq zurückgreifen. Dieselbe Abfrage sieht dann so aus:

query.Query = new XElement(„Where“,
                new XElement(„Eq“,
                  new XElement(„FieldRef“, new XAttribute(„Name“, „Title“)),
                  new XElement(„Value“, new XAttribute(„Type“, „Text“), „Hallo“)
                )
              ).ToString(SaveOptions.DisableFormatting) +
              new XElement(„OrderBy“,
                new XElement(„FieldRef“, new XAttribute(„Name“, „ID“))
              ).ToString(SaveOptions.DisableFormatting);

FieldRef

Beim Name-Attribut der FieldRef-Elemente muß immer der interne Name der Felder angegeben werden. Der sichtbare Name kann nicht verwendet werden. Anstelle von Name kann auch ein ID-Attribut angegeben werden, das dann die GUID des Feldes enthalten muß. Eine Liste mit den internen Namen und IDs der Standardfelder findet man z.B. hier.

Sortierung

Wenn nichts anderes angegeben wird, wird immer in aufsteigender Reihenfolge sortiert. Wenn in absteigender Reihenfolge sortiert werden soll, wird ein zusätzliches Ascending-Attribut mit dem Wert FALSE angegeben:

<FieldRef Name=’ID‘ Ascending=’FALSE’/>

Natürlich kann auch nach mehreren Feldern sortiert werden, indem man mehrere FieldRef-Elemente angibt. Sie werden in der angegebenen Reihenfolge und in der jeweils angegebenen Sortierrichtung berücksichtigt.

Mehrere Werte abfragen

Wenn man mehrere Werte abfragen möchte, muß man die Einzelabfragen mit And– oder Or-Elementen klammern:

<Where>
  <Or>
    <Eq>
      <FieldRef Name=‘Title‘/>
      <Value Type=‘Text‘>Hallo</Value>
    </Eq>
    <Eq>
      <FieldRef Name=‘Title‘/>
      <Value Type=‘Text‘>Welt</Value>
    </Eq>
  </Or>
</Where>

Diese Abfrage liefert alle Elemente, deren Titel entweder Hallo oder Welt entspricht.

Es können immer nur zwei Einzelabfragen geklammert werden. Wenn man mehr Abfragen braucht, muß man eine neue Klammer verwenden:

<Where>
  <And>
    <Or>
      <Eq>
        <FieldRef Name=‘Title‘/>
        <Value Type=‘Text‘>Hallo</Value>
      </Eq>
      <Eq>
        <FieldRef Name=‘Title‘/>
        <Value Type=‘Text‘>Welt</Value>
      </Eq>
    </Or>
    <Gt>
      <FieldRef Name=‘ID‘/>
      <Value Type=‘Number‘>15</Value>
    </Gt>
  </And>
</Where>

Diese Abfrage liefert alle Elemente, deren Titel entweder Hallo oder Welt entspricht und deren ID größer als 15 ist.

Vergleichsoperatoren

Folgende Vergleichsoperatoren können verwendet werden:

Eq ist gleich (equals)
Neq ist nicht gleich (not equals)
Gt größer als (greater than)
Geq größer als oder gleich (greater or equals)
Lt kleiner als (less than)
Leq kleiner als oder gleich (less or equals)
IsNull ist null, d.h. leer
IsNotNull ist nicht null, d.h. nicht leer
BeginsWith beginnt mit (Zeichenfolge)
Contains enthält (Zeichenfolge)
Nachschlagefelder

Bei Nachschlagefeldern muß man aufpassen. Wenn nichts weiter beachtet wird, muß als Value der Texteintrag des Nachschlagefeldes angegeben werden. Wenn man stattdessen die nachgeschlagene ID abfragen möchte, muß es so aussehen:

<FieldRef Name=“Lookup“ LookupId=“True“/>
<Value Type=“Lookup“>15</Value>

Personenfelder

Personenfelder sind intern wie Nachschlagefelder aufgebaut (weil damit in der Benutzerliste nachgeschlagen wird) und verhalten sich deshalb ähnlich. Wenn man nichts weiter beachtet, muß man als Value den Anmeldenamen verwenden. Wenn man nach der ID eines bestimmten Benutzers filtern möchte, muß man bei Value Type=“Integer“ angeben.

Filtern nach dem aktuellen Benutzer, d.h. nach dem Benutzer, der die Abfrage ausführt, kann man so:

<Value Type=“Integer“><UserID/></Value>

Gruppenmitgliedschaft auflösen

Bei Elementen mit einem Personenfeld gibt es eine Möglichkeit alle Elemente zu erhalten, bei denen in diesem Feld Personen aus Gruppen stehen, bei denen auch der aktuelle Benutzer Mitglied ist. Das funktioniert so z.B. bei der vordefinierten Ansicht Nach meinen Gruppen bei Aufgabenlisten. Die Abfrage dazu sieht so aus:

<Where>
  <Membership Type=“CurrentUserGroups“>
<FieldRef Name=“AssignedTo“/>
</Membership>
</Where>

Ja/Nein Felder

Bei Ja/Nein-Feldern muß als Value 0 oder 1 angegeben werden. True oder false funktionieren nicht!

<Value Type=“Boolean“>0</Value>

Datumsfelder

Auch Datumsfelder müssen besonders beachtet werden. Ohne weiteres Zutun wird bei Datumsvergleichen nur der Tagesanteil beachtet und der Zeitanteil wird ignoriert. Wenn der Zeitanteil ebenfalls beachtet werden soll, muß dem Value-Element ein IncludeTimeValue-Attribut mit dem Wert True hinzugefügt werden. Das Datum selbst muß in folgendem Format angegeben werden:

<Value Type=“DateTime“ IncludeTimeValue=“True“>yyyy-MM-ddThh:mm:ssZ</Value>

Wie man wiederkehrende Ereignisse einer Kalenderliste abfragen kann, habe ich in einem separaten Beitrag hier beschrieben.

Token

Als Value können folgende Token verwendet werden:

<Today/> liefert das aktuelle Datum ohne Zeitanteil. Es kann ein Attribut Offset oder OffsetDays angegeben werden, das einen Offset in ganzen Tagen angibt (kann auch negativ sein):

<Today OffsetDays=“2″/>

<Now/> liefert das aktuelle Datum inklusive Zeitanteil.

<UserID/> liefert die ID des aktuellen Benutzers.

List-Joins und ProjectedFields

Wie man mehrere Listen in Abfragen verbinden kann, habe ich in einem separaten Beitrag gezeigt.

Was es sonst noch zu beachten gibt

Abfragen mit SPQuery liefern standardmäßig immer alle Felder der Listenelemente, auch alle versteckten. Wenn man die nicht alle braucht, kann man die gewünschten Felder angeben, was sich besonders bei Listen mit sehr vielen Feldern empfiehlt. Dazu belegt man die Eigenschaft ViewFields des SPQuery-Objekts mit ein oder mehreren FieldRef-Elementen. Die Abfrage liefert dann nur noch die angegebenen Felder.

Standardmäßig liefert SPQuery nur Elemente, die sich im Root-Ordner einer Liste befinden. Wenn man auch Elemente aus Unterordnern haben möchte, belegt man die Eigenschaft ViewAttributes mit Scope=“Recursive“. Wenn man auch die Ordner selbst haben möchte, kann man Scope=“RecursiveAll“ angeben.

4 Gedanken zu “CAML-Abfragen in SharePoint

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s