博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[AX]AX2012 SSRS报表使用Report Data Provider Class作为数据集
阅读量:6332 次
发布时间:2019-06-22

本文共 6603 字,大约阅读时间需要 22 分钟。

在SSRS报表中使用默认的Dynamics AX作为数据源时可以使用多种数据集抓取数据,Report data provider class是其中一种,它用在一些数据在呈现到报表前还需要做一些处理,这些处理在AX中使用X++完成。

如果要在报表中使用一些参数,就需要在AOT中定义一个DataContract类,由它来定义报表所有参数名称及类型:

[DataContractAttribute]public class SrsRDPContractSample{    AccountNum accountNum;    CustAccountStatement accountStmt;    boolean inclTax;}[DataMemberAttribute("AccountNum")]public AccountNum parmAccountNum(AccountNum _accountNum = accountNum){    accountNum = _accountNum;    return accountNum;}[DataMemberAttribute("CustAccountStatement")]public CustAccountStatement parmAccountStmt(CustAccountStatement _accountStmt = accountStmt){    accountStmt = _accountStmt;    return accountStmt;}[DataMemberAttribute("InclTax")]public boolean parmInclTax(boolean _inclTax = inclTax){    inclTax = _inclTax;    return inclTax;}

SrsRDPContractSample是一个不继承于任何类的类,通过DataContractAttribute特性标注,定义了几个parmXXX方法来返回成员变量,这些方法通过DataMemberAttribute特性来定义报表参数的名称。

[    SRSReportQueryAttribute (querystr(Cust)),    SRSReportParameterAttribute(classstr(SrsRDPContractSample))]public class SrsRdpSampleClass extends SRSReportDataProviderBase{    TmpCustTableSample tmpCust;}[SRSReportDataSetAttribute("TmpCust")]public TmpCustTableSample getTmpCustTable(){    select * from tmpCust;    return tmpCust;}public void processReport(){    AccountNum              accountNumber;    CustAccountStatement    custAcctStmt;    boolean                 boolInclTax;    Query                   query;    QueryRun                queryRun;    QueryBuildDataSource    queryBuildDataSource;    QueryBuildRange         queryBuildRange;    CustTable               queryCustTable;    SrsRdpContractSample    dataContract;    // Get the query from the runtime using a dynamic query.     // This base class method reads the query specified in the SRSReportQueryAttribute attribute.    query = this.parmQuery();            // Get the parameters passed from runtime.     // The base class methods read the SRSReportParameterAttribute attribute.     dataContract = this.parmDataContract();    accountNumber = dataContract.parmAccountNum();    custAcctStmt = dataContract.parmAccountStmt();    boolInclTax = dataContract.parmInclTax();            // Add parameters to the query.    queryBuildDataSource = query.dataSourceTable(tablenum(CustTable));                    if(accountNumber)    {        queryBuildRange = queryBuildDataSource.findRange(fieldnum(CustTable, AccountNum));        if (!queryBuildRange)        {            queryBuildRange = queryBuildDataSource.addRange(fieldnum(CustTable, AccountNum));        }        // If an account number has not been set, then use the parameter value to set it.        if(!queryBuildRange.value())            queryBuildRange.value(accountNumber);    }                    if(custAcctStmt)    {        queryBuildRange = queryBuildDataSource.findRange(fieldnum(CustTable, AccountStatement));        if (!queryBuildRange)        {            queryBuildRange = queryBuildDataSource.addRange(fieldnum(CustTable, AccountStatement));        }        // If an account statement has not been set, then use the parameter value to set it.        if(!queryBuildRange.value())            queryBuildRange.value(int2str(custAcctStmt));    }            if(boolInclTax)    {        queryBuildRange = queryBuildDataSource.findRange(fieldnum(CustTable, InclTax));        if (!queryBuildRange)        {            queryBuildRange = queryBuildDataSource.addRange(fieldnum(CustTable, InclTax));        }        // If flag to include tax has not been set, then use the parameter value to set it.        if(!queryBuildRange.value())            queryBuildRange.value(int2str(boolInclTax));    }                    // Run the query with modified ranges.    queryRun = new QueryRun(query);    ttsbegin;    while(queryRun.next())    {        tmpCust.clear();        queryCustTable = queryRun.get(tablenum(CustTable));        tmpCust.AccountNum = queryCustTable.AccountNum;        tmpCust.CustName = queryCustTable.name();        tmpCust.LogisticsAddressing = queryCustTable.address();        tmpCust.CustGroupId = queryCustTable.CustGroup;        tmpCust.Phone = queryCustTable.phone();        tmpCust.CustInvoiceAccount = queryCustTable.InvoiceAccount;        tmpCust.CustAccountStatement = queryCustTable.AccountStatement;        tmpCust.InclTax = queryCustTable.InclTax;        tmpCust.insert();    }    ttscommit;}

SrsRdpSampleClass就是我们的Report data provider class,继承于SRSReportDataProviderBase类,注意特性SRSReportQueryAttribute('Cust')标识了所使用的Query对象,特性SRSReportParameterAttribute(classstr(SrsRDPContractSample))则说明了前面定义的报表参数data contract类。SrsRdpSampleClass定义了表TmpCustTableSample类型的变量tmpCust,TmpCustTableSample是一个TmpDB类型的临时表,通过getTmpCustTable方法返回这个临时表变量中的纪录数据,注意getTmpCustTable方法带有特性[SRSReportDataSetAttribute('TmpCust')],标识一个名为TmpCust的数据集。那么这个临时表tmpCust中的纪录数据又是哪里来的呢?这个是在重载函数processReport()函数中添加的,先是从通过this.parmQuery()得到相应的query对象,this.parmDataContract()得到data contract对象,根据参数来添加过滤条件到Query,最后运行Query,得到的结果添加到临时表变量tmpCust。

在VS2010中要使用这个report data provider,需要把data source type设为Report data provider:

 

在属性Query中点击...按钮可以选择到SrsRdpSampleClass及其fields,结果自动写入到Query属性中的查询字符串。有了dataset就可以布局数据字段了,更详细的步骤参看。注意Dataset的Dynamic Filters属性,设为true允许用户在query中自定义一些过滤的条件。

Report data provider被.net编写的service调用,所以它的调试需要做一些特别的设置。首先要保证AOS服务所用账号被添加到Microsoft Dynamics Ax Debugging Users本地用户组中,同时Microsoft Dynamics AX server cofiguration中启用Enable brakpoints to debug X++ code running on this server和Enable global breakpoints to debug X++ code running in batch jobs,当然用户options中Debug mode 设置为when breakpoint。最后还要记得手工打开运行Microsoft dynamics 2012 debugger,只有debugger窗口打开时才会中断到断点。详见

遇到一个奇怪的问题是如果在Report data provider class中更改了所用的Query,比如把前面的SRSReportQueryAttribute('Cust')改成SRSReportQueryAttribute('CopyOfCust'),CopyOfCust是从Query “Cust”复制过来的,在VS2010中预览报表可以看到结果是来自于这个新的Query,但是如果在AX中已经使用过MenuItem运行过这个报表就会发现总是使用第一次运行时所用的Query,原以为这和用户的User Data有关系,清理了几遍User data也是这样。被这个问题折腾了快半天,过调试代码发现整个过程异常复杂,大致是SrsReportRunService.getReportDataContract(str _reportName)初始化SrsReportDataContract的实例->SrsReportRunService.getRdlParser(str _reportName)->SrsReportRunCache.getRdlParser(str _reportName)->SrsReportRunCache::getValue(SrsReportRunCacheScope _scope, container _key)->classfactory.globalObjectCache().find(SrsReportRunCache::getCacheScopeStr(_scope), _key),最后看到这些信息pack之后被存放到了SysGlobalObjectCache,而不是User data中,所以清理User data没有用。我们知道SysGlobalObjectCache存放的是在所有client session可以共享的缓存数据,用来存放那些频繁读取的数据以提高性能,重启AOS这些cache数据就丢失了,而我们的这个问题实际上是可以手工刷新来解决的:Tools->Caches->Refresh elements,为什么就不能在VS2010更新报表后自动刷新下相关缓存纪录呢?!M$程序员还没来得及吧,程序员好累!

转载于:https://www.cnblogs.com/duanshuiliu/archive/2012/08/21/2648819.html

你可能感兴趣的文章
javascript的作用域
查看>>
新形势下初创B2B行业网站如何经营
查看>>
初心大陆-----python宝典 第五章之列表
查看>>
java基础学习2
查看>>
sysbench使用笔记
查看>>
有关电子商务信息的介绍
查看>>
NFC·(近距离无线通讯技术)
查看>>
多线程基础(三)NSThread基础
查看>>
PHP的学习--Traits新特性
查看>>
ubuntu下,py2,py3共存,/usr/bin/python: No module named virtualenvwrapper错误解决方法
查看>>
Ext.form.field.Number numberfield
查看>>
Linux文件夹分析
查看>>
解决部分月份绩效无法显示的问题:timestamp\union al\autocommit等的用法
查看>>
nginx 域名跳转 Nginx跳转自动到带www域名规则配置、nginx多域名向主域名跳转
查看>>
man openstack >>1.txt
查看>>
linux几大服务器版本大比拼
查看>>
在BT5系统中安装postgresQL
查看>>
Can't connect to MySQL server on 'localhost'
查看>>
【Magedu】Week01
查看>>
写给MongoDB开发者的50条建议Tip25
查看>>