2010-04-27 154 views
1

我是Crystal報告的新手,應用程序在ASP.net 3.5和MySQL 5.1中,將開發日期之間的報告,比如從日期到時間,報告的第一頁顯示不錯,但是當我嘗試另一頁我得到了像缺少參數誤差值同樣的錯誤,我在打印了和導出操作提前 由於在導航Crystal Report:缺少參數值

公共部分類BookingStatement:System.Web.UI.Page {

//DAL is my Data Access Layer Class 

// Book是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

當我寫SQL對於Crystal報表,在SQL參數的代碼是這樣的:

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

--Location 
('{?Facility}'= 'All' OR '{?Facility}' = table.location)) 

當然,你總是有編程的選項直接進入Crystal的參數。這種方法效率不高,但有時更容易。

1

問題似乎發生是因爲Crystal Reports在回發發生時未在其ViewState中保留其參數值。因此,當CrystalReportViewer嘗試加載ReportClass時,它再次用作其ReportSource,參數值不再存在。

,我們已經成功地使用一種解決方案是保存ReportClass(即水晶報表對象)到Session其所有參數值已設置&之後再根據在Page_Init事件每次回發此加載到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); 
     } 
    } 
} 

通過這種方式,可以確保任何用戶永遠只能在任何給定的時間內存中的一個報告。

如果記憶是一個問題,即使有這樣的做法,另一種可能是單獨的變量值存儲在Session &到那麼Page_Init &實例化一個新的報告將其分配給CrystalReportViewer.ReportSource之前保存的值重新填充它。但在我們的例子中,有40個用戶每天抽出50多個不同的報告,這個實現存儲ReportClass對象&附帶的內務管理,我們沒有遇到任何內存問題,因爲該應用程序在3年前上線。在將此解決方案投入生產之前,我仍然會建議您進行適當的負載測試,因爲結果可能會因具體實施情況而有所不同。