使用Java API更新Crystal Reports

2020-09-10 09:56发布

点击此处---> 群内免费提供SAP练习系统(在群公告中)加入QQ群:457200227(SAP S4 HANA技术交流) 群内免费提供SAP练习系统(在群公告中)我一直在努力找出与各种Cryst...

         点击此处--->   EasySAP.com群内免费提供SAP练习系统(在群公告中)

加入QQ群:457200227(SAP S4 HANA技术交流) 群内免费提供SAP练习系统(在群公告中)


我一直在努力找出与各种Crystal Reports Java API所出现的不一致之处,并且在线帮助在寻找明确的解决方案方面相当模糊或不确定。 所以我想在这里问

请原谅,但要有一些背景知识……

我们的BOE 4.1 FP11服务器管理着约1500个左右的Crystal Reports,这些服务器针对我们的数据仓库。 由于正在进行仓库迁移到另一个供应商的平台,我们需要使用新的DSN更新这些报告,并且一部分报告将需要对其CommandTable对象进行一些SQL调整。 我正在尝试使用您的Java SDK之一来自动执行此过程。 请记住,无论如何我都不是BOE或Crystal用户或专家,我只是一个在使用SDK和API进行集成/自动化方面具有丰富经验的编码人员。

仓库供应商正在协助我们进行此迁移,他们要求从受影响的报告中转储所有自定义SQL(CommandTable.CommandText),以便他们可以对其进行检查并进行任何必需的更改。 我能够使用Crystal Reports for Eclipse(CR4E)API并直接在BOE文件系统上的.RPT文件之后轻松提供此功能。 即使这些是托管报告,也可以直接查询RPT文件。 我能够遍历文件系统以收集所有RPT文件,识别受影响的文件,并将包括CommandTable自定义SQL在内的报告元数据转储到提供给供应商的文本文件中。 到目前为止很好...

然后,供应商获取了此文本转储,并对其运行了工具以验证SQL并进行任何必需的更新。 他们向我们返回了更新的文件,现在我应该阅读这些文件,然后为这些报告更新DSN和修改后的SQL(CommantTable.CommandText)。

所以现在我们可以解决当前的困境:

我意识到CR4E SDK不适用于托管报告,但是我认为我已经抓取了其中一些托管RPT并将其作为本地副本删除,只是为了尝试使用更新代码,然后再尝试远程访问它们 通过托管的API。 我编写了一些非常简单的代码来计算更新动态,并且代码运行无误。 但是,当我调用ReportClientDocument.save()和.close()时,实际上没有任何更改被写回到文件中。 文件时间戳确实发生更改,表明文件已更新,但是文件大小相同,表明内容未更改。 我还尝试了使用不同文件名的ReportClientDocument.saveAs()-也写入了新文件,但再次与原始文件相同。

在逐步调试时,我可以在内存的CommandTable.CommandText字段中看到SQL更改,因此我知道CommandTable.setCommandText()调用正在工作。 但是为什么它从不进入目标文件?该文件不是只读的,因为我检查ReportClientDocument.isReadOnly()会返回false。 再一次,saveAs()写入一个文件,但包含原始内容。

是因为CR4E SDK知道这实际上是一个托管报告并且拒绝更改它吗? 如果是这样,为什么不抛出异常而不是默默地失败并暗示成功?我希望保持这种过程既快速,简单又可行,因此首先尝试使用与我相同的CR4E API。 我还提供了RAS SDK和BIP41 SDK,可以尝试通过托管API,大约一半的人希望我必须这样做以确保正确更新元数据数据库。 但是在我再次追尾之前,我有什么想念的地方吗?

下面的代码片段显示了一个非常快速且肮脏的示例,该示例使用具有3个CommandTable对象的本地硬编码报告文件,并且我尝试将第一个CommandTable.CommandText更改为虚拟SQL字符串。

 File rptFile = new File(" test/update_test1.rpt");
 ReportClientDocument clientDoc = ReportClientDocument.openReport(rptFile);
 如果(clientDoc.isReadOnly())
   抛出新的异常("报告是只读的!");
 IDatabase数据库= clientDoc.getDatabaseController()。getDatabase();
 字符串cmdName = null;
 CommandTable cmdTable = null;
 对于(ITable t:database.getTables())
 {
   if(t instanceof CommandTable)
   {
     cmdTable =(CommandTable)t;
     cmdName = cmdTable.getAlias();
     cmdTable.setCommandText(" SELECT * FROM TEST_CRYSTAL_UPDATE;");
     打破;
   }
 }
 clientDoc.save();
 System.out.println("更改了命令'"的SQL'+报告中的cmdName +"'+ clientDoc.displayName()+"'));
 clientDoc.close();
 

上面的代码中没有显示它,但是周围有一个try/catch块可以捕获所有异常。 不会抛出任何异常,并且文件时间戳会再次更新,就像写了 something 。 这是调试器的前后截图,显示.setCommandText()调用实际上更改了CommandTable对象中的SQL。

之前:

之后:

感谢您提供的任何帮助。 我想接下来我将开始深入研究RAS API ...

(10.0 kB)
8条回答
Violet凡
2020-09-10 10:34

我还尝试了将SQL实际更改为某些实际SQL的尝试, 现有环境。 行为相同。 没有错误报告,一切看起来都执行正常。 该报告已保存到磁盘,但使用了旧的SQL。

是进行更新所需的verifyTableConnectivity()还是仅仅是最佳实践? 如果这只是最佳实践,我知道为什么要进行单个报告更新,但是鉴于我要更新的批处理量(〜1500个报告),似乎不可能为每个报告都执行此操作。

无论如何,我在设置新SQL之后并保存之前添加了以下行:

如果(!clientDoc.getDatabaseController()。verifyTableConnectivity(cmdTable))
         抛出新的异常("表验证失败!");
 

该调用返回false,从而引发我的异常,但不返回错误代码或任何指示实际失败的内容。 当我只是随机选择这份报告进行测试时,我不知道为什么。 我认为这是由于数据库凭证具有某种原因,可能是密码过期或ID无效,或者期望我已经对报告进行了身份验证。 鉴于手头的任务,这似乎都不是可行的方法。 我只需要能够更改DSN以及可能的SQL,保存它,并让芯片落在某人尝试下一次运行该报告时的位置。

还有另一种方法来执行这种类型的批处理CR更新吗? 我已经将头撞在这堵墙上已有一段时间了,我需要尽快向仓库迁移团队交付一些东西。

一周热门 更多>