使用Java API更新Crystal Reports

2020-09-10 09:56发布

         点击此处--->   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)

         点击此处--->   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条回答
haha101010
1楼-- · 2020-09-10 10:35

嗨,大卫,

这是因为CR在RPT文件中具有表和字段的副本,因此不能简单地将其更改为Select *。

它必须有效 该报告的SQL。

尝试添加WHERE子句,或在WHERE中对过滤器进行排序或更改以查看是否将其保存。

您还应该调用Database.Verify()这样 引擎可以验证您要设置的SQL。 请注意,如果字段信息与引擎不匹配,则只会从报告中删除字段。

Don

CPLASF-自律
2楼-- · 2020-09-10 10:37

Don,谢谢! 我会尝试的。 我想知道是否可能是这样的原因,但是我本来希望发生异常或抛出某些异常而不是无提示的失败。

一只江湖小虾
3楼-- · 2020-09-10 10:31

我尝试将现有的SQL重新格式化为 更新测试。 这样,我不会更改功能性SQL,只需更改其周围的空格即可。 除非CR足够聪明地认识到除了空格以外没有实质性变化并且忽略了它,否则它仍然无法正常工作。

此外,verify()也不是Database对象上的方法。 父DatabaseController对象上有一个verifyTableConnectivity()方法,该方法将ITable作为其参数。 不知道它是否可以与CommandTable一起使用,但是它的读取方式听起来好像可以验证与数据库的连接。 我宁愿避免这种情况,因为我不打算实时连接每个报告以更新它们。 这实际上是否只是更新报告文件的要求,还是我正确阅读了此文件?

Violet凡
4楼-- · 2020-09-10 10:34

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

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

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

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

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

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

闻人可可
5楼-- · 2020-09-10 10:39

啊哈,我想您可能一直在指 到ReportClientDocument.verifyDatabase()调用。

但是,与另一个调用具有相同的关注点,因为该调用还尝试连接到数据库并验证所有列。 我确实尝试了一下,但发现未找到JNDI名称(DSN)(这是事实,因为该测试文件所在的本地计算机中不存在该名称),这是事实。 它可以从托管RAS连接运行,但是我再次担心检查每个连接的开销。

吹牛啤
6楼-- · 2020-09-10 10:44

嗨,大卫,

首先要做的是首先在报告中进行所有这些操作。 打开设计器,打开您的报告之一,单击"数据库"菜单选项,然后单击"设置位置.....

选择客户端,填写登录信息,建立连接后,单击新数据源,然后单击旧数据源,然后单击"地图"按钮。 如果检测到任何字段类型映射问题,则会弹出一个Mapping UI,您需要单独映射该字段。

如果有子报表,请为列出的每个数据源设置位置。

现在单击"数据库...",然后单击"验证",这将使用选定的新表信息更新报告中的表信息。

现在在SDK中使用相同的工作流程。 在这种情况下,您将需要使用ReplaceConnection(OldConn,NewConn,DoNotVerify),以便即使使用Command,数据库信息也会得到相应更新。

这两个调用都是全局设置,因此它会验证集合中的每个表,因此您不必在循环中调用它来设置位置,一旦该循环完成,则仅进行一次调用,需要设置子报表连接 进行设置,然后拨打这些电话。

您实际上需要连接到数据库,您不能简单地调用它们并期望连接可以工作或验证表信息。

工作流程为:

打开报告

从Command对象获取SQL

更改SQL并将其设置为主报表和子报表

现在设置用于登录的连接属性。

如果reprot正在使用存储过程,则在登录之前首先设置SP的参数。

如果没有,则设置任何需要更改或未保存默认值的CR参数值

现在登录到数据库

在此处检查连接性,它实际上并不检查报告数据信息,只是测试连接信息是否有效。

根据需要设置参数默认值。

现在SetLocation()

现在验证数据库。

现在您可以保存报表,如果使用RAS更新任何部分,则在保存时需要使用ReportClientDocument对象。 它具有更新的信息。 ClientDocument可能无法保存某些基本属性,但是要更改数据库源,您需要使用RCD对象。

请注意,您使用的是Java还是.NET?

我没有任何示例,但是您可以在此处找到一些示例:

https://wiki.scn.sap.com/wiki/display/BOBJ/Java+%28Crystal+Reports+for+Eclipse%29+SDK

还有更多内容:

https://wiki.scn.sap.com/wiki/ display/BOBJ/Java + SDK

在.NET示例中,我编写了2个测试应用程序,其中一个用于参数/登录,另一个用于打印:

https: //wiki.scn.sap.com/wiki/display/BOBJ/Crystal+Reports%2C+Developer+for+Visual+Studio+Downloads

一周热门 更多>