如何在Crystal Report中获取使用的SQL SELECT语句?

7
我目前正在使用C#编写一个程序,允许我们的用户运行、查看和导出一批水晶报表。这些报表是使用Crystal Reports 2008 GUI制作的。其中一个主要原因是在将Crystal Report导出为PDF时,保留超链接。我的程序通过导出到rtf,然后将rtf转换为pdf来实现这一点。如果有人知道更简单的方法来保留超链接,请告诉我,但这不是我当前的问题。
我进行了很多测试,以优化我的程序,使导出所需的时间尽可能短。从我的测试中,查询数据,然后将结果集绑定到Crystal Report是迄今为止最快的方法。我的问题是,我无法在程序中硬编码查询,它们需要从Crystal Report本身检索。
在Crystal Reports 2008中,有一个名为“Show SQL Query”的选项,位于Database菜单下。这会打开一个窗口,显示给定报表所使用的SQL查询。这正是我需要从我的应用程序中获取的内容。我已经加载了一个水晶报表,然后在调试时遍历了ReportDocument对象,试图找到查询,但没有成功。
所以,我的问题是; 是否有任何可用的方法,允许我提取给定Crystal Report使用的查询?

如果报告中的表是“SQL 命令”,您仍然可以设置数据源吗?我认为表必须从数据集(XSD)创建才行。 - dotjoe
在我的测试中,Crystal Report使用“SQL Command”作为“Table”。我将报表绑定到了从数据库查询的数据集上,使用了与报表中“SQL Command”相同的SQL select,没有遇到任何问题。它完美地工作,并且比让报表自己刷新数据要快得多。 - Chronicide
有趣的是,我正在尝试将报告转换为PUSH模型,如果我只能传递数据源,那么我可能不需要这样做。我的报告都是存储过程,一些有参数,一些没有。 - dotjoe
进入调试器,找到 Table -> 非公共成员 -> RasTable -> 动态视图,你就能看到查询语句了。现在需要弄清楚如何在代码中访问它... - dotjoe
不错的发现,谢谢!我不确定是否可以通过代码找到它,因为它是非公开的。如果我添加一个监视器,我会得到以下路径。"((dynamic)((System.__ComObject)((new System.Linq.SystemCore_EnumerableDebugView(rd.Database.Tables.RasTables)).Items[0]))).CommandText"... 它在监视器中起作用,因为我可以在监视窗口中看到我的查询,但只是将其添加到我的代码中会引发大量错误。我会开始仔细研究它,看看能否分解它。再次感谢您指向正确的方向。 - Chronicide
1
你可能可以通过反射获取它...但是对于 COM 对象上的动态属性可能会变得相当困难。祝好运,如果你弄清楚了,请将其作为答案发布。 - dotjoe
2个回答

3
我知道这是一个很老的问题,但我想为那些需要3.5框架目标的人提供一种替代方案(动态不可用于3.5)。要使此解决方案有效,您需要以下参考资料。
using CrystalDecisions.ReportAppServer.DataDefModel;
using CrystalDecisions.CrystalReports.Engine;

然后只需使用以下方法访问ClientDoc接口,并返回命令文本字符串的列表。

    private static List<string> GetCommandText(CrystalDecisions.CrystalReports.Engine.ReportDocument report)
    {
        var rptClientDoc = report.ReportClientDocument;
        return rptClientDoc.DatabaseController.Database.Tables.OfType<CommandTable>()
              .Select(cmdTbl => cmdTbl.CommandText).ToList();
    }

1
我最喜欢这种方式,它更容易阅读和理解。 - tuespetre
@tuespetre 谢谢!很高兴能帮到你! - Evan L

2

好的,dotjoe给了我所有需要解决这个问题的提示。以下代码可用于从Crystal报表中提取命令文本。

public string getCommandText(ReportDocument rd)
{
    if (!rd.IsLoaded)
        throw new ArgumentException("Please ensure that the reportDocument has been loaded before being passed to getCommandText");
    PropertyInfo pi = rd.Database.Tables.GetType().GetProperty("RasTables", BindingFlags.NonPublic | BindingFlags.Instance);
    return ((dynamic)pi.GetValue(rd.Database.Tables, pi.GetIndexParameters()))[0].CommandText;
}

虽然看起来有些混乱,但当你开始研究它时,它就有点意义了。基本上,它使用反射来获取CommandText属性的值,并加入一些动态内容以处理ReportDocument中的动态属性。

这个代码段可以帮助我提取命令文本,但我还没有时间对其进行任何测试。我相信在我有时间工作后,我会进行一些微调。我不知道不使用“SQL Commands”报表会发生什么情况。在我进一步测试之后,我会发布评论。

  • Scott

P.S. 这需要引用标准的反射/动态库,以及以下Crystal Report库:

crystaldecisions.reportappserver.datadefmodel

crystaldecisions.crystalreports.engine

crystaldecisions.shared


我想要替换参数的SQL命令,使用给定的代码我可以获得SQL命令,但是参数没有用提供的值替换。如何获取最终的SQL语句?并且我能否使用ReportDocument在IEnumerable集合或dataTable中获取查询的DataSet? - zeppelin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接