解惑

解己之惑,解人之惑

标签:Crystal Report

问题多多

刚刚说到我们要迁移数据库,所以我就试验了下使用ODBC连接数据库,配置完成以后,可以连接,但是在选择表的时候有问题,里面只列出了oracle的一些包,没有列出任何一个表或者视图,加了一个Command,随便写了一个SQL,从我们的一个表里面取全部数据(select * from tablename),可以正常过,到了报表设计器里面可以看到Command列出的字段确实是SQL选择的那个表的字段,但是把字段添加到报表中,然后预览的时候设计器就死掉自动退出了。

打开Business View Manager,添加数据源,从那个里面可以正常的列出数据库的表和视图。

看来Crystal Report的代码重用没有做好,一些地方可以正常工作,但是另外的地方就不能正常工作了。

更新:
找到解决方案了,选择那个ODBC连接,右键打开菜单选择Options,在Data Explorer中把Stored procedures去掉就可以了。

Command中不能添加多值的参数

有一个报表要进行统计,但是按照原来的做法都不太好实现,后来没有办法使用Command来获取数据(说白了就是直接写SQL),但是在Command的界面里面添加的参数的值不能是多选的,但是有一个解决方法就是把参数转换为一个字符串。
一个例子就是Command里面使用到多值参数的时候,就创建一个字符串参数,然后写SQL的时候就设置为:
xxx in ({?parameter})
假设外面的真正的参数是params,那么可以写一个Formula把param转换为那个字符串:
Local StringVar result:="";
Local NumberVar i;
for i:=1 to count({?params}) do (
if i<count({?params}) then
result := result & toText({?params}[i],"0") & ","
else
result := result & toText({?params}[i],"0")
);
result

这样就可以解决Command里面不能使用多值参数的问题了。

痛苦的Crystal Report

这个阶段的任务包括修改一些Crystal Report,从我最开始研究Crystal Report时我就很讨厌做这个,因为没有什么共享的机制,各种格式要在创建报表的时候一次一次的重复,各种字段的显示格式也是,而我最讨厌的就是做重复的工作,而且特别讨厌做格式化的工作。
另外,你永远工作在一个沙箱中,很多时候你平时编程中使用到的东西在创建报表的时候就不能用了。
当然,一个可能的原因是我对这个东西并不是很熟悉,另外我对写SQL也不是很在行,所以在创建复杂业务逻辑的报表的时候问题就更加的严重。
但愿写报表的日子早点结束。

动态排序

这个是刚刚提出的一个需求,我开始以为不能实现,但是是可以的,虽然比较麻烦。
Crystal Report Designer中可以选择用来排序的字段可以是数据库字段,也可以是Fomula字段,不能是参数字段,所以一个可行的方法就是创建一个Fomula字段,这个Fomula的任务很简单,就是根据参数的值选择字段:

if {?sortcolumn} =’ID’ then totext({DEVICEGROUPCONFIG.DG_ID},’0000000000000′)
else
{DEVICEGROUPCONFIG.DG_NAME}

需要注意的就是那个totext的使用,Fomula是没有类型的,但是要求其返回值的类型要一致,不能一会是字符串一会是数字,所以我使用了totext把数字转换为字符串,如果有日期类型,也要类似的实现。

取得参数的缺省值列表

我们要求报表可以根据用户的选择来动态进行排序,但是每个报表所显示的列肯定不一样,所以每个报表在实现这个功能的时候,参数提示的时候必然要提供可选的值,到了Java里面,如何从Crystal Report Server上读取这些信息呢?
    public static ValueObjList getReportParameters(int reportID) throws Exception
    {
        String query = "Select SI_PROCESSINFO.SI_PROMPTS From CI_INFOOBJECTS Where si_progid = ‘crystalenterprise.report’ and SI_ID = "
                + reportID;
        IInfoObjects results = query(query);
        ValueObjList result = new ValueObjList();
        if (results == null)
        {
            return result;
        }
        IInfoObject report = (IInfoObject) results.get(0);
        List allParameters = ((IReport) report).getReportParameters();
        IReportParameter reportParameter = null;
        //Fix THRX2282, this maybe crystal report’s bug
        Set parameterNames = new HashSet();
        for (int j = 0; j < allParameters.size(); j++)
        {
            reportParameter = (IReportParameter) allParameters.get(j);
            if (!reportParameter.isInUse())
            {
                continue;
            }
            CrystalReportParamConfigValueObj paramvo = new CrystalReportParamConfigValueObj();
            String name = reportParameter.getParameterName();
            if (name.equals("sortcolumn"))
            {
                IReportParameterValues defaultValues = reportParameter.getDefaultValues();
                Values values = defaultValues.getValues(reportParameter.getValueType());
                for (int m = 0; m < values.size(); m++)
                {
                    ParameterFieldDiscreteValue value = (ParameterFieldDiscreteValue) values.get(m);
                    System.out.println(value.displayText(Locale.ENGLISH));
                }
            }
            if (parameterNames.contains(name))
            {
                continue;
            }
            else
            {
                parameterNames.add(name);
                paramvo.setAttribute(CrystalReportParamConfigAttributes.name, name);
                paramvo.setAttribute(CrystalReportParamConfigAttributes.type, new Integer(reportParameter
                        .getValueType()));
                result.add(paramvo);
            }
        }
        return result;

    }

注意蓝色的代码,特别是defaultValues.getValues(reportParameter.getValueType()),这样我们就可以从服务器上读取到报表随带的参数值列表。

Crystal Report的几个问题

我们美国那边做Crystal Report的人走了,所以这个版本中,Crystal Report相关的一些bug就都由我来修改了,很痛苦
在这个过程中深切的感受到Crystal Report的一些问题:

  • 没有比较好的重用机制,特别是一些公式或者Formula以及显示内容的格式,而模版功能还不够强大
  • 子报表不能再包含子报表,这个也很痛苦,在创建复杂的报表内容的时候尤其痛苦,只能通过修改视图解决
  • 从数据库取数据的时候默认是大小写不敏感的
  • RPT文件是二进制格式,不利于版本比较
  • 保存数据库结构信息,例如表的完整定义,如果更新了数据库,那么报表可能不能运行,但是实际上修改对报表没有影响(例如增加了一个表字段)

以后要搞Crystal Report?

公司的一个兼职搞Crystal Report的同事要离职,但是我们最近几个要打的patch中和Crystal Report相关的问题最多,这边好像我是最熟悉的,领导找我谈话问能不能做,我说不一定,一些比较简单的可能没有问题,复杂的不一定。其实我是很不愿意搞Report的,不为别的,就是感觉做报表很烦琐,特别是用它的GUI工具,为了控制某种效果,要点击那些Formula按钮并写些脚步,要完成一个报表可能要重复这个过程十几次几十次,可能还要建几个子报表。不过现在可能避免不了,先看看能不能把这次的紧急情况应付过去把。

PS:如果有熟悉Crystal Report的朋友可以和我联系,我们要兼职或者全职搞Crystal Report的人。

查询报表执行的最新状态

我们的系统和水晶报表集成起来了,而且一个报表可以同时运行多次,我们要监控每次的执行结果。查询语句如下:
Select TOP 1 *  From CI_INFOOBJECTS Where SI_INSTANCE_OBJECT=1 AND SI_PARENTID="
        + reportId
        + " and AR_INSTANCE_ID= "
        + instanceId
        + " and AR_EXECUTE_ID= " + executeId + " Order by SI_ID desc";
其 中reportId是报表的那个ID了,AR_INSTANCE_ID是自定义的属性,用来跟踪每次的执行,我们的系统中增加了和CR SERVER中类似的概念instance,就是可以使用不同的参数设置运行同一个报表,而每一个instance又可以同时运行多次,所以又增加了一个 EXECUTE_ID,可以跟踪每次的执行了。
这个查询有个问题,就是如果报表没有运行完,那么是查询不到当前的状态的,后来发现是SI_INSTANCE_OBJECT=1的问题,去掉那个条件就可以了。可能是报表运行成功或者失败才会生成或者设置那个字段。

© 2019 解惑

本主题由Anders Noren提供向上 ↑