如何:使用 LINQ to SharePoint 进行查询

本主题介绍如何使用 LINQ to SharePoint 提供程序查询 Microsoft SharePoint Foundation 列表。

步骤 1:获取对网站的引用


所有针对 LINQ to SharePoint 提供程序的代码编写过程都必须由创建 DataContext 对象开始。该对象代表内容数据库的子集,具体说就是 SharePoint Foundation 网站的列表和列表项。创建此类对象最简单的方法是将需要查询的网站的绝对 URL 作为文字字符串传递给类构造函数,如此处所示。

C#

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

但是,更常见的情况是,您将需要对许多服务器场上的许多网站运行解决方案,而在编写代码时,您并不知道完整的 URL。如果您的代码运行在具有 HTTP 上下文的任何场合(例如运行在 Web 部件自定义应用程序页中),并且您要查询当前网站,则可以使用 SPContext 对象来获取 URL,如本例所示。

C#

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

还可以使用上下文间接获取网站集内其他网站甚至是 Web 应用程序的其他网站集的 URL。例如,以下代码为 Web 应用程序中最旧网站集的首要网站创建 DataContext

C#

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

请注意,您必须释放 DataContext 对象,因为它使用的 SPWeb 对象不是 SPContext 所提供的对象。

注释注释

SPWebApplication 对象的引用需要命名空间 Microsoft.SharePoint.Administration 的 using 语句(在 Visual Basic 中为 Imports)。

有关获取对 SharePoint Foundation 服务器场中网站的引用的其他方法,请参阅获取对网站、Web 应用程序和其他关键对象的引用

如果没有 HTTP 上下文(例如在控制台应用程序中),并且您在编写代码时并不知道服务器的名称,则可以使用“localhost”别名来获取对根网站的引用,如以下示例所示。

C#

using (DataContext topLevelSite = new DataContext(“http://localhost”))
{
}

using (DataContext mySite = new DataContext(“http://localhost/sites/MySite”))
{
}

由于没有 HTTP 上下文,因此您应释放 DataContext 对象。

您可以从 DataContext 派生类,在这种情况下,应使用您的类的构造函数,如以下示例所示。

C#

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

步骤 2:获取对列表的引用


可使用 GetList<T>(String) 方法获取 EntityList<TEntity> 对象。该对象是列表的 IQueryable<T> 表示形式。下面是一个示例。

C#

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

请注意,列表的内容类型必须由显示声明的类表示,在该例中为“Announcement”类。必须使用 ContentTypeAttribute 修饰该类,以指定 SharePoint Foundation 网站中内容类型的名称以及内容类型的 ID。通常,在编写代码时,您应该知道您的代码将要查询哪些列表。代表该内容类型的类必须至少包含一个代表列表中的列的属性,并且必须用至少指定字段名称及其类型的 ColumnAttribute 修饰该属性声明。以下示例演示了启用调用代码功能以调用 GetList<T>(String)(其中 T 是 Announcement)方法所需的最少声明。

C#

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

但是,查询只能引用由内容类型类中的属性所表示的列,因此,如果只提供此最少声明,您的调用代码就只能引用 Title 字段(列),如本例所示。

C#

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

注释注释

如本例所示,将类命名为 Announcement 这一事实并不意味着它必须准确地镜像同名的 SharePoint Foundation 内容类型。这表示您不必对内容类型的每一列分别使用一个属性。该类可以只代表内容类型列的子集,也可以具有更多成员。事实上,这正是 LINQ to SharePoint 提供程序的重要特征,因为网站所有者可以向列表中添加列,而这样做实际上会为该列表创建新的内容类型。该类也不必与列表的内容类型同名。它可以使用任何名称,只要在调用 GetList<T>(String) 方法时将该名称用作类型参数即可。但是,如果您的类与正规的列表内容类型同名,则您的代码的可读性通常会更高。默认情况下,SPMetal 工具遵循此惯例。

内容类型可以从其他内容类型继承,并且对于 GetList<T>(String) 方法调用,您可以使用继承树中处于较高级别的任何内容类型作为类型参数。例如,由于所有内容类型都是从基本 Item 内容类型派生的,因此您可以使用 Item 作为类型参数,如本例所示:

C#

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

源代码必须提供 Item 类的声明,并且该类必须为您的查询所引用的内容类型中的每个列声明属性。

如果使用 Item 内容类型,则可以查询列表,而不需要在编写代码时知道列表名称或其派生内容类型,如本例所示。

C#

DataContext topLevelSite = new DataContext(“http://localhost”);
SPSite siteCollection = new SPSite("http://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);
}

但是,在最切合实际的有效 LINQ to SharePoint 编码的应用场合中,将涉及对特定列表唯一的列,因此,作为一种可行的方法,您需要知道列表名称及其特定的派生内容类型。具体说就是,在编写代码时,您必须能够假设要对其运行查询代码的网站上存在特定列表。而且,由于指定列表的查询将会引用特定列,因此您必须能够假设指定列表将会包含列的特定子集。这意味着您的 SharePoint Foundation 解决方案将属于以下两种类型之一:

  • 它设计用于查询 SharePoint Foundation 中附带的已知列表类型,或功能得到增强的产品(如 Microsoft SharePoint Server)中附带的已知列表类型。

  • 其开发过程将结合作为功能集或自定义网站定义一部分的一个或多个自定义列表,并且与这些列表一起安装。

建议您使用 SPMetal 工具生成所需的类和属性声明。

步骤 3(可选):关闭对象修订


如果您的代码只查询列表,而不添加、删除或编辑列表项,则可以关闭对象修订功能。这样做将会提高性能。将 ObjectTrackingEnabled 属性设置为 false 即可。

HTML

teamSite.ObjectTrackingEnabled = false;

步骤 4:定义 LINQ 查询


LINQ 的价值在于,查询基本上是采用相同的方式编写的,而不考虑数据源或 LINQ 提供程序。除了在引用数据上下文和获取 IQueryable<T> 对象的方式上稍有不同外,LINQ to SharePoint 查询与用于 LINQ to SQLLINQ to XML 的查询基本相同。有关详细信息,请参阅 LINQ to SQL:针对关系数据的 .NET 语言集成查询(该链接可能指向英文页面)LINQ to XML(该链接可能指向英文页面)

但是,没有两个 LINQ 提供程序是完全相同的。数据源的本机查询语言(提供程序要将 LINQ 查询转换为的语言)之间的差异有时会对查询可能性施加不同的限制。特别是在使用 LINQ to SharePoint 提供程序的查询中,列表联接上就存在隐式或显式限制。LINQ to SharePoint 查询可以显式或隐式联接两个列表,但仅在其中一个列表具有可查阅另一表中列的“查阅”类型时。如果“查阅”字段只允许一个值,则必须在您的代码中表示列表之间的这种关系,方法是使用代表列表内容类型的类中的 EntityRef<TEntity> 字段。如果该字段允许多个值,则必须使用 EntitySet<TEntity> 字段和包装该字段的 EntitySet<TEntity> 属性表示这种关系。

提示提示

Log 属性是一个 TextWriter,它可以编写您的 LINQ 查询要转换为的 CAML 查询。能够看到 CAML 查询对调试过程很有帮助。为此,请将 TextWriter 对象分配给 Log 属性。在下面的示例中,将 OutTextWriter 分配给 Log。这会导致在控制台应用程序中执行 LINQ 查询时,CAML 查询将出现在控制台上,如此处所示。

C#

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

步骤 5:枚举查询结果


与所有 LINQ 提供程序一样,仅在枚举 LINQ to SharePoint 查询后才会执行该查询。这通常发生在 foreach 循环中。在少数情况下,如果您需要自定义枚举(例如,隔行跳过结果中的项目),则可以使用 IEnumerableIEnumerator 的方法。

还可以将查询结果分配给 IEnumerable<T> 变量(如 IList<T>ICollection<T> 对象),而不是匿名类型 var(在 Visual Basic 中为 Dim)。这会导致立即执行查询以填充变量。例如:

C#

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

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

步骤 6(可选):合并来自多个列表和多个数据源的结果


可以将来自多个列表的结果合并到一个 IList<T> 中,然后可以使用 LINQ to Objects 进一步筛选该列表。以下示例演示如何生成企业和团队事件的 IList<T>,以及如何生成礼堂中当天发生的事件的报告。

C#

DataContext corpSiteData = new DataContext(“http://localhost/CorpSite”);
DataContext markTeamData = new DataContext(“http://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);
}

两个 IList<T> 对象必须具有相同的类型参数。

步骤 7(可选):联接来自多个数据源的结果


步骤 7 中用于合并多个 SharePoint Foundation 列表中数据的方法可用于合并来自 SharePoint Foundation 列表的数据和来自其他源的数据,前提是来自其他源的记录可转换为代表 SharePoint Foundation 内容类型的类。例如,假设您的代码使用 LINQ to SQL 生成一个名为 oldClients 的 IList<T>(其中 T 是 Client)对象,并假设它使用 LINQ to SharePoint 生成一个名为 activePatients 的 IList<T>(其中 T 是 Patient)对象。如果这些属性和 Client 类的其他成员是 Patient 类的成员的子集,而且对应的成员具有相同的签名,则可以将来自 SQL 源的数据与来自 SharePoint Foundation 列表的数据进行合并,如本例所示。

C#

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

当需要合并来自两个不同 LINQ 提供程序的数据时,最好对这两种提供程序使用相同项目类型的类。这是可以实现的,因为您可以将 LINQ to SharePoint 所需的属性修饰和另一个 LINQ 提供程序所需的属性修饰放在同一个类声明中。以下示例演示了使用 LINQ to SharePoint 的 ContentTypeAttribute 和 LINQ to SQL 的 TableAttribute 进行修饰的类声明的签名。

C#

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

通过这些属性,您无需进行类型转换,即可将 SQL 表中的数据与 SharePoint Foundation 列表中的数据进行合并。

请参阅


引用

SPMetal

ColumnAttribute

ContentTypeAttribute

DataContext

EntityList<TEntity>

EntityRef<TEntity>

EntitySet<TEntity>

ICollection<T>

IEnumerable

IEnumerator

IList<T>

IQueryable<T>

SPContext

SPWebApplication

TableAttribute

概念

内容类型 ID

不支持的 LINQ 查询和两阶段查询

获取对网站、Web 应用程序和其他关键对象的引用

如何:使用 LINQ to SharePoint 写入内容数据库

其他资源

LINQ to Objects(该链接可能指向英文页面)

LINQ to SQL:针对关系数据的 .NET 语言集成查询(该链接可能指向英文页面)

LINQ to XML(该链接可能指向英文页面)

Web 部件概述

原文地址:https://www.cnblogs.com/Bany/p/2957888.html