我是Crystal报道的新手,应用程序在ASP.net 3.5和MySQL 5.1中,将在日期和日期之间开发报告,报告的第一页显示良好,但当我尝试在另一页面上导航时我在打印和导出操作中遇到了与缺少参数值相同的错误 提前致谢
public partial class BookingStatement:System.Web.UI.Page {
//DAL is my Data Access Layer Class
// Book is ReportClass
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;
}
}
答案 0 :(得分:1)
问题似乎发生是因为Crystal Reports在发生回发时不会在其ViewState中保留其参数值。因此,当CrystalReportViewer
尝试再次加载ReportClass
作为ReportSource
时,参数值将不再存在。
我们成功使用的解决方案是在设置了所有参数值后将ReportClass
(即您的Crystal Report对象)保存到Session
中。然后在CrystalReportViewer
事件中的每个PostBack上将其加载到Page_Init
。一个例子:
// 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);
}
}
}
通过这种方式,您可以确保任何用户在任何给定时间内只在内存中有一个报告。
如果记忆是一个问题,即使采用这种方法,另一种选择可能是将个别变量值存储在Session
&amp;然后在Page_Init
&amp;中实例化一个新报告。在将其分配给CrystalReportViewer.ReportSource
之前,使用保存的值重新填充它。但在我们的案例中,有40位用户每天提取50多种不同的报告,这种ReportClass
对象的存储实现了自从应用程序于3年前上线以来,我们没有遇到任何内存问题。我仍然建议做适当的负载测试和在将此解决方案推向生产之前进行监控,因为结果可能会因具体实施而异。
答案 1 :(得分:0)
当我为Crystal报表编写SQL时,SQL中的参数代码如下:
--Date Range
(
(table.datetime >= '{?Start Date}')
and table.datetime < '{?End Date}')
)
--Location
('{?Facility}'= 'All' OR '{?Facility}' = table.location))
当然,您总是可以选择将参数直接编程到Crystal中。这种方法效率不高,但有时更容易。