我在Visual Studio 2010中使用Crystal Reports与ASP.NET。
我有一个从数据库中提取数据的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代码,以使其实际连接到数据库。我以为我正在使用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);
毕竟:没有。如果没有参数可用,它仍会加载表中的所有数据。只要我添加一个参数(到页面,或作为选择专家的一部分),就不会加载任何记录。
编辑3 :我已尝试以编程方式传递参数:
rpt.SetParameterValue("par1", 1);
有趣的是,确实加载了DataSet中的所有数据......直到我向它传递了一个新参数。然后,即使我将参数设置回1,也没有加载任何记录。看起来,一旦查看者必须处理参数,它就会删除所有记录。
我真的不知道现在在哪里看。据我所知,这是rpt.SetDataSource()或CrystalReportsViewer1.ReportSource = rpt的问题。
编辑4 :正如user4663200所指出的那样,当页面被回发时,mapPath为空。我尝试修复它,但遇到了一个新的错误,弹出窗口出现并说“请等待文档处理。”#39;永远。我查看了这个错误,多个消息来源告诉我将加载代码从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;
}
}
问题在于其他解决方案要求将REPORT保存在会话中,但为了实现这一点,需要将Sessionstate设置为&#34; InProc&#34;模式。我不能把这个网站从&#34; StateServer&#34;模式。我尝试通过在会话中保存DataSet,然后每次将其绑定到新报表来解决方法。但这也没有用。
编辑4.5 我刚尝试将sessionState更改为InProc,但这仍然无法正常工作。即使我这样做,报告也会在会话中被保存。
编辑4.75 我尝试在Page_Init()中添加一个断点,它揭示了一些有趣的东西。
我可以看到会话[&#34;报告&#34;];在初始运行代码时正确保存。
但是在输入参数后我再次看了Page_Init(),当它尝试做rpt =(ReportDocument)Session [&#34; Report&#34;];会话[&#34;报告&#34;]中的所有内容均为空。它抛出了许多空异常,但这些仅在断点调试器中可见,它们似乎在正常运行期间似乎没有出现。我很确定这就是为什么它会在回帖后永远加载。
现在的问题是,输入参数后回发会导致会话中的所有数据丢失。
编辑4.825 :您可以忽略之前的修改。我注释掉了这段代码:
protected void Page_UnLoad(object sender, EventArgs e)
{
try
{
rpt.Close();
rpt.Dispose();
}
catch { }
}
在删除此代码后,我再次查看了Session [&#34; Report&#34;]变量,它不再为null。
有趣的是,即使进入参数条目,也会调用Page_UnLoad BEFORE。如果是rpt.Close();正在转储对rpt的所有引用,然后就好像Session变量就像一个指针一样,而不是存储一个实际的rpt对象。因此,当rpt为Disposed()时,Session [&#34; Report&#34;]似乎只是一个空指针。
所以现在它正确的东西被传递......它仍然有无限的文件处理&#39;屏幕。
编辑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(); 在我将整个DataSet传递给rpt之前。我不确定原因,但使用GetData()结果创建新的DataTable可让报告保持在会话中。
现在我的报告即使在所有回发中都会保持在会话中。我遇到并解决了一些其他问题,例如当用户离开页面并返回时会话未重置。
答案 0 :(得分:0)
您的SQL查询缺少where子句,因此无论您为参数添加什么内容,它都将始终返回所有记录。可能后续调用失败的原因是你的mapPath是空白的,你在每个Page_Load上创建它,但只有在它不是回发时才设置它。这意味着在初始页面加载后,mapPath为null,因此没有报告可以提取。
答案 1 :(得分:0)
解决。有关说明,请参见第5步。