Crystal 当我向报表添加参数时,报表没有选择任何记录

Crystal Reports not selecting any records when I add a parameter to the report

我在 Visual Studio 2010 年内使用 Crystal 报告 ASP.NET。

我有一个从数据库中提取数据的数据集,它似乎可以很好地加载到报表中。当我在浏览器中查看报告时,所有记录都正确加载。

我必须添加一个参数供用户输入,以便过滤掉报告中的条目。问题是,当我 添加 任何类型的参数到报表时,查看器找不到任何记录。这是 BEFORE 我使用选择向导做任何事情。

我添加了一个仅包含数字 1、2 和 3 的下拉列表参数。如果选择专家中没有任何内容,这应该不会有任何影响。但无论出于何种原因,当它出现在报告中时,不会选择任何记录。一旦我删除参数,它就会再次起作用。

我正在通过字段资源管理器添加参数及其值(如果有影响的话)。

奇怪的是,当我让报表直接从数据库中提取数据而不是先创建数据集时,实现工作正常。我不能使用这个实现的原因是它一直在询问数据库登录信息。即使我预先定义了信息。我切换到数据集,这样我就可以避免登录提示。

我认为我的 DataSet 实现一定有问题。相关代码在这里:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using CrystalDecisions.CrystalReports.Engine;
using CrystalDecisions.Shared;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Data;


public partial class reportPage : System.Web.UI.Page
{

    private ReportDocument rpt;
    private string mapPath;

    protected void Page_Load(object sender, EventArgs e)
    {

        if (!Page.IsPostBack) // If the page is loaded for the first time
        {

            mapPath = "CrystalReport1.rpt";
            ConfigureCrystalReport();

        }

    }

    private void ConfigureCrystalReport() // Creates the instance of the report file and binds it to the viewer on the page
    {

        myDataSet ds = new myDataSet();

        myDataSetTableAdapters.myTableTableAdapter dsTA = new myDataSetTableAdapters.myTableTableAdapter();
        dsTA.Fill(ds.myTable);

        // Initializing the report file
        rpt = new ReportDocument();
        string reportPath = Server.MapPath(mapPath);
        rpt.Load(reportPath);

        DataTable dt = ds.myTable;
        Response.Write("<script>alert('Table has "+ dt.Rows.Count.ToString() +" rows');</script>");
        rpt.SetDataSource(dt); 

        // Binding the report file to the report viewer on the page
        CrystalReportViewer1.ReportSource = rpt;
        CrystalReportViewer1.ToolPanelView = CrystalDecisions.Web.ToolPanelViewType.ParameterPanel;
        CrystalReportViewer1.HasToggleGroupTreeButton = false;

    }

response.write 会在页面上弹出一个警告,说明 table 中有多少行被发送到报告。它计数正确,所以我知道数据正在发送到报告,但它没有选择任何数据。

老实说,我不知道为什么它没有选择任何东西。

编辑:经过一些快速测试后,我似乎可以在不破坏报告的情况下将参数添加到列表中。当我将实参元素放在页面上,或者当我将它用作选择专家的一部分时,报告无法加载行。

换句话说,报表只有在不弹出参数提示时才有效。

编辑 2:我尝试更改我的 DataSet 代码以使其实际连接到数据库。我以为我正在使用数据集来避免这种情况...但我在教程视频中看到了它。

代码在这里:

        string sConnectionString;
        sConnectionString = "Password=mYp@ssw0rd*;User ID=sa;" + "Initial Catalog=databaseName;" + "Data Source=serverName";
        SqlConnection conn = new SqlConnection(sConnectionString);
        conn.Open();
        SqlDataAdapter sDA = new SqlDataAdapter("Select * from myTable", conn);
        conn.Close();

        myDataSet ds = new myDataSet();

        sDA.Fill(ds, "myTable");
        // Initializing the report file
        rpt = new ReportDocument();
        string reportPath = Server.MapPath(mapPath);
        rpt.Load(reportPath);

        rpt.SetDataSource(ds);

毕竟:什么都没有。如果没有参数在工作,它仍然会从 table 加载所有数据。只要我添加一个参数(到页面,或作为选择专家的一部分),就没有记录加载。

编辑 3:我试过以编程方式传递参数:

rpt.SetParameterValue("par1", 1);

有趣的是,它确实 加载了DataSet 中的所有数据...直到我向它传递了一个新参数。然后没有记录加载,即使在我将参数设置回 1 之后也是如此。似乎一旦查看器必须处理一个参数,它就会删除所有记录。

我现在真的不知道去哪里看。据我所知,这是 rpt.SetDataSource() 或 CrystalReportsViewer1.ReportSource = rpt.

的问题

编辑 4:正如 user4663200 所指出的,当页面被 post 回退时,mapPath 为空存在一个问题。我尝试修复它,但 运行 变成了一个新错误,弹出窗口显示 'Please wait while the document is being processed.' 永远。我调查了这个错误,多个消息来源告诉我 t运行 将加载代码从 Page_Load().

转移到 Page_Init()

重要的是,当页面 post 在用户输入参数 后返回 时,此错误不知何故会导致。显然,如果没有 post 返回,该页面会正常加载。

我尝试在 Page_Init 中实现一个更简单的代码版本,但它不起作用,仍然有无休止的加载弹出窗口。

这是我的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using CrystalDecisions.CrystalReports.Engine;
using CrystalDecisions.Shared;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Data;  



private ReportDocument rpt;
private myDataSet ds;

protected void Page_Init(object sender, EventArgs e)
    {

        if (!Page.IsPostBack)
        {

            ds = new myDataSet();


            myDataSetTableAdapters.myTableTableAdapter dsTA = new myDataSetTableAdapters.myTableTableAdapter();

            dsTA.Fill(ds.myTable);
            // Initializing the report file
            rpt = new ReportDocument();
            string reportPath = Server.MapPath("myReport.rpt");
            rpt.Load(reportPath);
            Session.Add("dataSet", ds);
            Session["dataSet"] = ds;

            rpt.SetDataSource(ds);

            CrystalReportViewer1.ReportSource = rpt;

        }
        else
        {

            ds = (myDataSet)Session["Report"];
            rpt = new ReportDocument();
            string reportPath = Server.MapPath("myReport.rpt");
            rpt.Load(reportPath);
            rpt.SetDataSource(ds);
            CrystalReportViewer1.ReportSource = rpt;

        }

    }

问题是其他解决方案要求将报告保存在 session 中,但要实现这一点,需要将 Sessionstate 设置为 "InProc" 模式。我无法让这个网站脱离 "StateServer" 模式。我尝试了一种变通方法,将 DataSet 保存在 session 中,然后每次都将其绑定到新报告。但这也没有用。

EDIT 4.5 我刚刚尝试将 sessionState 更改为 InProc,但这仍然不起作用。即使我做到了,所以报告就是保存在 session.

中的内容

编辑 4.75 我尝试在 Page_Init() 中放置一个断点,它揭示了一些有趣的事情。

我可以看到 Session["Report"];在初始 运行 期间通过代码正确保存。

但是在输入参数后,我再次观察了 Page_Init(),当它尝试执行 rpt = (ReportDocument)Session["Report"]; Session["Report"] 中的所有内容均为空。它抛出了很多空异常,但这些只在断点调试器中可见,它们似乎从未在正常 运行 期间出现。我很确定这就是为什么它在 post 返回后一直加载的原因

所以现在的问题是post输入参数后返回导致session里面的数据全部丢失

EDIT 4.825:您可以忽略之前的编辑。我注释掉了这段代码:

    protected void Page_UnLoad(object sender, EventArgs e)
    {
        try
        {
            rpt.Close();
            rpt.Dispose();
        }
        catch { }
    }

摆脱这段代码后,我再次查看了 Session["Report"] 变量,它不再为空。

有趣的是,Page_UnLoad 在到达参数条目之前就被调用了。如果rpt.Close();正在转储对 rpt 的所有引用,那么 Session 变量就像一个指针,而不是存储实际的 rpt object。所以当 rpt 是 Disposed() 时,Session["Report"] 看起来只是一个空指针。

所以现在它传递了正确的东西...它仍然有无限 'document processing' 屏幕。

编辑 5:我终于让它工作了。

事实证明 sessions 是解决方案,但我找不到它的任何好的实现。

我的大部分相关代码都来自 here。但是你不能只是复制和粘贴它。

这是我的实现

    private ReportDocument rpt;
    private myDataSet ds;

    protected void Page_Init(object sender, EventArgs e)
    {

        if (!IsPostBack)
        {

            Session["Report"] = null;

        }

        if (Session["Report"] == null)
        {

            ds = new myDataSet();
            myDataSetTableAdapters.myTableTableAdapter dsTA = new myDataSetTableAdapters.myTableTableAdapter();
            DataTable dt = dsTA.GetData();

            rpt = new ReportDocument();
            rpt.Load(Server.MapPath("myReport.rpt"));
            rpt.SetDataSource(dt);
            Session.Add("Report", rpt);
            CrystalReportViewer1.ReportSource = rpt;
            CrystalReportViewer1.ToolPanelView = CrystalDecisions.Web.ToolPanelViewType.ParameterPanel;
            CrystalReportViewer1.HasToggleGroupTreeButton = false;

        }

    }

    protected void Page_Load(object sender, EventArgs e)
    {

        if (Page.IsPostBack)

        {

            rpt = (ReportDocument)Session["Report"];
            CrystalReportViewer1.ReportSource = rpt;
            CrystalReportViewer1.ToolPanelView = CrystalDecisions.Web.ToolPanelViewType.ParameterPanel;
            CrystalReportViewer1.HasToggleGroupTreeButton = false;

        }

    }

    protected void butReport_Click(object sender, EventArgs e)
    {

        if (Session["Report"] == null) // Report is not in session (previously loaded) so load report, set params, view and place in session
        {

            ds = new myDataSet();
            myDataSetTableAdapters.myTableTableAdapter dsTA = new myDataSetTableAdapters.myTableTableAdapter();
            DataTable dt = dsTA.GetData();

            rpt = new ReportDocument();
            rpt.Load(Server.MapPath("myReport.rpt"));
            rpt.SetDataSource(dt);
            Session.Add("Report", rpt);
            CrystalReportViewer1.ReportSource = rpt;
            CrystalReportViewer1.ToolPanelView = CrystalDecisions.Web.ToolPanelViewType.ParameterPanel;
            CrystalReportViewer1.HasToggleGroupTreeButton = false;

        }
        else
        {

            rpt = (ReportDocument)Session["Report"];
            CrystalReportViewer1.ReportSource = rpt;
            CrystalReportViewer1.ToolPanelView = CrystalDecisions.Web.ToolPanelViewType.ParameterPanel;
            CrystalReportViewer1.HasToggleGroupTreeButton = false;

        }

    }

最大的区别在于这一行:DataTable dt = dsTA.GetData(); 在我将整个数据集传递给 rpt 之前。我不确定为什么,但是使用 GetData() 的结果创建一个新的 DataTable 让报告保留在 session.

现在我的报告保存在 session 中,即使有所有 post 支持。我遇到并解决了其他一些问题,例如 session 在用户离开页面并返回时未重置。

您的 SQL 查询缺少 where 子句,因此无论您为参数输入什么,它总是 return 所有记录。后续调用失败的可能原因是您的 mapPath 为空,您在每个 Page_Load 上创建它,但仅在它不是回发时才设置它。这意味着在初始页面加载后,mapPath 为空,因此没有要拉取的报告。

已解决。有关解释,请参阅编辑 5。