C# Crystal报告:缺少参数值

C# Crystal报告:缺少参数值,c#,asp.net,mysql,C#,Asp.net,Mysql,我是Crystal report的新手,应用程序在ASP.net 3.5和MySQL 5.1中,将在日期之间(如从日期到日期)开发报表,报表的第一页显示良好,但当我尝试在另一页上导航时,我遇到了错误,如缺少参数值在打印和导出操作中遇到的相同错误 提前谢谢 公共部分类预订状态:System.Web.UI.Page { //这本书在课堂上很受欢迎 DAL obj = new DAL(); Book bkStmt = new Book(); protected void Page_Load(objec

我是Crystal report的新手,应用程序在ASP.net 3.5和MySQL 5.1中,将在日期之间(如从日期到日期)开发报表,报表的第一页显示良好,但当我尝试在另一页上导航时,我遇到了错误,如缺少参数值在打印和导出操作中遇到的相同错误 提前谢谢

公共部分类预订状态:System.Web.UI.Page {

//这本书在课堂上很受欢迎

DAL obj = new DAL();
Book bkStmt = new Book();
protected void Page_Load(object sender, EventArgs e)
{

    if (!IsPostBack)
    {
       //crvBooking is Crystal Report Viewer
       //reportFill method is to fill Report 

        reportFill();
        crvBooking.EnableViewState = true;
        crvBooking.EnableParameterPrompt = false;
    }


   /* Also try reportFill() out side !IsPostBack but didn't work */


    //Check if the parmeters have been shown.
 /*   if ((ViewState["ParametersShown"] != null) && (ViewState["ParametersShown"].ToString() == "True"))
    {
        bkStmt.SetParameterValue(0, "20/04/2010");
        bkStmt.SetParameterValue(1, "20/04/2010");
    }*/

}


protected void crvBooking_navigate(object sender, CrystalDecisions.Web.NavigateEventArgs e)
{
   // reportFill();
}

protected void reportFill()
{

    //bkStmt.rpt is Report file
    //bookingstatment is View
    //bkStmt is ReportClass object of Book

    string rptPath = "bkStmt.rpt";

    string query = "select * from bookingstatment";


    crvBooking.RefreshReport();
    crvBooking.Height = 600;
    crvBooking.Width = 900;



    bkStmt.ResourceName = rptPath;


    String dtFrm = bkStmt.ParameterFields[0].CurrentValues.ToString();

    obj.SetCommandType(CommandType.Text);
    obj.CommText = query;
    DataTable dtst = obj.GetDataTable();

    crvBooking.ParameterFieldInfo.Clear();



    ParameterDiscreteValue discretevalue = new ParameterDiscreteValue();
    discretevalue.Value = "20/04/2010"; // Assign parameter
    ParameterValues values = new ParameterValues();
    values.Add(discretevalue);

    bkStmt.SetDataSource(dtst);

    ViewState["ParametersShown"] = "True";
    crvBooking.EnableViewState = true;

    bkStmt.DataDefinition.ParameterFields[0].ApplyCurrentValues(values);
    bkStmt.DataDefinition.ParameterFields[1].ApplyCurrentValues(values);


    crvBooking.ReportSource = bkStmt;
}

}

当我为Crystal报表编写SQL时,SQL中参数的代码如下所示:

--Date Range
(
(table.datetime >= '{?Start Date}')
and table.datetime < '{?End Date}')
)

--Location
('{?Facility}'= 'All' OR '{?Facility}' = table.location))
——日期范围
(
(table.datetime>='{?开始日期}')
和table.datetime<'{?结束日期}')
)
--位置
(“{Facility}”='All'或“{Facility}'=table.location))

当然,您始终可以选择将参数直接编程到Crystal中。这种方法效率不高,但有时更容易。

当我为Crystal报表编写SQL时,SQL中参数的代码如下所示:

--Date Range
(
(table.datetime >= '{?Start Date}')
and table.datetime < '{?End Date}')
)

--Location
('{?Facility}'= 'All' OR '{?Facility}' = table.location))
——日期范围
(
(table.datetime>='{?开始日期}')
和table.datetime<'{?结束日期}')
)
--位置
(“{Facility}”='All'或“{Facility}'=table.location))

当然,您始终可以选择将参数直接编程到Crystal中。这种方法效率不高,但有时更简单。

问题似乎发生了,因为Crystal Reports在回发时不会在其ViewState中保留其参数值。因此,当
CrystalReportViewer
再次尝试加载用作其
ReportSource
ReportClass
时,参数值不再存在

我们成功使用的一个解决方案是,在设置了
报告类的所有参数值后,将
报告类
(即您的Crystal Report对象)保存到
会话
,然后在
页面初始化
事件中每次回发时将其加载到
CrystalReportViewer
。例如:

// instantiate the Crystal Report
var report = new DeliveryLabelsSingle();

// set the required parameters
report.DataSourceConnections[0].SetConnection("DBServer", "DatabaseName", "DatabaseUser", "DatabasePassword");
report.SetParameterValue("@Param1", "val1");
report.SetParameterValue("@Param2", "val2");

// set the data source of the viewer
crvLabels.ReportSource = report;

// save the report object in session for postback binding
Session["rptDeliveryLabels"] = report;
然后,页面的Page_Init事件如下所示:

protected void Page_Init(object sender, EventArgs e)
{
    if (IsPostBack) {
        if (Session["rptDeliveryLabels"] != null) {
            // cast the report from object to ReportClass so it can be set as the CrystalReportViewer ReportSource
            // (All Crystal Reports inherit from ReportClass, so it serves as an acceptable data type through polymorphism)
            crvLabels.ReportSource = (ReportClass)Session["rptDeliveryLabels"];
        }
    }
}
通过这种方式,我们将始终为查看器设置一个报告对象,该对象已使用适当的值初始化

这种方法需要记住的一点是,您可能会非常快地填满服务器内存,特别是当您有许多用户生成许多不同的报告时。所以一些家政工作是有序的。我们通过为包含报表的所有ASP.NET页面实现基类(以及该报表加载代码)实现了这一点。在这个基类中,我们将所有可能的
Session
变量都设置为null。像这样:

// class definition for ASP.NET page containing CrystalReportViewer & associated report(s)
public partial class DeliveryLabelPrint : BaseReport
那么BaseReport的定义如下:

public class BaseReport : System.Web.UI.Page
{
    protected override void OnLoad(EventArgs e)
    {
        if (!IsPostBack) {
            for (var i = 0; i < Session.Count; i++) {
                var sv = Session[i];
                // if this session variable contains a Crystal Report, destroy it
                if (sv is ReportClass) {
                    sv = null;
                }
            }

            base.OnLoad(e);
        }
    }
}
公共类BaseReport:System.Web.UI.Page
{
受保护的覆盖无效加载(事件参数e)
{
如果(!IsPostBack){
对于(var i=0;i
通过这种方式,您可以确保任何用户在任何给定时间的内存中只有一个报告


如果内存是一个问题,即使采用这种方法,另一种方法可能是在
会话中存储单个变量值,然后在
页面初始化中实例化一个新报告,并在将其分配给
CrystalReportViewer.ReportSource
之前用保存的值重新填充它。但是在我们的例子中,40个用户每天拉取50多个不同的报告,这种存储
ReportClass
对象的实现以及随之而来的管理,自从应用程序3年前上线以来,我们没有遇到任何内存问题。我仍然建议在将此解决方案推向生产之前进行适当的负载测试和监控,因为结果可能会因具体实现而有所不同。

问题似乎发生了,因为Crystal Reports在回发时不会将其参数值保留在其ViewState中。因此,当
CrystalReportViewer
再次尝试加载用作其
ReportSource
ReportClass
时,参数值不再存在

我们成功使用的一个解决方案是,在设置了
报告类的所有参数值后,将
报告类
(即您的Crystal Report对象)保存到
会话
,然后在
页面初始化
事件中每次回发时将其加载到
CrystalReportViewer
。例如:

// instantiate the Crystal Report
var report = new DeliveryLabelsSingle();

// set the required parameters
report.DataSourceConnections[0].SetConnection("DBServer", "DatabaseName", "DatabaseUser", "DatabasePassword");
report.SetParameterValue("@Param1", "val1");
report.SetParameterValue("@Param2", "val2");

// set the data source of the viewer
crvLabels.ReportSource = report;

// save the report object in session for postback binding
Session["rptDeliveryLabels"] = report;
然后,页面的Page_Init事件如下所示:

protected void Page_Init(object sender, EventArgs e)
{
    if (IsPostBack) {
        if (Session["rptDeliveryLabels"] != null) {
            // cast the report from object to ReportClass so it can be set as the CrystalReportViewer ReportSource
            // (All Crystal Reports inherit from ReportClass, so it serves as an acceptable data type through polymorphism)
            crvLabels.ReportSource = (ReportClass)Session["rptDeliveryLabels"];
        }
    }
}
通过这种方式,我们将始终为查看器设置一个报告对象,该对象已使用适当的值初始化

这种方法需要记住的一点是,您可能会非常快地填满服务器内存,特别是当您有许多用户生成许多不同的报告时。所以一些家政工作是有序的。我们通过为包含报表的所有ASP.NET页面实现基类(以及该报表加载代码)实现了这一点。在这个基类中,我们将所有可能的
Session
变量都设置为null。像这样:

// class definition for ASP.NET page containing CrystalReportViewer & associated report(s)
public partial class DeliveryLabelPrint : BaseReport
那么BaseReport的定义如下:

public class BaseReport : System.Web.UI.Page
{
    protected override void OnLoad(EventArgs e)
    {
        if (!IsPostBack) {
            for (var i = 0; i < Session.Count; i++) {
                var sv = Session[i];
                // if this session variable contains a Crystal Report, destroy it
                if (sv is ReportClass) {
                    sv = null;
                }
            }

            base.OnLoad(e);
        }
    }
}
公共类BaseReport:System.Web.UI.Page
{
受保护的覆盖无效加载(事件参数e)
{
如果(!IsPostBack){
对于(var i=0;i
通过这种方式,您可以确保任何用户在任何给定时间的内存中只有一个报告

如果内存是c