使用CAML查询大型外部列表



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

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

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

我怎样才能最好地做到这一点?

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

我的想法是,您可能需要修改readlist-method,以确保它读取整个sql表,但使用readlist-method中过滤器参数指定的where参数。就像

伪代码:

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
    }
}

祝你好运

根据查询的结构和这里提供的信息,报告表明<RowLimit>实现了您想要的功能:

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

语法

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

注意事项:请注意文档中的注释。

你可能已经为你的目的检查过了(引用你的问题:"所以我在操作中添加了一个大小为200的限制过滤器。")。那么,进入下一个问题:

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

这似乎很奇怪。如果您确实在使用<RowLimit>并且文档是正确的:

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

:

<RowLimit>标签在视图的模式定义中(的直接子视图),因此不能嵌套在<Query>标签中。

那么,嵌套查询在View组件之前执行,以满足limit语句的保证,这应该成立。由此推论,这应该允许您跨查询定义的集合的其余部分执行结果分页。

基于这些原则,我们可以构造一个像这样的页面查询:
<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'

我可能完全错了,因为这看起来正是你已经尝试过的。但是,为了详尽地描绘出这个空间,建议一下也无妨。

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

这是无代码BCS本身不能真正解决的情况之一。要么在数据库服务器上将其作为存储过程实现,要么使用Visual Studio中内置的自定义BDC连接器。

如果你不能把整个SQL表拉到你的外部列表中,那么你就不可能像查询SharePoint列表那样查询数据集。

然而,我可以提供一个解决方案,我们已经使用了几乎相同的场景,对我们来说非常有效。在我们的场景中,我们正在查询一个Oracle数据库,它需要很长时间才能返回大型数据集。

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

下面的例子有点老套,但它们很好地说明了这个概念。

那么,从定义如何查询数据集以及返回哪些字段的接口开始:

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
    }
}

通过这个实现,您已经在各自的数据提供程序中封装了查询的逻辑和细节。

现在您有了一个工厂,它构建了适当的数据提供程序(基于指定的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();
}

此模式将您的外部实现封装到它自己的数据提供程序中,并从消费者那里抽象出查询的细节。所有消费者需要做的就是指定他们想要查询的列表的名称,然后工厂决定启动哪个实现。

你甚至可以让你的IQueryData接口实现泛型来进一步扩展:

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

这将为消费者也指定他们期望返回的对象类型打开大门。

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

我只是想提出这个建议,因为它看起来几乎和我们一年前遇到的情况一样,这个策略对我们来说一直很有效。

使用SPQuery和SPListItemCollection中的listtitemcollectionposition属性,例如

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);
}

相关内容

  • 没有找到相关文章

最新更新