摘 要:水晶報表是一個功能強大的報表工具,現在已經被Microsoft Visual Studio 2005集成在一起,如何能動態地將多表以交叉表的方式實現是一種相當關鍵的技術難點,本文從完成“陽易教學分析系統V1.0-成績交叉分析”模塊來向讀者做一個詳細的介紹。
關鍵詞:水晶報表 動態 交叉表
一、引言
幾乎在所有的應用程序中報表都是程序員頭疼的問題。在.Net環境下包含了功能強大的報表工具:水晶報表(Crystal Report)。
Crystal Reports通過數據庫驅動程序與數據庫連接。每個驅動程序都被編寫為可處理特定數據庫類型或數據庫訪問技術。為了向開發人員提供最靈活的數據訪問方法,Crystal Reports 數據庫驅動程序被設計為可同時提供數據訪問的拉模型和推模型。
●拉模型
在拉模型中,驅動程序將連接到數據庫并根據需要將數據“拉”進來(見圖1)。使用這種模型時,與數據庫的連接和為了獲取數據而執行的SQL命令都同時由Crystal Reports本身處理,不需要開發人員編寫代碼。如果在運行時無須編寫任何特殊代碼,則使用拉模型。

●推模型
相反,推模型需要開發人員編寫代碼以連接到數據庫,執行SQL命令以創建與報表中的字段匹配的記錄集或數據集,并且將該對象傳遞給報表(見圖2)。該方法使您可以將連接共享置入應用程序中,并在Crystal Reports收到數據之前先將數據篩選出來。
本文為了實現動態按條件生成報表的,因此主要采用推模型。
交叉表是一種非常常見的報表形式。一般的二維表只有列頭,行就是數據,而交叉表(Cross Table)是行和列都有相應的行頭和列頭,中間的格子是交叉匯總項。原來的數據標題(字段)在兩列上,但是現在想給其中一個列放到水平方向,形成行列交叉,交叉點求出統計結果,得出直接在表中不能看出的分析數據。交叉表查詢顯示來源于表中某個字段的總結值(合計、計算以及平均值等),并將它們分組放置在查詢表中,一組列在數據表的左側,一組列在數據表的上部。
本文將從完成“陽易教學分析系統V1.0-成績交叉分析”模塊來向讀者做一個詳細地介紹。
二、系統模塊的設計
1. 數據庫表的建立
系統已經有一個數據庫:YangYiDB,包括三張表:課程、成績、學生。各表之間的關系圖見圖3。

2.系統模塊的實現
第一步、啟動VS2005,新建一個架構文件。
a.在解決方案資源管理器中,右擊項目名,指向“添加”,然后單擊“添加新項”。
b.在“添加新項”對話框的“類別”區域,展開文件夾,然后選擇“數據”。
c.在“模板”區域選擇“數據集”。
d.修改默認名稱 DataSetCross.xsd。
這就創建了一個新的架構文件(DataSetCross.xsd),以后將用它來生成強類型數據集。該架構文件將顯示在ADO.NET數據集設計器中。
e.從“工具箱”中拖放一個DataTable,放入DataSetCross.xsd中,創建幾個字段:名字、課程名、成績(見圖4)。
第二步、新建一個創建新報表。
a.指向“添加”,單擊“添加新項”。
b.在“添加新項”對話框中,從“模板”區域選擇Crystal Report,將報表命名為CrystalReport006,同時根據前面的數據集DataSetCross.xsd設計交叉表(如圖5)。
第三步、新建窗體文件,命名為“Form012”。
a.拖放控件tableLayoutPanel1、groupBox2、checkBox3、checkBox2、checkBox1、button1、crystalReportViewer1、statusStrip1,布局和設置如圖6所示。
第四步、代碼實現。
a.在Form012類前面添加語句
using System.Data.OleDb;
using CrystalDecisions.CrystalReports.Engine;
using CrystalDecisions.Shared。
b.給Form012類添加類字段
tempDataView:
private DataView tempDataView; //
c.自定義私有方法myDataView(),實現連接數據庫,讀取前面所提的三張表的名字、課程名、成績字段,返回一個內存中的數據視圖,代碼如下:
private DataView myDataView( )
{
DataSet tempDataSet = new DataSet( );
string connString = ″Provider=SQLOLEDB;Data Source=.;User ID=sa;Initial Catalog=Test″;
OleDbConnection myOleDbConnection = new OleDbConnection(connString);
string sqlString = ″select 名字,課程名,成績 from 學生,課程,成績 where 學生.學號=成績.學號and課程.課程號=成績.課程號″;
OleDbDataAdapter myOleDbDataAdapter = new OleDbDataAdapter(sqlString, myOleDbConnection);
myOleDbDataAdapter.Fill(tempDataSet, ″學生課程成績″);
return tempDataSet.Tables[″學生課程成績″].DefaultView;
}
d.在Form012_Load事件中添加tempDataView=myDataView();來調用上述方法。
e.雙擊“輸出報表”按鈕,在button1_Click事件中加入如下代碼:
CrystalReport006 myCrystalReport006 = new CrystalReport006( );
DataSetCross myDataSetCross = new DataSetCross( );
//產生動態條件,存入字符ChooseStr中
string ChooseStr = ″″;
if (checkBox1.Checked) ChooseStr = ChooseStr + ″課程名=’″ + checkBox1.Text + ″’″;
if (checkBox2.Checked) ChooseStr = ChooseStr + ″ or ″ + ″課程名=’″ + checkBox2.Text + ″’″;
if (checkBox3.Checked) ChooseStr = ChooseStr + ″ or ″ + ″課程名=’″ + checkBox3.Text + ″’″;
if (ChooseStr == ″″)
{ MessageBox.Show(″請選擇要顯示的字段″); return; }
if (ChooseStr.Substring(0, 4) == ″ or ″)
ChooseStr = ChooseStr.Substring (4, ChooseStr.Length - 4);
//產生視圖tempDataView,對應存入架構文件myDataSetCross中
tempDataView.RowFilter = ChooseStr;
foreach (DataRowView drw in tempDataView)
{
DataRow dr = myDataSetCross.Tables[″DataTableCross″].NewRow();
dr = drw[″名字″]; dr = drw[″課程名″]; dr = drw[″成績″];
myDataSetCross.Tables[″DataTableCross″].Rows.Add(dr);
}
//刷新crystalReportViewer1,并將crystalReportViewer1顯示出新的數據集結果
crystalReportViewer1.Refresh();
myCrystalReport006.SetDataSource(myDataSetCross.Tables[″DataTableCross″]);
crystalReportViewer1.ReportSource = myCrystalReport006;
第五步、程序運行,查看結果。
a.任意選擇各種課程;
b.點擊“輸出報表”按鈕;
c.重復a和b,可以看到有不同的交叉表輸出。

結束語
用C#實現動態地水晶報表交叉表的實現方式,在許多項目中都將會用到,掌握其中的細節將會對軟件開發者帶來很大的幫助。
參考文獻:
[1].NET環境下水晶報表使用總結
http://blog.csdn.net/vwfkyy/archive/2007/08/30/1765960.aspx
[2]Microsoft Visual Studio 2005中使用水晶報表
http://blog.csdn.net/zhaobinheng/archive/2007/08/14/1742200.aspx
[3]VS2005下水晶報表如何實現動態數據源綁定
http://www.cnblogs.com/newwind521/archive/2007/08/31/876884.html