Crystal Reports for Visual Studio会使用子报表链接抛出“缺少参数值”异常

时间:2013-06-27 14:55:36

标签: c# visual-studio-2010 crystal-reports

我在C#中创建了一个代码,用于Crystal Reports for Visual Studio,版本13.0.5.891和Visual Studio 2010.它基本上接收报告文件的名称和带有要传递给.rpt的参数的Dictionary。文件并在浏览器窗口中显示生成的报告。它是ASP.NET MVC 3应用程序的一部分。

以下是代码:

    /// <summary>
    /// Shows the report
    /// </summary>
    /// <param name="reportName">Report name</param>
    /// <param name="parameters">Dictionary containing the pairs "key/value" of each parameter.</param>
    public static void ShowReport(string reportName, Dictionary<string, object> parameters)
    {
        if (!string.IsNullOrEmpty(reportName))
        {
            ReportDocument rd = new ReportDocument();
            CrystalDecisions.Shared.ConnectionInfo connection = new CrystalDecisions.Shared.ConnectionInfo();
            TableLogOnInfo tableLogin = new TableLogOnInfo();

            reportName += "_o.rpt"; // all .rpt files we use here have names ending with "_o"

            //Find and load the report.
            string strRptPath = Path.Combine(System.Web.HttpContext.Current.Server.MapPath("~/"), "Reports", reportName);
            rd.Load(strRptPath);

            //Get the application connection string to build de connection info object
            OracleConnectionStringBuilder builder = new OracleConnectionStringBuilder(ConnectionString.providerConnectionString());

            CrystalDecisions.ReportAppServer.DataDefModel.Table boTable =
                new CrystalDecisions.ReportAppServer.DataDefModel.Table();

            //boMainPropertyBag: These hold the attributes of the tables ConnectionInfo object
            PropertyBag boMainPropertyBag = new PropertyBag();
            //boInnerPropertyBag: These hold the attributes for the QE_LogonProperties
            //In the main property bag (boMainPropertyBag)
            PropertyBag boInnerPropertyBag = new PropertyBag();

            //Set the attributes for the boInnerPropertyBag
            boInnerPropertyBag.Add("Server", builder.DataSource);
            boInnerPropertyBag.Add("Trusted_Connection", "False");

            //Set the attributes for the boMainPropertyBag
            boMainPropertyBag.Add("Database DLL", "crdb_oracle.dll");
            boMainPropertyBag.Add("QE_DatabaseName", "");
            boMainPropertyBag.Add("QE_DatabaseType", "Oracle Server");
            //Add the QE_LogonProperties we set in the boInnerPropertyBag Object
            boMainPropertyBag.Add("QE_LogonProperties", boInnerPropertyBag);
            boMainPropertyBag.Add("QE_ServerDescription", "XE");
            boMainPropertyBag.Add("QE_SQLDB", "False");
            boMainPropertyBag.Add("SSO Enabled", "False");

            //Create a new ConnectionInfo object
            CrystalDecisions.ReportAppServer.DataDefModel.ConnectionInfo boConnectionInfo =
            new CrystalDecisions.ReportAppServer.DataDefModel.ConnectionInfo();
            //Pass the database properties to a connection info object
            boConnectionInfo.Attributes = boMainPropertyBag;
            //Set the connection kind
            boConnectionInfo.Kind = CrConnectionInfoKindEnum.crConnectionInfoKindCRQE;
            //**EDIT** Set the User Name and Password if required.
            boConnectionInfo.UserName = builder.UserID;
            boConnectionInfo.Password = builder.Password;
            //Pass the connection information to the table
            boTable.ConnectionInfo = boConnectionInfo;

            //Get the Database Tables Collection for your report
            CrystalDecisions.ReportAppServer.DataDefModel.Tables boTables;
            boTables = rd.ReportClientDocument.DatabaseController.Database.Tables;

            //For each table in the report:
            // - Set the Table Name properties.
            // - Set the table location in the report to use the new modified table
            int numtable = 0;
            foreach (CrystalDecisions.ReportAppServer.DataDefModel.Table table in boTables)
            {
                boTable.Name = table.Name;
                boTable.QualifiedName = builder.UserID + "." + table.Name;
                boTable.Alias = table.Name;

                rd.ReportClientDocument.DatabaseController.SetTableLocation(boTables[numtable], boTable);
                numtable++;
            }

            //Code for subreports.
            CrystalDecisions.ReportAppServer.Controllers.DatabaseController boDatabaseCtl = null;
            CrystalDecisions.ReportAppServer.DataDefModel.Database boDatabase = null;
            CrystalDecisions.ReportAppServer.ClientDoc.ISCDReportClientDocument boClientDoc = rd.ReportClientDocument;
            Strings subreportNames=boClientDoc.SubreportController.GetSubreportNames();
            for (int i = 0; i < subreportNames.Count; i++)
            {
                boDatabaseCtl = boClientDoc.SubreportController.GetSubreport(subreportNames[i]).DatabaseController;
                boDatabase = boDatabaseCtl.Database;
                boTables = boDatabase.Tables;

                numtable = 0;
                foreach (CrystalDecisions.ReportAppServer.DataDefModel.Table t in boTables)
                {
                    boTable.Name = t.Name;
                    boTable.QualifiedName = builder.UserID + "." + t.Name;
                    boTable.Alias = t.Name;

                    boDatabaseCtl.SetTableLocation(boTables[numtable], boTable);
                    numtable++;
                }
            }

            //Verify the database after adding substituting the new table.
            //To ensure that the table updates properly when adding Command tables or Stored Procedures.
            rd.VerifyDatabase();

            //Set the parameters.
            foreach (string key in parameters.Keys)
            {
                object value;
                if (parameters.TryGetValue(key, out value))
                    rd.SetParameterValue(key, value);
            }

            //Export(show) the report.
            rd.ExportToHttpResponse(ExportFormatType.PortableDocFormat, System.Web.HttpContext.Current.Response, false, "crReport");
            rd.Close();
            rd.Dispose();
        }
        else
        {
            // throws an exception saying the .rpt name was not informed
            throw new Exception(Idiomas.Atual.NomeRelatórioNãoInformado);   
        }
    }

当我使用没有子报表的报表或具有从外部接收参数的子报表的报表时,它工作正常,但是当我使用带有子报表链接的子报表时,它会抛出异常并显示消息:缺少参数值。

对于我在这里缺少的东西有什么想法吗?任何帮助是极大的赞赏。谢谢!

2 个答案:

答案 0 :(得分:0)

我的情况与更高级别的细节不同,但我也是以编程方式分配参数。但是,我没有使用过SetParameterValue方法。

相反,我遍历数据定义中的参数集合:

int intNumParameters = reportDoc.ParameterFields.Count;

for(int i = 0; i < intNumParameters; i++)
{
    if(!reportDoc.DataDefinition.ParameterFields[i].IsLinked())
    {
        ParameterValues pVals = new ParameterValues();
        ParameterDiscreteValue pdv = new ParameterDiscreteValue();
        pdv.Value = objValue;
        pVals.Add(pdv);
        reportDoc.DataDefinition.ParameterFields[i].ApplyCurrentValues(pVals);
    }
}

reportDoc.Export(expOpts);

我想你可能会做很多内联,但这只是我自己使用的一个小工具的一部分。我可能应该获取DataDefinition.ParameterFields数组的长度而不是ReportDocument.ParameterFields数组,但它无论如何都可以。

我不知道这是否会对你有所帮助,因为我故意跳过看似问题根源的链接参数。但我至少可以提供另一种分配参数的方法。我会注意到,在我的大多数报告中我也有子报告,并且没有注意到在处理那些报告和没有报告的报告之间存在任何差异。

希望这会有所帮助:)

答案 1 :(得分:0)

如果您想继续使用SetParameterValue,请使用此

reportDocument.SetParameterValue(string name,object value,string subreportname)

将值传递给子报表中的指定参数。

希望帮助