【问题标题】:Crystal Reports not selecting any records when I add a parameter to the report当我向报表添加参数时,Crystal Reports 没有选择任何记录
【发布时间】:2015-05-14 22:51:04
【问题描述】:

我在带有 ASP.NET 的 Visual Studio 2010 中使用 Crystal Reports。

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

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

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

如果有影响,我将通过字段资源管理器添加参数及其值。

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

我认为我的 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 会在页面上弹出一个警报,说明正在发送到报告的表中有多少行。它计算正确,所以我知道数据正在发送到报告中,但它没有选择任何数据。

我真的不知道为什么它没有选择任何东西。

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

也就是说,报表只有在不弹出参数提示时才有效。

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

代码在这里:

        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);

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

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

rpt.SetParameterValue("par1", 1);

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

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

编辑 4:正如 user4663200 指出的那样,当页面回发时,mapPath 为 null 存在问题。我尝试修复它,但遇到了一个新错误,出现一个弹出窗口并说“正在处理文档,请稍候。”永远。我调查了这个错误,多个消息来源告诉我将加载代码从 Page_Load() 转移到 Page_Init()。

重要的是,当页面回发用户输入参数时,会以某种方式导致此错误。显然,如果页面不回发,该页面会正常加载。

我尝试在 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;

        }

    }

问题是其他解决方案要求将报告保存在会话中,但要做到这一点,需要将 Sessionstate 设置为“InProc”模式。我不能让这个网站脱离“StateServer”模式。我尝试了一种解决方法,将数据集保存在会话中,然后每次将其绑定到新报告。但这也不起作用。

EDIT 4.5 我刚刚尝试将 sessionState 更改为 InProc,但这仍然不起作用。即使我这样做了,报告也是会话中保存的内容。

EDIT 4.75 我尝试在 Page_Init() 中放置一个断点,它揭示了一些有趣的东西。

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

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

所以现在的问题是,输入参数后回传会导致会话中的所有数据丢失。

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 对象。因此当 rpt 为 Disposed() 时,Session["Report"] 似乎只是一个空指针。

所以现在它传递了正确的东西......它仍然有无限的“文档处理”屏幕。

EDIT 5:我终于让它工作了。

原来会话是解决方案,但我找不到任何好的实现。

我的大部分相关代码来自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 可以让报表保持在会话中。

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

【问题讨论】:

  • 这是否会以“执行超时”异常结束,或者确实如此,您可能需要等待一段时间才能获得超时,我认为默认值为 15 分钟。
  • 为了测试这一点,我已经运行了 20 多分钟。它没有抛出任何异常。

标签: c# asp.net crystal-reports


【解决方案1】:

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

【讨论】:

  • 我很确定我的 SQL 查询应该返回所有记录。该参数由水晶报表处理,因此报表需要接收所有记录,然后它会自己从中选择。除此之外,我试着让它 mapPath 一直都是正确的,但我遇到了一个新错误。看我的编辑 4。你说得对,这绝对是个问题。
【解决方案2】:

解决了。有关说明,请参见编辑 5。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-06
    相关资源
    最近更新 更多