[AX]AX2012 AIF(十):Query service系统服务中处理大数据集

在查询服务中可以使用分页(pageing)和流(Streaming)两种方式处理查询返回的大量数据。

  • 分页:客户端程序可以传入一个page对象,由它分页返回直至最大记录数上限的数据(默认每个数据源25000条记录)。分页在三种查询服务(静态查询、用户自定义查询、动态查询)中都可以使用,如果传入NULL的page对象,则直接返回直至记录数上限的数据。

分页由分基于位置的分页和基于值的分页两种方式,基于值的分页又分标准值分页、顶级数据源值分页和高级值分页三种,下面用实例代码来看看它们具体如何使用。

示例一:

using System;
using System.Data;
using System.Globalization;
using TestQueryServicePosPage.ServiceReference1;

namespace TestQueryServicePosPage
{
    class Program
    {
        static void Main()
        {
            var client = new QueryServiceClient();

            var i = 0;
            DataSet dataSet;
            Paging paging = new PositionBasedPaging { StartingPosition = 1, NumberOfRecordsToFetch = 10 };

            do
            {
                // Call the CustTable query using the query service.
                dataSet = client.ExecuteStaticQuery("CustTable", ref paging);

                // Code to perform operations on the data returned.
                Console.WriteLine("Query service call: " + i.ToString(CultureInfo.InvariantCulture));
                Console.WriteLine("Number of Records in CustTable: " + dataSet.Tables[0].Rows.Count.ToString(CultureInfo.InvariantCulture));
                Console.WriteLine("Number of Records in CustTrans: " + dataSet.Tables[1].Rows.Count.ToString(CultureInfo.InvariantCulture));
                Console.WriteLine("Number of Records in CustTransOpen: " + dataSet.Tables[2].Rows.Count.ToString(CultureInfo.InvariantCulture));
                i++;
            }
            // Check if the last call returned any data. If so, then this is the next page of data.
            while (dataSet.Tables[0].Rows.Count > 0);

            Console.ReadLine();
        }
    }
}

在上面的例子中使用了基于位置的分页,每个数据源返回的记录每页不超过10个,通过传入相同的Paging对象多次执行查询顶级数据源以获取所有数据,如果需要按照一定顺序返回记录,需要在Query中显式的指定排序字符串。

示例二:

var client = new QueryServiceClient();

            var i = 0;
            Paging paging = new ValueBasedPaging() { RecordLimit = 10 };

            do
            {
                // Call the CustTable query using the query service.
                var dataSet = client.ExecuteStaticQuery("CustTable", ref paging);

                // Code to perform operations on the data returned.
                Console.WriteLine("Query service call: " + i.ToString(CultureInfo.InvariantCulture));
                Console.WriteLine("Number of Records in CustTable: " + dataSet.Tables[0].Rows.Count.ToString(CultureInfo.InvariantCulture));
                Console.WriteLine("Number of Records in CustTrans: " + dataSet.Tables[1].Rows.Count.ToString(CultureInfo.InvariantCulture));
                Console.WriteLine("Number of Records in CustTransOpen: " + dataSet.Tables[2].Rows.Count.ToString(CultureInfo.InvariantCulture));
                i++;
            }
            // Check if the returned bookmark is NULL. If so, there is no more data to be returned.
            while (((ValueBasedPaging)paging).Bookmark != null);

上面的例子演示如何使用标准值分页,通过查询ValgeBasedPaging对象的Bookmark检查是否还有下一页的数据,没个数据源都返回不超过RecordLimit指定的记录数。

示例三:

var client = new QueryServiceClient();

            var i = 0;
            Paging paging = new TopLevelValueBasedPaging() { RecordLimit = 25, LimitTopLevelDataSourcesOnly = true };

            do
            {
                // Call the CustTable query using the query service.
                var dataSet = client.ExecuteStaticQuery("CustTable", ref paging);

                // Code to perform operations on the data returned.
                Console.WriteLine("Query service call: " + i.ToString(CultureInfo.InvariantCulture));
                Console.WriteLine("Number of Records in CustTable: " + dataSet.Tables[0].Rows.Count.ToString(CultureInfo.InvariantCulture));
                Console.WriteLine("Number of Records in CustTrans: " + dataSet.Tables[1].Rows.Count.ToString(CultureInfo.InvariantCulture));
                Console.WriteLine("Number of Records in CustTransOpen: " + dataSet.Tables[2].Rows.Count.ToString(CultureInfo.InvariantCulture));
                i++;
            }
            // Check if the last call returned any data. If so, then this is the next page of data.
            while (((ValueBasedPaging)paging).Bookmark != null);

上面的例子演示级记录值分页的使用,参数LimitTopLevelDataSourcesOnly设为true时顶级数据源只返回RecordLimit指定的记录数,子级数据源则返回最大记录数上限的记录数;如果LimitTopLevelDataSourcesOnly设为false,则所有数据源返回RecordLimit指定记录数的数据源记录,这和标准值分页是一样的。

示例四:

var client = new QueryServiceClient();

            var i = 0;
            var advPaging = new AdvancedValueBasedPaging();
            Paging paging = advPaging;

            advPaging.RecordLimits = new[] {
                new DataSourceRecordLimit() { DataSourceName = "CustTable", RecordLimit = 2 },
                new DataSourceRecordLimit() { DataSourceName = "CustTrans", RecordLimit = 10 },
                new DataSourceRecordLimit() { DataSourceName = "CustTransOpen", RecordLimit = 10 }};

            do
            {
                // Call the CustTable query using the query service.
                var dataSet = client.ExecuteStaticQuery("CustTable", ref paging);

                // Code to perform operations on the data returned.
                Console.WriteLine("Query service call: " + i.ToString(CultureInfo.InvariantCulture));
                Console.WriteLine("Number of Records in CustTable: " + dataSet.Tables[0].Rows.Count.ToString(CultureInfo.InvariantCulture));
                Console.WriteLine("Number of Records in CustTrans: " + dataSet.Tables[1].Rows.Count.ToString(CultureInfo.InvariantCulture));
                Console.WriteLine("Number of Records in CustTransOpen: " + dataSet.Tables[2].Rows.Count.ToString(CultureInfo.InvariantCulture));
                i++;
            }
            // Check if the last call returned any data. If so, then this is the next p

上面的例子演示高级值分页的使用,在高级值分页中可以对每个数据源设置返回记录数的限制。

在实际测试中以上的例子和预期的结果都有差异,为了简化测试,这里修改一下查询“CustTable”为:顶级数据源为表CustTable(包含39条记录),CustTable下包含表CustTrans(只有2条记录,分别对应2条CustTable的记录),子级CustTrans和父级CustTable数据源的关系分三种情况,一是Relation=No,两者无关联;二是Relation=Yes,FetchMode=1:1;三是Relations=Yes,FetchMode=1:n,测试结果如下:

  样例一:基于位置分页 样例二:标准值分页 样例三:顶级记录值分页 样例四:高级值分页
Relation=No

NumberOfRecordsToFetch=1:每次CustTable返回1条记录,CustTrans返回1条记录,分页78次

NumberOfRecordsToFetch=2:每次CustTable返回1条记录,CustTrans返回2条记录,分页39次

NumberOfRecordsToFetch=10:每次CustTable返回5条记录,CustTrans返回2条记录,分页8次

NumberOfRecordsToFetch=39:每次CustTable返回20条记录,CustTrans返回2条记录,分页2次

RecordLimit=1:每次CustTable返回1条记录,CustTrans返回1条记录,分页78次

RecordLimit=2:每次CustTable返回2条记录,CustTrans返回2条记录,分页20次

RecordLimit=10:每次CustTable返回5条记录,CustTrans返回2条记录,分页8次

RecordLimit=39:每次CustTable返回20条记录,CustTrans返回2条记录,分页2次

RecordLimit=1,LimitTopLevelDataSourcesOnly = true:每次CustTable返回1条记录,CustTrans返回2条记录,分页39次

RecordLimit=2LimitTopLevelDataSourcesOnly = true:每次CustTable返回2条记录,CustTrans返回2条记录,分页20次

RecordLimit=10LimitTopLevelDataSourcesOnly = true:每次CustTable返回10条记录,CustTrans返回2条记录,分页4次

RecordLimit=39LimitTopLevelDataSourcesOnly = true:每次CustTable返回39条记录,CustTrans返回2条记录,分页1次

LimitTopLevelDataSourcesOnly = false的情况和标准值分页相同

CustTable.RecordLimit=1,CustTrans.RecordLimit=1:每次CustTable返回1条记录,CustTrans返回1条记录,分页78次

CustTable.RecordLimit=1,CustTrans.RecordLimit=2:每次CustTable返回1条记录,CustTrans返回2条记录,分页39次

CustTable.RecordLimit=2,CustTrans.RecordLimit=2:每次CustTable返回2条记录,CustTrans返回1条记录,分页20次

CustTable.RecordLimit=10,CustTrans.RecordLimit=2:每次CustTable返回10条记录,CustTrans返回2条记录,分页4次

CustTable.RecordLimit=10,CustTrans.RecordLimit=1:每次CustTable返回1条记录,CustTrans返回1条记录,分页78次

Relation=Yes,FetchMode=1:1 NumberOfRecordsToFetch=1:每次CustTable返回1条记录,CustTrans返回1条记录,分页2次

NumberOfRecordsToFetch=2:每次CustTable返回2条记录,CustTrans返回2条记录,分页1次

NumberOfRecordsToFetch=10:每次CustTable返回2条记录,CustTrans返回2条记录,分页1次

NumberOfRecordsToFetch=39:每次CustTable返回2条记录,CustTrans返回2条记录,分页1次

同样例一,Relation=Yes,FetchMode=1:1 同样例一,Relation=Yes,FetchMode=1:1  

CustTable.RecordLimit=1,CustTrans.RecordLimit=1:每次CustTable返回1条记录,CustTrans返回1条记录,分页2次

CustTable.RecordLimit=1,CustTrans.RecordLimit=2:每次CustTable返回1条记录,CustTrans返回1条记录,分页2次

CustTable.RecordLimit=2,CustTrans.RecordLimit=2:每次CustTable返回2条记录,CustTrans返回2条记录,分页1次

CustTable.RecordLimit=10,CustTrans.RecordLimit=2:每次CustTable返回2条记录,CustTrans返回2条记录,分页1次

CustTable.RecordLimit=10,CustTrans.RecordLimit=1:每次CustTable返回1条记录,CustTrans返回1条记录,分页2次

Relation=Yes,FetchMode=1:n  同Relation=Yes,FetchMode=1:1  同样例一,Relation=Yes,FetchMode=1:1 同样例一,Relation=Yes,FetchMode=1:1  同上

从以上得出的结论是如果设置父子数据源关系连接,无论是1:1还是1:n的取值方式,最终都只返回父记录的2条记录,这和我们想要的left join效果是不一致的,或者说分页就不支持1:n连接。其次可以看出值分页的recordlimit是在单个数据源上应用,而位置分页的NumberOfRecordsToFetch是应用在每次父子数据源起来的记录总数。上面的结果只是2级2个数据源的情况,如果更复杂些的Query不知道会是什么样的结果,总之,分页的结果不像MSDN说的那样确定,使用的时候还是依据具体的数据自行调试处理吧。

流:可以使用ExecuteStreamedQuery的ExecuteStreamedQuery()和ExecuteStreamedDynamicQuery()方法从自定义查询或者动态查询中返回一个Stream类型的流对象,但是如何从这个Stream中分解出记录的数据MSDN上没有说明,搜遍网络也没有找到有用的信息,等着微软更新再说吧。

  

原文地址:https://www.cnblogs.com/duanshuiliu/p/2947751.html