微软CRM2011升级到了2013之后,原来可以把报表放在记录的窗体中,现在不行了。非得放在记录列表中不可,然后再带上记录窗体。这么明显的一个BUG,到了它的SP1包出来,还是没有改进。这里就且不说它了。
即使能在列表里面出来,它也变成了三个选项:
对于自己开发的实体而言,第一个选项:“所有适用的记录”一般都是出不来任何记录的。但这并不意味着你就可以高枕无忧!因为用 SQL Profiler 追踪可知,它是在你设计的报表参数尾部,自动加上了一句:表格名.modifiedonutc>=''20140201 16:00:00'' and 表格名.modifiedonutc <= ''20140301 00:00:00''。注意表格名是带有Filtered前缀的,表明会被CRM进行权限管理。以后若对这些记录进行修改,修改的时间点又正好落在这个段内,那报表还是能出来记录的,所以才说是 “隐患” 啊!
第二个选项:“ 选定的记录 ”,则正常。因为它被自动加上了" tblName.主ID=N 'GUID' -- 用主ID做筛选,当然正确啦。
而第三个选项:“当前视图所有页面的全部记录”,则被蹊跷地加入了一句筛选:tblName.statecode = 0。尽管这个statecode字段,并没有被报表本身所使用到(这点像极了上面的所有记录modifiedonutc栏位),但是它们被加入的依据是什么呢?搞懂了这个,报表也就能 “ 有的放矢 ”了。
modifiedonutc 和 statecode 都是每个实体建立时,都会拥有的栏位。前者管修改时间,后者管当前状态。说穿了,其实它们就是当前视图的Where条件。报表只是照抄了这个条件,那么我们在报表中做一个检测,去探查报表到底被加上了什么,不就可以避开那些错的、然后“ 对症下药 ”了吗?
回顾一下CRM2011报表的基础知识:那些只能在窗口运行的报表,是需要统一成一种参数格式,即:“@CRMFiltered表格名 ”作为参数名称的。至于参数的默认值和可选值里,都是“ Select * From Filtered表格名”。
” 温习完Dynamics CRM2011,再说2013。我们再建立一个内部参数,比如叫@cWhere吧。其默认值和可选值都是“=Iif(Instr(Parameters!CRM_Filtered表格名.Value,"utc")=0 And Instr(Parameters!CRM_Filtered表格名.Value,"statecode")=0," Where 1=1 "," Where 1<0 ")”。意思很简单:如果包含了utc或者statecode关键字,那就说明是第一个或者是第三个选项,当然给它一个永远不会成立的条件(1<0)。反之亦然(给个永远成立的条件:1=1)。
再把这个参数加到原来报表数据集的属性中,一般数据集的语句会是:
Declare @sql as nVarchar(4000)
Set @sql = 'SELECT FO.* FROM (' + @CRM_Filtered表格名 + ') as FO'
exec(@sql)
只要在第二句的末尾,加上:+@cWhere 大功就此告成!
后记:
别看这里写得简单,其实这已经我发现的最快捷径了。而且很好地保持了对2011的兼容性。
回忆起自己曾经尝试过的各种方法,那所耗掉的时间、所走的弯路,都是以下午计算啊!
比如,我曾经想,再建立一个辅助数据集,专门捕捉主数据集的记录个数:Select Distinct 主ID From Filtered表格名。如果这个辅数据集的@@Coun大于1,那就说明有多个主ID,也就是第一或者第三选项,那就让Tablix控件不显示。结果发现:这要用到 First() 等聚合函数、或者 RowNumber() 等杂项函数,运行时都不会被允许。
我还想过把整个@sql字段做Replace,即发现utc或statecode,就强行替换成空字符串。但发现这要在前端的报表定义语句,和后端的服务器语句之间切换来切换去,不是一般的麻烦。俺要改的报表又那么多....... 于是也只有放弃。
还曾经想着为了节省一个参数,就把 @cWhere 的功能,直接赋予 Tablix 的 Visible 或者 Filter 属性,结果这些函数在运行时统统也都报错。
综上所述,把准备工作做好后,直接对@cSQL语句动手,才是效率最高、最好懂、最有兼容性的方式。