Mit dem Release von SharePoint 2010 wurde auch die Komponente LINQ 2 SharePoint ausgerollt. Der LINQ Provider für SharePoint 2010 erlaubt es, streng typisierte und kompilierbare Abfragen für SharePoint Listen zu schreiben.

Vor SharePoint 2010 musste jeder SharePoint Entwickler CAML – eine XML basierte SharePoint Abfragesprache – Abfragen erstellen um damit Elemente aus Listen zu selektieren. Der LINQ Context bietet nun einen Wrapper um die Sprache CAML Abfragen an. LINQ 2 SharePoint soll gerade auf einfache Customizings zielen und unerfahrenen SharePoint Entwickler den Einstieg auf die Anwendungsplattform erleichtern.

 

LINQ

Wer zu diesem Zeitpunkt noch keine LINQ Kentnisse hat, der sollte sich eventuell 30 Minuten Zeit nehmen um kurz die Syntax und die Möglichkeiten von LINQ kennenzulernen.

Das kostenlose LINQPad (http://www.linqpad.net/) bietet einen direkten Einstieg in den LINQ Syntax. Wer gerade keinen SQL Server zur Hand hat, oder das ganze bequem auf seinem Netbook machen möchte, der kann mit wenig Aufwand eine Demodatenbank auf SQL Azure erstellen, um eine Datenquelle für die LINQ Queries zu haben. (http://windowsazure.com/)

Auf der MSDN findet sich auch eine Sammlung von 101 LINQ Beispielen in C# und VB.NET (http://msdn.microsoft.com/en-us/vstudio/aa336746), meine Empfehlung ist es an dieser Stelle einfach die ersten N Beispiele sich online anzuschauen und einfach ein wenig mit dem genialen LINQPad zu experimentieren.

 

SPMetal

SPMetal ist ein kleines CommandLineTool, welches dazu verwendet wird, den LINQ 2 SharePoint Context für eine bestimmte SharePoint Webseite zu erstellen. Das Tool kann im Bin Folder des SharePoint Roots gefunden werden. (%ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\BIN\SPMetal.exe)

SPMetal wird lediglich über ein paar Parameter konfiguriert und somit an die Umgebung angepasst.

 

Parameter

Beschreibung

web

URL der SharePoint Webseite

code

Absoluter Pfad für die Ausgabedatei. (den generierten LINQ DataContext)

language

Gibt die Programmiersprache an, in welcher der Context generiert werden soll.

namespace

Git den Namensraum an, der für den Context und die Entity-Klassen verwendet werden soll

user

Definiert den Benutzer, in dessen Kontext der Code generiert werden soll.

password

Das Passwort des optional angegebenen Benutzers

parameters

Wird verwendet um den Pfad zu einer XML Konfigurationsdatei anzugeben. Durch die Verwendung dieses Parameters können die Standardeinstellungen von SPMetal überschreiben werden

 

Ein LINQ Kontext in C# kann in der einfachsten Variante über folgenden Aufruf erstellt werden:

SPMetal.exe /web:http://sp2010dev /code:IntranetSite.cs

Um für die gleiche Seite einen LINQ Kontext in Visual Basic zu erstellen sieht der Aufruf wie folgt aus:

SPMetal.exe /web:http://sp2010dev /code:IntranetSite.vb

SPMetal ermittelt, falls nicht explizit angegeben, die gewünschte Programmiersprache über die FileExtension des Code Parameters. Wenn man die Extension des Outputfiles nicht explizit angibt, so muss der Aufruf um den Parameter Language erweitert werden

SPMetal.exe /web:http://sp2010dev /language:vb /code:IntranetSite

Integration in ein SharePoint Projekt

Ein bereits erstellter LINQ 2 SharePoint DataContext kann recht einfach in ein vorhandenes SharePoint Projekt integriert werden.

clip_image002Die generierte Datei kann einfach mittels Drag and Drop zum Projekt hinzugefügt werden. Versucht man sein Projekt an dieser Stelle zu kompilieren, so werden prompt diverse Fehlermeldungen präsentiert. Der Grund hierfür ist recht schnell gefunden, das SharePoint Projekt benötigt einen AssemblyVerweis auf Microsoft.SharePoint.Linq.dll. Wie die meisten SharePoint spezifischen DLLs findet man auch diese im ISAPI Ordern unterhalb des SharePoint Roots.

Mit der neu hinzugefügten Referenz auf die LINQ Assembly sollte sich das SharePoint Projekt jetzt wieder problemlos kompilieren lassen.

 

Stay up-to-date

Bereits an dieser Stelle kann man mit sehr wenig Aufwand nachhaltige Fehlerprävention betreiben. Die von mir zuvor beschriebene Erstellung des LINQ 2 SharePoint Contextes sollte man als PreBuild Ereignis eintragen.
Dadurch kann sehr einfach sichergestellt werden, dass der LINQ 2 SharePoint Kontext stets aktuell ist und sofern sich an der Umgebung etwas ändert, man als Entwickler unmittelbares Feedback erhält.

Die in den Build-Ereignissen existierenden MSBuild Parameter erlauben es darüber hinaus auch, die Dateien noch vor dem Kompilierungsprozess im Projektordner zu überschreiben.

clip_image003

Somit sind alle Voraussetzungen für den Einsatz von LINQ 2 SharePoint gegeben, jetzt kann mit der Entwicklung begonnen werden.

 

Getting started

In Abbildung 3 sieht man eine einfache LINQ 2 SharePoint Abfrage. Es werden hier sämtliche Kunden, die aus Deutschland stammen ermittelt und deren Name wird auf der Console ausgegeben.

clip_image005

Eigentlich nichts spektakuläres, dennoch lassen sich unter genauerer Betrachtung einige Fehler, Probleme und Unschönheiten finden, die man als SharePoint Entwickler im täglichen Leben auslassen bzw. umgehen sollte.

 

Daily LINQ 2 SharePoint

Das erste Problem, welches unser einfaches LINQ 2 SharePoint Beispielscript beinhaltet ist, dass der Context nicht freigegeben wird. Man kann den LINQ 2 SharePoint DataContext mit einer Datenquellenverbindung gleichsetzen, auch hier werden unmanaged Resourcen verwendet, die es wieder freizugegeben gilt.

Analog zum Disposing von SPWeb und SPSite, bietet sich auch hier das using-Schlüsselwort an.

 

clip_image007

 

Gut, jetzt sollte zumindest das offensichtliche Speicherproblem behoben sein, doch analysieren wir das kleine Codefragment weiter.

Die Select() Methode von IEnumerable<T> wird dazu verwendet den Rückgabetyp des gesamten LINQ Ausdrucks zu definieren. Weil diese Abfrage gegen eine Kontaktliste in SharePoint ausgeführt wird, ist unser Rückgabetyp hier Contact. – Das generierte Gegenstück zum Inhaltstyp unserer SharePoint Seite.

An dieser Stelle ist es wichtig, dass man sich wieder darauf besinnt, dass der LINQ Provider für SharePoint lediglich ein Wrapper um CAML darstellt.

Wenn man in Umgebungen arbeitet wo man auf Datentransfermengen und/oder Performance achten muss, dann sollte man unbedingt die Abfrage anpassen, so dass lediglich die benötigten Werte von der Datenquelle abgefragt und zurückgegeben werden.

 

clip_image009

 

Aktivert man auf dem LINQ 2 SharePoint Context das Logging, so sieht man bei der Ausführung unmittelbar, dass sich die CAML Query geändert hat. Durch das hinzufügen des Anonymen Typs in der Select() Methode, wurden in der CAML Query ViewFields integriert. Durch das Verwenden von ViewFields in CAML wir dem SharePoint signalisisert, dass lediglich die angegebenen Felder an den Aufrufer übertragen werden sollen. Ohne ViewFields werden alle Spalten eines Elementes zurückgegeben.

Das dritte Problem des Snippets ist eher ein strukturelles Problem. In diesem Snippet wird eine Abfrage direkt auf dem LINQ 2 SharePoint Context abgesetzt.
Diese direkte Interaktion mit dem LINQ 2 SharePoint Context sollte durch ein Repository Pattern (http://msdn.microsoft.com/en-us/library/ff649690.aspx) gekapselt sein, so dass nicht an beliebigen Stellen im Anwendungscode der Context verwendet wird.

Vielmehr sollte es einen Service gegeben, welcher von den jeweiligen Komponenten verwendet wird um die benötigten Objekte aus der SharePoint Liste zu erhalten.

clip_image010

 

Die neuste Version des Snippets verwendet den CustomerService. Der CustomerService übernimmt die Domainlogik und fragt die Elemente beim CustomerRepository nacht. Erst das CustomerRepository hat dann einen direkten Zugriff auf den LINQ 2 SharePoint Context.

In diesem Stadium kann das LINQ Query ohne weitere Bedenken eingesetzt werden. Doch LINQ 2 SharePoint hat noch ein paar weitere Interessante Aspekte.

 

Semi-Efficient-Queries

Die Feautres von LINQ wirken auf den ersten Blick schier unbegrenzt. Alles scheint möglich zu sein, sämtliche Aspekte, die man im Kontext der Datenabfrage oder Datenaggregation erwartet, bietet LINQ nun auch dem SharePoint Entwickler direkt auf der Basis von SharePoint Listen an.

Nun, so ganz stimmt dies nicht. LINQ 2 SharePoint fungiert als Wrapper um CAML und kann somit auf effiziente Weise nur die Abfragen und Aggregationen ausführen, welche auch nativ in CAML möglich sind.

Damit aber auch der SharePoint Entwickler Werte einer Gruppierung summieren, oder eine bestimmte Anzahl von Elementen aus der Ergebnismenge überspringen kann, gibt es in LINQ 2 SharePoint ein Konzept welches sich Semi-Efficient-Queries nennt.

Einfach erklärt bedeutet dies, das Abfragen in zwei Schritten ausgeführt werden, sobald sie eine von CAML nicht unterstützte Funktion beinhalten.

Eine genaue List der Methoden, die nicht nativ von CAML unterstützt werden findet ihr auf der MSDN (http://msdn.microsoft.com/en-us/library/ee536585.aspx).

 

Der RunWithElevatedPrivileges Bug

Wer kennt sie nicht, die RunWithElevatedPrivileges() Methode der Klasse SPSecurity? Dank dieser Methode ist es uns möglich direkt in einen anderen Benutzerkontext zu impersonieren.
Gerne wird hier der SharePoint Farm Kontext genommen, da dieser natürlich über weitgehende Rechte verfügt. Doch wenn man mit LINQ 2 SharePoint arbeitet, existiert hier noch ein Problem in der SharePoint API.

So führt dieses Script

 

clip_image012

nicht dazu, dass der linqContext im Kontext der Farm läuft.

Sofern dieser Code aus SharePoint selbst aufgerufen wird, ist linqContext immernoch im Kontext des ursprünglichen Benutzers und kann somit vielleicht nicht auf die gewünschten SharePoint Elemente zugreifen.

Die Ursache liegt wie bereits gesagt in der SharePoint API selbst, genauer gesagt in der Klasse SPServerDataConnection aus dem Namespace Microsoft.SharePoint.Linq.Provider.

clip_image014

Der Screenshot zeigt die Klasse im .NET Reflector. Hier ist zu sehen dass, falls der SPContext gefüllt ist, einfach dessen Werte (Current.Site, Current.Web) verwendet werden, unabhängig davon ob eventuell eine Impersonierung vorliegt.

Der zweite Fehler findet sich im If Statement welches der Variable defaultWeb zugewiesen wird.

Angenommen es wird impersoniert auf ein SPWeb, welches sich auf einer anderen SiteCollection befindet, so erhalten wir hier sogar eine FileNotFoundException zur Laufzeit, weil die API immer die SiteCollection aus dem SPContext als Grundlage nimmt.

 

Glücklicherweise lässt sich der Bug mit etwas Mehraufwand umfahren. Damit wir korrekt impersonieren können im Zusammenhang mit LINQ, muss der SPContext neu gesetzt werden. Da die Current Property von SPContext ReadOnly ist, muss zuerst der gesamte HttpContext gesichert! und überschrieben werden. Mit dem neuen HttpContext kann dank SPControl auch der SPContext neu initialisiert werden. Ganz wichtig ist es, nach der eigenen Logik den ursprünglichen Context wieder herzustellen (hier der finally Block)

 

clip_image016

 

 

Mein Fazit

Durch LINQ 2 SharePoint wird .NET Entwickler natürlich der Einstieg auf die SharePoint Plattform etwas einfacher gemacht und für den erfahrenen SharePoint Entwickler sind es sicherlich die qualitätssteigernden Aspekte wie StronglyTyped- und Compiled- Queries.

Dennoch ist es wichtig um die hier beschriebenen Probleme und Stolperfallen zu wissen, weil sonst der Zeitgewinn schnell aufgesogen wird.

Beachtet man jedoch diese einfachen Regeln, so kann LINQ 2 SharePoint euren Code sicherer, lesbarer und sicherlich auch einfacher machen, als es die großen CAML-String-Blöcke noch in SharePoint 2007 gemacht haben :)

 

Thorsten

1 Kommentar to “LINQ 2 SharePoint”

Erstelle Kommentare

You must be logged in to post a comment.

Hinweis zum Kommentar

Zum Kommentieren der Beiträge (und damit zur Teilnahme am Gewinnspiel) bitte auf die Zahl in der Bubble neben dem Titel des Blogeintrags klicken, dies öffnet das Kommentarformular!

Sponsored by

Subscribe

Über

Der SharePoint Advent

Ein Gemeinschaftsprojekt der deutschsprachigen SharePoint MVP's

Rubriken

Impressum

(c) 2011 SharePointCommunity