最近改造一个小型购物网站,要求使用水晶报表实现订单打印,本人对水晶报表从一无所知到,到最终弄出来整整花了一夜的时间,特此记录下此文和大家共享。
关于水晶报表更详细的介绍建议大家可以参考阿泰的博客:http://blog.csdn.net/babyt
首先来说说关于水晶报表的推(PUSH)模式和拉(PULL)模式,这个其实很好理解,说简单点推(PUSH)模式就是自己写SQL语句去查询数据库,然后把查询数据集(可以是DataSet也可以是对象集合)结果推送给水晶报表引擎,水晶报表本身不不跟数据库进行交互;而拉(PULL)模式就不用写SQL语句,由水晶报表模板(引擎)直接连接数据库(源),从数据库(源)里拉取数据就是我们在水晶报表里设置好数据库信息,以及相关的表。
关于推拉模式的优缺点我不去做过多的评价,但是在这里用的是access数据库,使用推(PUSH)模式会是一个比较好的选择,为什么?因为免去了水晶报表访问数据库验证登录的问题,此外既然是access数据库数据库绝对路径总会有所变化的,所以拉(PULL)模式不合适,再者订单打印的条件总是变化的,虽然说在拉(PULL)模式下你也可以使用添加命令的方式书写SQL语句和设置对应的参数来适应打印条件的变化,但个人比较喜欢用SQL语句来控制,查到什么打什么,所以说推(PUSH)模式是最适合我的。
接下来说说多数据源的问题,大家都知道,订单这种东西一般都是上面有主订单的信息,然后下面是订单明细,更坑爹的是我这个数据库订单明细里没有商品名,所以还得关联到商品表里去商品名称,所以在使用数据库作为数据专家设计rpt报表时肯定涉及到多数据源也就是多张数据库的表,当然你也可以以用类对象作为.NET对象来设计rpt报表,但是这样在后面提供数据源时你还得报数据库查询的结果转换成对象集合,我不想那么麻烦所以直接用数据库表作为数据专家设计rpt报表,这里一定不要忘了在设置数据专家时设置好多张表的关联关系。
上面我已经说了订单的形式是上面主订单,下面订单明细,同时我们还有可能一次打印多张订单,所以主订单信息只能作为主报表的详细资料,而订单明细必须作为子报表加入到主报表的详细资料里,如下图:
主报表和子报表都设计好了,接下来就是写代码了,主报表设置数据源很简单,子报表数据源呢?其实也很简单,要这设置数据源就要获取子报表对象,我们只要通过 主报表.Subreports["子报表名"]; 就可以取得子报表了,那子报表数据源有两张表,怎提供数据呢?其实把多个查询到的集合合并到同一个DataSet就行了,下面看代码:
using System; using System.Collections; using System.Configuration; using System.Data; using System.Linq; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Xml.Linq; using System.Collections.Generic; using CrystalDecisions.CrystalReports.Engine; using CrystalDecisions.Shared; using System.Data.OleDb; public partial class admin_Default2 : System.Web.UI.Page { protected void Page_Init(object sender, EventArgs e) { if (Session["myRpt"] != null) { CrystalReportViewer1.ReportSource = (ReportDocument)Session["myRpt"]; } } protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { string key="and oId=3"; //string key = ""; string sql1 = "select * from ordergoods where 1=1" + key; string sql2 = "select * from orderdetailed where oId in (select oId from ordergoods where 1=1" + key + ")"; string sql3 = "select * from goods where id in (select gId from orderdetailed where oId in (select oId from ordergoods where 1=1" + key + "))"; string cn = System.Configuration.ConfigurationManager.ConnectionStrings["myorderConnectionString"].ToString(); DataSet dataSet = new DataSet(); OleDbConnection oleDbConnection = new OleDbConnection(cn); //ordergoods表 OleDbDataAdapter oleDbDataAdapter = new OleDbDataAdapter(sql1, oleDbConnection); oleDbDataAdapter.Fill(dataSet); dataSet.Tables[0].TableName = "ordergoods"; //orderdetailed表 oleDbDataAdapter = new OleDbDataAdapter(sql2, oleDbConnection); oleDbDataAdapter.Fill(dataSet); dataSet.Tables[1].TableName = "orderdetailed"; //goods表 oleDbDataAdapter = new OleDbDataAdapter(sql3, oleDbConnection); oleDbDataAdapter.Fill(dataSet); dataSet.Tables[2].TableName = "goods"; //主报表 ReportDocument Maindoc = new ReportDocument(); Maindoc.Load(Server.MapPath("~/admin/CrystalReport1.rpt")); Maindoc.SetDataSource(dataSet); //子报表 ReportDocument Subdoc = Maindoc.Subreports["CrystalReport2.rpt"]; Subdoc.SetDataSource(dataSet); this.CrystalReportViewer1.ReportSource = Maindoc; this.CrystalReportViewer1.DataBind(); //保存到Session Session["myRpt"] = Maindoc; } } }
水晶报表的功能远不止这些,大家可以在网上找一下相关的资源,特别是阿泰的博客,另外还有以下的一些教程:
http://blog.csdn.net/ajaxtop/article/details/6672218
http://blog.sina.com.cn/s/blog_730d1aed0101472r.html
http://blog.csdn.net/luols/article/details/7037367