上次修改时间: 2011年9月22日
适用范围: SharePoint Foundation 2010
本文内容
不支持的查询
两阶段查询
差异无关紧要的场合
本主题描述 LINQ to SharePoint 提供程序不支持的某些类型的语言集成查询 (LINQ) 查询。它还描述如何对使用 LINQ 运算符的查询(LINQ to SharePoint 提供程序无法将这些查询转换为协作应用程序标记语言 (CAML))使用两阶段过程。
不支持的查询
一些在 C# 和 Visual Basic 的 LINQ 语法中可用的以及仅在特定类型的数据源的某些上下文中工作正常的查询,在用于 Microsoft SharePoint Foundation 网站中的数据时,会造成不可接受的低性能。LINQ to SharePoint 提供程序不支持此类查询。具体而言,这包括需要对内容数据库进行多次单独查询的任意查询。例如,如果对表 A 的查询实际需要为表 A 的每一行对表 B 进行单独查询,则对表 A 的查询不受支持。同样,尝试使用 LINQ union 关键字(如以下示例所示)不受支持并将引发异常,因为此尝试需要对两个列表进行单独查询。
DataContext data = new DataContext("http://ContosoServer"); DataContext juniorData = new DataContext("http://ContosoServer/JuniorTeamSite");
EntityList<Announcement> Announcements = data.GetList<Announcement>("Announcements");
EntityList<Announcement> JuniorAnnouncements = juniorData.GetList<Announcement>("Announcements");
var seniorAnns = from ann in Announcements
select ann;
var juniorAnns = from ann in JuniorAnnouncements
select ann;
IEnumerable<Announcement> mergedAnns = seniorAnns.union(juniorAnns);
foreach (Announcement ann in mergedAnns)
{
Console.WriteLine(ann.Title);
}
此规则的一种含义是,假定两个 SharePoint Foundation 列表之间存在隐式联接的查询当且仅当联接字段配置为查阅字段时受支持。
两阶段查询
某些 LINQ 查询无法完全转换为 CAML。但从原则上说,这些查询应能够正常运行,因为可以按两个阶段来执行它们。在第一个阶段中,LINQ to SharePoint 提供程序会尽可能多地将查询转换为 CAML 并执行该查询。这将生成一个数据超集,此超集将作为一个 IEnumerable<T> 对象从内容数据库传递回前端 Web 服务器。在第二个阶段中,会将查询的其余部分改写为针对 IEnumerable<T> 对象的 LINQ to Objects(该链接可能指向英文页面) 查询。(不过,可使用对内容数据库的单个查询来执行第一个阶段,否则整个查询将引发异常。)
在单阶段查询的示例中,请考虑 LINQ select 子句,如"select new { c.Name, c.ZipCode }"。可以将其转换为以下形式的 CAML:一个包含两个 <FieldRef(该链接可能指向英文页面)> 子元素的 <ViewFields(该链接可能指向英文页面)> 标记。但子句"select new { c.Price*2, c.Orders, c.Customer }"包含 CAML 中不支持的数学函数。因此,虽然查询已由 LINQ to SharePoint 转换并执行,但仅执行到 select 子句。然后,将从 CAML 查询中收到的结果作为一个 IEnumerable<T> 对象发送到前端 Web 服务器。前端 Web 服务器上的新 LINQ 查询之后将使用 LINQ to Objects 的 Enumerable.Select() 方法对该对象执行 select 子句投影。
没有用于指定不支持或需要两个阶段的 LINQ 运算符的简单方法。例如,如果要合并的两个数据源都是来自内容数据库的列表,则 Union() 运算符不受支持(如前所述)。但是,如果其中的一个数据源是 SharePoint Foundation 列表,另一个数据源是内存中已有的表,则可以使用 Union()。
在大多数情况下,需要将要求使用数学运算的查询方法拆分为两个阶段,但如果 LINQ to SharePoint 可从 SharePoint Foundation 对象模型中获取值,则无需这样做。例如,Count() 和 LongCount() 方法不需要将查询拆分为两个阶段。
下面的运算符通常需要两个阶段且能正常工作,前提是第一个阶段只需对内容数据库进行一次查询。
差异无关紧要的场合
如果您使用 ToList<TSource>(IEnumerable<TSource>)、ToDictionary() 或 ToArray<TSource>(IEnumerable<TSource>) 方法将查询的 CAML 可转换部分的输出写入 IEnumerable<T> 对象中,则紧跟在对这些方法之一的调用后面的查询部分将使用 Enumerable 类而非 Queryable 类中的查询运算符。在此情况下,两阶段查询和单阶段查询之间的差异将无关紧要。
例如,将以下两个查询进行比较。由于使用了数学运算符"-",因此这两个查询都需要分为两个阶段;但这一点在第二个查询中更加明显,因为仅在 from 行中使用了 LINQ to SharePoint,这会将整个列表"orders"读入 IList<T> 中。
var ordersInArrears = from order in orders
where order.Price – order.Paid > 0
select order;
var ordersInArrears = from order in orders.ToList()
where order.Price – order.Paid > 0
select order;
此外,通过手动将查询拆分为 LINQ to SharePoint 部分和 LINQ to Objects 部分,您可以使用无法通过其他方式使用的 LINQ 关键字。例如,以下版本的对两组通知进行的合并尝试将适用,因为这会单独将 LINQ to SharePoint 查询枚举到两个 IEnumerable<T> 对象中。使用的 union 关键字为 LINQ to Objects 版本的 Union()。
DataContext data = new DataContext("http://ContosoServer"); DataContext juniorData = new DataContext("http://ContosoServer/JuniorTeamSite");
EntityList<Announcement> Announcements = data.GetList<Announcement>("Announcements");
EntityList<Announcement> JuniorAnnouncements = juniorData.GetList<Announcement>("Announcements");
List<Announcement> seniorAnns = (from ann in Announcement
select ann).ToList();
List<Announcement> juniorAnns = (from ann in JuniorAnnouncements
select ann).ToList();
IEnumerable<Announcement> mergedAnns = seniorAnns.union(juniorAnns);
foreach (Announcement ann in mergedAnns)
{
Console.WriteLine(ann.Title);
}
请参阅
引用
Select