使用CAML查询大型外部列表

时间:2011-08-25 04:37:19

标签: sharepoint caml bcs

我有一个SharePoint外部列表,指向100,000个记录的SQL表。我必须在读取列表操作上设置过滤器,否则列表不起作用。它会在尝试返回完整列表时超时。所以我在操作中添加了一个大小为200的限制过滤器。

这个问题导致当我使用CAML查询外部列表时,它只搜索返回的200个条目,而不是完整列表。

我希望它能够搜索整个列表,但最多只返回200个匹配的条目。

我怎样才能最好地实现这一目标?

6 个答案:

答案 0 :(得分:2)

也许SharePoint-Exchange的这个答案可以帮到你。 https://sharepoint.stackexchange.com/questions/31566/caml-and-external-list-pass-parameter-to-readlist-finder-method

我的理念是,您可能需要修改readlist方法,以确保它读取整个SQL表,但使用readlist-method中filter参数指定的Where-parameter。像

这样的东西

伪代码:

public static IEnumerable<YourEntity> ReadList(string param)
{
    if(string.IsNullOrEmpty(param) == true)
    {
        //Your original code thata only fetches the first 200 items
    }
    else
    {
        //Read your SQL-table with a Where ParamName = 'param' - clause
    }
}
祝你好运

答案 1 :(得分:2)

根据您的查询结构和此处显示的信息,reports indicate <RowLimit>实现了您想要的功能:

  

RowLimit 元素设置视图的行限制。

     

<强>语法

     

     

<强>属性

     
      
  • 分页:可选布尔值。如果列表支持,则为TRUE   逐页显示更多项目。如果为FALSE或未指定,那么   行限制是绝对的,没有链接可以查看更多项目。
  •   

警告:请注意the documentation中的评论。

您可能已经为了您的目的检查了这一点(引用您的问题:“所以我在操作中添加了一个大小为200的限制过滤器。”)。那么,到下一期:

  

这导致的问题是当我使用查询外部列表时   CAML它只搜索返回的200个条目,而不是完整列表。

这看起来很奇怪。如果您确实使用<RowLimit>并且文档正确无误:

  

RowLimit元素设置视图的行限制。

And

  

<RowLimit>标记位于视图的模式定义中(直接子项),因此无法嵌套在<Query>标记内。

然后应该认为嵌套查询在View组件之前执行,以满足限制语句的保证。作为推论,这应该允许您在查询定义的其余集合中执行结果分页。

基于这些原则,我们可以构建一个像这样的分页查询:

<View>
    <RowLimit Paged='True'>200</RowLimit>
    <Method Name='ReadList'/>
    <Query>
        <Where>
            <Contains>
                    <FieldRef Name='Name'/>
                    <Value Type='Text'>{0}</Value>
            </Contains>
        </Where>
    </Query>
    <ViewFields>
    <FieldRef Name='Name'/>
    <FieldRef Name='Id'/>
    <FieldRef Name='BdcIdentity'/>                        
    </ViewFields>
</View>

注意,如文档中所述,我们必须实施<PagedRowset>。如果不需要,我们会在上面设置Paged='FALSE'

我可能完全不在这里,因为这看起来就像你已经尝试过的那样。但是,为了彻底规划出空间,建议它不会有害。

答案 2 :(得分:0)

不幸的是,这是查询外部列表的已知问题。但是,在OOB Web部件中,通过XSLT支持分页。 RowLimit仅适用于XSLT,而不适用于CAML查询。在外部列表中,没有服务器端分页,而是分页是客户端,这意味着SharePoint会提取所有数据,然后在视图中设置过滤器限制。

答案 3 :(得分:0)

这是其中没有代码BCS本身并没有真正削减它的场景之一。将其实现为数据库服务器上的存储过程,或使用Visual Studio中内置的自定义BDC连接器。

答案 4 :(得分:0)

如果您无法将整个SQL表拉入外部列表,那么就无法像SharePoint列表一样查询该数据集。

但是,我可以提供一种解决方案,我们已经将其用于几乎完全相同的方案,这对我们来说效果非常好。在我们的场景中,我们正在查询Oracle数据库,该数据库需要永远返回大型数据集。

我们采用的方法是使用Factory模式来确定应该以何种方式查询数据源(SharePoint列表,外部数据库等)。

以下示例有点陈词滥调,但它们很好地说明了这一概念。

因此,从一个interfaced开始,它定义了如何查询数据集以及将返回哪些字段:

public interface IQueryData
{
    string ListToQuery { get; set; }
    List<MyResultObject> ExecuteQuery();
}

您有一个自定义对象,表示查询返回的单个记录

public class MyResultObject
{
    public string FileRef { get; }
    public string Title { get; set; }
    // any other fields you'd like to see potentially returned...
}

然后你有一个数据提供者为SQL数据源实现这个接口

public class SqlDataProvider : IQueryData
{
    public string ListToQuery { get { return "BigSqlTable"; } }
    public List<MyResultObject> ExecuteQuery()
    {
        // query your external data source here...
        // populate a list of MyResultObject's from the result set and return it to the consumer
    }
}

您还有一个实现SharePoint数据源接口的数据提供程序

public class SharePointDataProvider : IQueryData
{
    public string ListToQuery { get { return "MySharePointList"; } }
    public List<MyResultObject> ExecuteQuery()
    {
        // query your SharePoint list here, using CAML, SharePoint object model, etc...
        // populate a list of MyResultObject's from the result set and return it to the consumer
    }
}

通过此实现,您已在相应的数据提供程序中封装了查询的逻辑和详细信息。

现在你有一个Factory来构建适当的数据提供者(基于指定的ListToQuery参数):

public static class QueryDataProviderFactory
{
    public static IQueryData Build(string listToQuery)
    {
        switch(listToQuery)
        {
            case "BigSqlTable": return new SqlDataProvider(); break;
            case "MySharePointList": return new SharePointDataProvider(); break;
            // you can have many other implementations here that query your data sources in different manners
        }
    }
}

最后,您将使用工厂启动查询,传入要查询的数据源的名称:

public List<MyResultObject> RunQuery()
{
    return QueryDataProviderFactory.Build("BigSqlTable").ExecuteQuery();
}

此模式将外部实现封装到自己的数据提供程序中,并从消费者中抽象出查询的详细信息。所有消费者需要做的是指定他们想要查询的列表的名称,并且Factory决定要启动哪个实现。

您甚至可以使IQueryData接口实现泛型以进一步扩展:

public interface IQueryData<T>
{
    string ListToQuery { get; set; }
    List<T> ExecuteQuery();
}

这将为消费者打开大门,同时指明他们希望返回的对象类型。

我们的查询数据接口实际上有更多的成员,它们为查询提供者添加了更多的可扩展性点,但我认为这个例子以简洁易懂的方式说明了这一点。

只是想提供这个建议,因为它似乎与我们在大约一年前遇到的情况几乎相同,而且这种策略对我们来说非常有效。

答案 5 :(得分:-1)

使用来自SPQuerySPListItemCollection的属性ListItemCollectionPosition,例如

using (var web = site.OpenWeb("bla-bla"))
{
  var list = web.Lists["your_list"];
  var query = new SPQuery();
  query.Query = "your query";
  do
  {
    var items = list.GetItems(query);
    foreach(SPListItem item in items)
    {
      //your code
    }
    query.ListItemCollectionPosition = items.ListItemCollectionPosition;
  } while(query.ListItemCollectionPosition != null);
}