Freigeben über


Gewusst wie: Ausführen von Abfragen mithilfe von LINQ to SharePoint

Letzte Änderung: Freitag, 8. Oktober 2010

Gilt für: SharePoint Foundation 2010

Inhalt dieses Artikels
Schritt 1: Rufen Sie einen Verweis auf eine Website ab
Schritt 2: Rufen Sie einen Verweis auf eine Liste ab
Schritt 3 (optional): Deaktivieren Sie die Objektänderungsverfolgung
Schritt 4: Definieren Sie die LINQ-Abfrage
Schritt 5: Listen Sie die Abfrageergebnisse auf
Schritt 6 (optional): Führen Sie Ergebnisse aus mehreren Listen und mehreren Datenquellen zusammen
Schritt 7 (optional): Verbinden Sie Ergebnisse aus mehreren Datenquellen miteinander

In diesem Thema wird erklärt, wie Sie mithilfe des LINQ to SharePoint-Anbieters Microsoft SharePoint Foundation-Listen abfragen können.

Schritt 1: Rufen Sie einen Verweis auf eine Website ab

Die gesamte Codierung für den LINQ to SharePoint-Anbieter muss mit dem Erstellen eines DataContext-Objekts beginnen. Dieses Objekt stellt eine Teilmenge einer Inhaltsdatenbank dar, genau gesagt die Listen und Listenelemente einer SharePoint Foundation-Website. Die einfachste Möglichkeit, ein solches Objekt zu erstellen, besteht darin, die absolute URL der abzufragenden Website als Literalzeichenfolge an den Klassenkonstruktor zu übergeben, wie hier gezeigt.

DataContext teamSite = new DataContext("http://MarketingServer/SalesTeam");

Wahrscheinlich jedoch wird die Lösung für zahlreiche Websites in vielen Farmen ausgeführt werden, und Sie kennen beim Schreiben des Codes die vollständige URL nicht. Wenn Ihr Code in einer Situation ausgeführt wird, in der ein HTTP-Kontext vorhanden ist, wie z. B. in einem Webpart oder in einer benutzerdefinierten Anwendungsseite, und Sie eine Abfrage der aktuellen Website ausführen, können Sie zum Abrufen der URL das SPContext-Objekt verwenden, wie im folgenden Beispiel gezeigt.

DataContext teamSite = new DataContext(SPContext.Current.Web.Url);

Sie können den Kontext auch verwenden, um die URLs von anderen Websites innerhalb der Websitesammlung oder sogar der anderen Websitesammlungen der Webanwendung indirekt abzurufen. Mit dem folgenden Code wird beispielsweise ein DataContext für die Website auf oberster Ebene der ältesten Websitesammlung in der Webanwendung erstellt.

String rootOfOldestURL = this.Site.WebApplication.Sites[0].RootWeb.Url;      
using (DataContext topSiteOfOldestSiteCollection = new DataContext(rootOfOldestURL))
{
}

Beachten Sie, dass Sie das DataContext-Objekt entfernen müssen, da es ein anderes SPWeb-Objekt verwendet als das vom SPContext bereitgestellte Objekt.

HinweisHinweis

Verweise auf ein SPWebApplication-Objekt erfordern eine using-Anweisung (in Visual Basic Imports) für den Microsoft.SharePoint.Administration-Namespace.

Informationen zu weiteren Möglichkeiten zum Abrufen von Verweisen auf Websites innerhalb einer SharePoint Foundation-Farm finden Sie unter Abrufen von Verweisen auf Websites, Webanwendungen und andere Schlüsselobjekte.

Ist kein HTTP-Kontext vorhanden, wie etwa in einer Konsolenanwendung, und ist Ihnen der Name des Servers bei der Codierung nicht bekannt, können Sie den "localhost"-Alias verwenden, um einen Verweis auf die Stammwebsite abzurufen, wie in den folgenden Beispielen gezeigt.

using (DataContext topLevelSite = new DataContext("https://localhost"))
{
}

using (DataContext mySite = new DataContext("https://localhost/sites/MySite"))
{
}

Da kein HTTP-Kontext vorhanden ist, sollten Sie das DataContext-Objekt entfernen.

Sie können eine Klasse von DataContext ableiten. In diesem Fall verwenden Sie den Konstruktor der Klasse, wie im folgenden Beispiel gezeigt.

ContosoTeamData teamSite = new ContosoTeamData(SPContext.Current.Web.Url);

Schritt 2: Rufen Sie einen Verweis auf eine Liste ab

Rufen Sie mithilfe der GetList<T>(String)-Methode ein EntityList<TEntity>-Objekt ab. Dieses Objekt ist eine IQueryable<T>-Darstellung einer Liste. Im Folgenden ein Beispiel.

EntityList<Announcement> announcements = teamSite.GetList<Announcement>("Announcements")

Beachten Sie, dass der Inhaltstyp der Liste durch eine explizit deklarierte Klasse dargestellt werden muss, in diesem Fall "Announcement". Die Klasse muss mit einem ContentTypeAttribute dekoriert sein, das den Namen des Inhaltstyps in der SharePoint Foundation-Website und die ID des Inhaltstyps angibt. Grundsätzlich sollten Sie beim Schreiben des Codes wissen, in welchen Listen der Code Abfragen durchführt. Die Klasse, die den Inhaltstyp darstellt, muss zumindest eine Eigenschaft beinhalten, die eine Spalte in der Liste darstellt, und diese Eigenschaftsdeklaration muss mit einem ColumnAttribute dekoriert sein, das mindestens den Namen und den Typ des Felds angibt. Im folgenden Beispiel werden die Deklarationen gezeigt, die mindestens benötigt werden, damit der aufrufende Code die GetList<T>(String)-Methode (wobei T Announcement ist) aufrufen kann.

[ContentType(Name="Announcement", Id="0x0104")]
public partial class Announcement
{
    [Column(Name = "Title", FieldType = "Text")] 
    public String Title { get; set; }
}

Eine Abfrage kann jedoch nur auf Spalten verweisen, die durch Eigenschaften in der Inhaltstypklasse dargestellt werden. Wenn also nur diese Mindestdeklaration bereitgestellt wird, kann der aufrufende Code nur auf das Title-Feld (Spalte) verweisen, wie im folgenden Beispiel gezeigt.

var excitingAnnouncements = from announcement in announcements
                            where announcement.Title.EndsWith("!")
                            select announcement;
HinweisHinweis

Dieses Beispiel zeigt Folgendes: Die Tatsache, dass die Klasse Announcement heißt, bedeutet nicht, dass sie exakt den SharePoint Foundation-Inhaltstyp mit dem gleichen Namen widerspiegeln muss. Das heißt, Sie brauchen nicht für jede Spalte des Inhaltstyps eine Eigenschaft. Die Klasse kann eine Teilmenge der Spalten des Inhaltstyps darstellen, und sie kann zusätzliche Member enthalten. Dies ist ein entscheidendes Merkmal des LINQ to SharePoint-Anbieters, da Spalten von Websitebesitzern zu Listen hinzugefügt werden können, und dadurch wird im Endeffekt ein neuer Inhaltstyp für die Liste erstellt. Die Klasse muss außerdem nicht den gleichen Namen haben wie der Inhaltstyp der Liste. Sie kann einen beliebigen Namen haben, vorausgesetzt, dieser Name wird auch als Typparameter im Aufruf der GetList<T>(String)-Methode verwendet. Der Code ist in der Regel aber besser lesbar, wenn die Klasse den gleichen Namen hat wie der offizielle Inhaltstyp der Liste. Im SPMetal-Tool wird diese Praxis standardmäßig eingehalten.

Inhaltstypen können von anderen Inhaltstypen erben, und für den Aufruf der GetList<T>(String)-Methode können Sie als Typparameter jeden beliebigen Inhaltstyp verwenden, der in der Vererbungsstruktur weiter oben steht. Beispielsweise können Sie, da alle Inhaltstypen vom grundlegenden Item-Inhaltstyp abgeleitet sind, Item als Typparameter verwenden, wie im folgenden Beispiel gezeigt:

EntityList<Item> announcements = teamSite.GetList<Item>("Announcements")

Der Quellcode muss eine Deklaration einer Item-Klasse bereitstellen, und diese Klasse muss Eigenschaften für jede der Spalten im Inhaltstyp deklarieren, die von den Abfragen referenziert werden.

Wenn Sie den Item-Inhaltstyp verwenden, können Sie Abfragen in Listen durchführen, ohne dass Sie beim Codieren den Namen der Liste oder ihren abgeleiteten Inhaltstypen kennen, wie im folgenden Beispiel gezeigt.

DataContext topLevelSite = new DataContext("https://localhost");
SPSite siteCollection = new SPSite("https://localhost");
EntityList<Item> someList = topLevelSite.GetList<Item>(siteCollection.RootWeb.Lists[0].Title);

var first3Items = from item in someList
                  where item.Id <= 3
                  select item;

foreach (var item in first3Items)
{
    Console.Writeline("{0} is one of the first 3 items in {1}", item.Title, someList.Title);
}

Realistischerweise ist jedoch davon auszugehen, dass Sie für eine sinnvolle Codierung mit LINQ to SharePoint die Spalten benötigen, die ausschließlich zu bestimmten Listen gehören. In der Praxis bedeutet das, Sie müssen die Listennamen und deren jeweilige abgeleitete Inhaltstypen kennen. Besonders beim Codieren müssen Sie davon ausgehen können, dass bestimmte Listen auf den Websites vorhanden sind, für die der Abfragecode ausgeführt wird. Da Ihre Abfragen einer angegebenen Liste auf bestimmte Spalten verweisen werden, müssen Sie außerdem für eine angegebene Liste voraussetzen können, dass eine bestimmte Teilmenge von Spalten in der Liste vorhanden ist. Dies bedingt, dass Ihre SharePoint Foundation-Lösung einem der beiden folgenden Typen entspricht:

  • Die Lösung ist für die Abfrage von bekannten Listentypen konzipiert, die in SharePoint Foundation oder in Produkten mit erweiterter Funktionalität wie etwa Microsoft SharePoint Server enthalten sind.

  • Die Lösung wird in Verbindung mit einem Satz von benutzerdefinierten Listen entwickelt und zusammen mit diesen als Teil einer Featuregruppe oder einer benutzerdefinierten Websitedefinition installiert.

Wir empfehlen Ihnen, zum Generieren der benötigten Klassen und Eigenschaftendeklarationen das SPMetal-Tool zu verwenden.

Schritt 3 (optional): Deaktivieren Sie die Objektänderungsverfolgung

Wenn der Code nur Abfragen in Listen durchführt und keine Listenelemente hinzufügt, bearbeitet oder löscht, können Sie die Objektänderungsverfolgung deaktivieren. Dadurch erzielen Sie eine Leistungssteigerung. Legen Sie die ObjectTrackingEnabled-Eigenschaft auf false fest.

teamSite.ObjectTrackingEnabled = false;

Schritt 4: Definieren Sie die LINQ-Abfrage

Der Nutzen von LINQ liegt darin, dass Abfragen unabhängig von der Datenquelle oder dem LINQ-Anbieter im Wesentlichen immer auf die gleiche Weise geschrieben werden. Abgesehen von kleinen Unterschieden beim Erhalten eines Verweises auf den Datenkontext und das IQueryable<T>-Objekt entsprechen LINQ to SharePoint-Abfragen den Abfragen, die Sie für LINQ to SQL oder LINQ to XML verwenden würden. Weitere Informationen finden Sie unter LINQ to SQL: .NET Language-Integrated Query für relationale Daten und LINQ to XML.

Allerdings ist jeder LINQ-Anbieter anders. Die Unterschiede in den systemeigenen Abfragesprachen der Datenquellen (in die LINQ-Abfragen vom Anbieter übersetzt werden) erzwingen mitunter verschiedene Begrenzungen der Möglichkeiten für Abfragen. Insbesondere gibt es einen Grenzwert für (implizite oder explizite) Listenverbindungen in Abfragen, die den LINQ to SharePoint-Anbieter verwenden. Eine LINQ to SharePoint-Abfrage kann zwei Listen miteinander verbinden, sei es explizit oder implizit, jedoch nur, wenn eine der Listen eine Spalte vom Typ Lookup enthält, die eine Spalte in der jeweils anderen Tabelle nachschlägt. Lässt das Lookup-Feld nur einen Wert zu, muss diese Beziehung zwischen den Listen im Code mit einem EntityRef<TEntity>-Feld in der Klasse dargestellt werden, das den Inhaltstyp der Liste darstellt. Wenn das Feld mehrere Werte zulässt, muss die Beziehung mit einem EntitySet<TEntity>-Feld und einer EntitySet<TEntity>-Eigenschaft dargestellt werden, die dieses Feld einbindet.

TippTipp

Die Log-Eigenschaft ist ein TextWriter, der die CAML-Abfrage schreiben kann, in die die LINQ-Abfrage übersetzt wird. Wenn Sie die CAML-Abfrage sehen können, kann dies beim Debuggen sehr hilfreich sein. Dazu ordnen Sie der Log-Eigenschaft ein TextWriter-Objekt zu. Im folgenden Beispiel wird der OutTextWriter der Log-Eigenschaft zugeordnet. Dadurch wird die CAML-Abfrage in der Konsole angezeigt, wenn eine LINQ-Abfrage in einer Konsolenanwendung ausgeführt wird, wie hier gezeigt.

#if DEBUG
teamSite.Log = Console.Out;
#endif

Schritt 5: Listen Sie die Abfrageergebnisse auf

Wie bei allen LINQ-Anbietern wird eine LINQ to SharePoint-Abfrage erst ausgeführt, nachdem sie aufgelistet wurde. Dies geschieht meist in einer foreach-Schleife. In unüblichen Fällen, in denen Sie eine benutzerdefinierte Enumeration benötigen, z. B. das Überspringen jedes zweiten Elements im Abfrageergebnis, können Sie die Methoden von IEnumerable und IEnumerator verwenden.

Sie können die Ergebnisse der Abfrage auch einer IEnumerable<T>-Variablen zuordnen, z. B. einem IList<T>- oder einem ICollection<T>-Objekt, statt dem anonymen Typ var (in Visual Basic Dim). Dadurch wird die Abfrage sofort ausgeführt, sodass die Variable aufgefüllt werden kann. Im Folgenden ein Beispiel:

EntityList<Announcement> announcements = teamSite.GetList<Announcement>("Announcements")

IList<Announcement> excitingAnnouncements = from announcement in announcements
                                            where announcement.Title.EndsWith("!")
                                            select announcement;

Schritt 6 (optional): Führen Sie Ergebnisse aus mehreren Listen und mehreren Datenquellen zusammen

Sie können Ergebnisse aus mehreren Listen in einer einzigen IList<T> zusammenführen, die dann mithilfe von LINQ to Objects weiter gefiltert werden kann. Im folgenden Beispiel wird gezeigt, wie Sie eine IList<T> der Firmen- und Teamveranstaltungen erstellen und einen Bericht der Veranstaltungen vom heutigen Tag generieren können, die in einem Auditorium stattfinden.

DataContext corpSiteData = new DataContext("https://localhost/CorpSite");
DataContext markTeamData = new DataContext("https://localhost/Marketing");

EntityList<Event> allCorpEvents = corpSiteData.GetList<Event>("Calendar");
EntityList<Event> allMarkTeamEvents = markTeamData.GetList<Event>("Calendar");

List<Event> todaysCorpEvents = (from ev in allCorpEvents
                  where ev.StartDate = DateTime.Now
                  select ev).ToList();

List<Event> todaysTeamEvents = (from ev in allMarkTeamEvents
                  where ev.StartDate = DateTime.Now
                  select ev).ToList();

IEnumerable<Event> mergedEvents = todaysCorpEvents.Union(todaysTeamEvents);

var todaysAuditoriumEventTitles = from ev in mergedEvents
                  where ev.Location.Contains("Auditorium")
                  select new { ev.Title };

foreach (var eventTitle in todaysAuditoriumEventTitles)
{
    Console.WriteLine(eventTitle.Title);
}

Die beiden IList<T>-Objekte müssen den gleichen Typparameter aufweisen.

Schritt 7 (optional): Verbinden Sie Ergebnisse aus mehreren Datenquellen miteinander

Die in Schritt 7 angewendete Methode zum Zusammenführen von Daten aus mehreren SharePoint Foundation-Listen können Sie auch zum Zusammenführen von Daten aus SharePoint Foundation-Listen mit Daten aus anderen Quellen nutzen, vorausgesetzt, die Datensätze aus der anderen Quelle lassen sich in die Klasse umwandeln, die den SharePoint Foundation-Inhaltstyp darstellt. Angenommen, Ihr Code verwendet LINQ to SQL, um ein IList<T>-Objekt mit dem Namen oldClients zu erstellen (wobei T Client ist), und der Code verwendet LINQ to SharePoint, um ein IList<T>-Objekt namens activePatients zu erstellen (wobei T Patient ist). Wenn die Eigenschaften und anderen Member der Client-Klasse eine Teilmenge der Member der Patient-Klasse sind und die entsprechenden Member die gleichen Signaturen aufweisen, können Sie die Daten aus der SQL-Quelle mit den Daten aus der SharePoint Foundation-Liste zusammenführen, wie im folgenden Beispiel gezeigt.

foreach (Patient patient in activePatients)
{
    oldClients.Add((Client)patient);
}

Wenn Sie Daten aus zwei verschiedenen LINQ-Anbietern zusammenführen müssen, ist es noch besser, für beide Anbieter die gleiche Elementtypklasse zu verwenden. Diese Möglichkeit besteht, weil Sie die für LINQ to SharePoint und für den anderen LINQ-Anbieter benötigten Attributdekorationen in der gleichen Klassendeklaration platzieren können. Im folgenden Beispiel wird die Signatur einer Klassendeklaration gezeigt, die mit dem ContentTypeAttribute von LINQ to SharePoint und dem TableAttribute von LINQ to SQL dekoriert ist.

[ContentType(Name="Item", Id="0x01" List="Customers")]
[Table(Name = "Customers")]
public partial class Customer : Item
{
}

Wenn diese Attribute angegeben sind, ist für die Zusammenführung von Daten aus der SQL-Tabelle mit Daten aus der SharePoint Foundation-Liste keine Typumwandlung erforderlich.

Siehe auch

Referenz

SPMetal

ColumnAttribute

ContentTypeAttribute

DataContext

EntityList<TEntity>

EntityRef<TEntity>

EntitySet<TEntity>

ICollection<T>

IEnumerable

IEnumerator

IList<T>

IQueryable<T>

SPContext

SPWebApplication

TableAttribute

Konzepte

Inhaltstyp-IDs

Nicht unterstützte LINQ-Abfragen und zweiphasige Abfragen

Abrufen von Verweisen auf Websites, Webanwendungen und andere Schlüsselobjekte

Gewusst wie: Schreiben in Inhaltsdatenbanken mithilfe von LINQ to SharePoint

Weitere Ressourcen

LINQ to Objects

LINQ to SQL: .NET Language-Integrated Query für relationale Daten

LINQ to XML

Web Parts Overview