- PR -

DataSetからのCrystalReports出力について

1
投稿者投稿内容
kuta
会議室デビュー日: 2008/06/25
投稿数: 8
お住まい・勤務地: 東京都
投稿日時: 2008-06-25 13:35
初投稿です。宜しくお願いします。

VS2005(C#)のWebアプリケーションでCrystalReports for VS2005を用いた帳票を作成しています。

以下のようにしてレポートに出力されるデータを制限しようとしたのですが、レポートファイルに定義しているSQL ServerのView全件が出力されてしまいます。


// レポートに出力するデータを取得
DataSet ds = con.ExecuteQuery("SELECT * FROM dbo.v_Test WHERE column1='01112200001'");

// 取得データのバインド
CrystalDecisions.CrystalReports.Engine.ReportDocument cReport = new CrystalDecisions.CrystalReports.Engine.ReportDocument();
cReport.Load(@"Test.rpt");
cReport.SetDataSource(ds);
CrystalReportViewer1.ReportSource = cReport;


何か良い解決方法があればご教示願います。
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2008-06-25 14:26
引用:

kutaさんの書き込み (2008-06-25 13:35) より:

以下のようにしてレポートに出力されるデータを制限しようとしたのですが、レポートファイルに定義しているSQL ServerのView全件が出力されてしまいます。


まず con の型を教えてください。

Web の場合はキャッシュが悪さをしている可能性があります。 CrystalReports 側に問題があるとしたら、バウンド レポートになっていることが考えられます。

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
kuta
会議室デビュー日: 2008/06/25
投稿数: 8
お住まい・勤務地: 東京都
投稿日時: 2008-06-25 14:51
早速のご回答、ありがとうございます。

con は独自に開発した SQL Serverへの接続・問合せ・トランザクション処理等、DBアクセスに必要となるメソッドを提供するクラスで、con.ExecuteQueryメソッドは、引き渡されたSQL文を元にクエリを実行して結果を DataSet へ戻す仕組みになっています。

デバッグ実行したところ、ds変数には期待したSQL結果が戻ってきているので、取得データ自身は問題ないと思います。

問題は、バウンドレポートに対するデータの再セットが効かない点だとは認識しているのですが、その回避方法がわからない状態です。

「SQL ServerのViewからデータを絞り込んで、且つ任意のソート順でレポートを出力したい」

上記目的を考慮の上、ご回答頂ければ幸いです。
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2008-06-25 15:53
引用:

kutaさんの書き込み (2008-06-25 14:51) より:

問題は、バウンドレポートに対するデータの再セットが効かない点だとは認識しているのですが、その回避方法がわからない状態です。


つまり 「キャッシュ」 が原因ではないということでしょうか? バウンド レポートをやめるか、バウンド レポートに設定されているクエリを変更するほかないと思います。 DataSet を使っている時点でアンバウンド レポートでなければならないと思いますが。

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
kuta
会議室デビュー日: 2008/06/25
投稿数: 8
お住まい・勤務地: 東京都
投稿日時: 2008-06-25 17:31
レポート側でViewを直接参照することを止め、ソリューションにDataSetを追加して、そのDataSetを参照するようにしてみました。
(バウンドレポート→アンバウンドレポートへの切り替え?)

@ソリューションエクスプローラの「新しい項目の追加」からデータセットを追加。(DataSet2)
ADataSet2の中にDataTableを追加。(dtReport)
BDataTableに、レポートが元々参照していたViewと同じ項目を追加。
C以下のようにプログラムを修正。

// レポートに出力するデータを取得
DataSet ds = con.ExecuteQuery("SELECT * FROM dbo.v_Test WHERE column1='01112200001'");

// 取得データのバインド
CrystalDecisions.CrystalReports.Engine.ReportDocument cReport = new CrystalDecisions.CrystalReports.Engine.ReportDocument();
cReport.Load(@"Test.rpt");

DataSet2 ds2 = new DataSet2();
foreach (DataRow dr in ds.Tables[0].Rows)
{
DataSet2.dtReportRow dr2 = (DataSet2.dtReportRow)ds2.Tables[0].NewRow();
dr2.BeginEdit();
for (int iColIdx = 0; iColIdx < ds.Tables[0].Columns.Count; iColIdx++)
{
dr2[iColIdx] = dr[iColIdx];
}
dr2.EndEdit();

ds2.dtReport.AdddtReportRow(dr2);
}
cReport.SetDataSource(ds2);

これにより無事、抽出したデータのみをレポートへ出力することができました。
但し一つ腑に落ちない点があります。

追加した厳密な型指定のDataSetのDataTableに直接、System.Data.DataTableをセットできないのか?
(foreachの処理を簡素化したい)

何か良い方法があれば教えてください。宜しくお願いします。

[ メッセージ編集済み 編集者: kuta 編集日時 2008-06-25 17:39 ]
kuta
会議室デビュー日: 2008/06/25
投稿数: 8
お住まい・勤務地: 東京都
投稿日時: 2008-06-26 10:36
自己レスです。
色々試してみましたが、厳密に型指定されたDataSet(プロジェクトに追加する方式のDataSet)へは、DataRow レベルでの値のセットしかできませんでした。
が、やりたいことは出来たので解決とさせて頂きます。
じゃんぬねっと様、適切なヒントをありがとうございました。

CrystalReports に関する技術情報を公開している箇所が少ないので、本件に至るまでに得た情報も含め、まとめとして投稿しておきます。



◆レポートデータとして Table/View等 を割り当てて CrystalReportViewer で表示させたい場合
(1)Webページに CrystalReportViewer を配置する
(2)レポートの編集へ移り、データベースエクスプローラを起動する
(3)Table/View等 を割り当てる

【SQL ServerのView へ接続する場合の例】
 @接続の新規作成から OLE DB(ADO) を選択し、SQL Native Client を選択する
 A適切な接続情報を入力
 B利用可能なデータソース欄に上記で入力したDBが追加されるので、対象の Table/View等 を選択する




◆レポートデータとして Table/View等 を割り当てて CrystalReportViewer で表示する際に、ユーザ名・パスワードを都度入れるのを抑止したい場合

CrystalDecisions.CrystalReports.Engine.ReportDocument cReport = new CrystalDecisions.CrystalReports.Engine.ReportDocument();
cReport.Load(@"[レポートファイル名(フルパス)]")
cReport.SetDatabaseLogon("[DBユーザ]", "[DBユーザのパスワード]");
CrystalReportViewer1.ReportSource = cReport;

//(CrystalReportViewer のプロパティで AutoBind = False に設定している場合は以下のメソッドを実行)
CrystalReportViewer1.DataBind();

※SetDatabaseLogon にはいくつかのオーバーロードがあるため、サーバ1・サーバ2で同じViewを定義して切り替えるようなこともできるかも?




◆レポートデータとしてオリジナルで作成した DataSet を割り当てて CrystalReportViewer で表示させたい場合
(1)ソリューションエクスプローラから新しい項目の追加としてデータセットを追加する
(2)自動的に表示されるウィザードをキャンセルする
(3)ツールボックスから DataTable を選択して追加する
(4)取得するデータのカラムを定義して保存する
(5)Webページに CrystalReportViewer を配置する
(6)レポートの編集へ移り、データベースエクスプローラを起動する
(7)プロジェクトに追加した DataSet を割り当てる
(8)プロジェクトデータ→ADO.NETデータセットの順に展開すると上記で作成した DataSet が表示されるので、その配下にある DataTable を選択する
(9)CrystalReportViewer を配置したページで以下のようにコーディングする

// SQL DataAdapter等を用いて System.Data.DataSet へデータを取得する
// 例の con はオリジナルに作成したクラスで、con.ExecuteQuery は引数のSQL文の実行結果を System.Data.DataSet へ戻します
DataSet ds = con.ExecuteQuery("SELECT * FROM dbo.v_Test WHERE column1='01112200001'");

// ReportDocument の DataSource へ、上記で取得した DataSet の値をセットする
CrystalDecisions.CrystalReports.Engine.ReportDocument cReport = new CrystalDecisions.CrystalReports.Engine.ReportDocument();
cReport.Load(@"[レポートファイル名(フルパス)]")

DataSet2 ds2 = new DataSet2(); // DataSet2はプロジェクトに追加した、厳密に型指定された DataSet
foreach (DataRow dr in ds.Tables[0].Rows)
{
DataSet2.dtReportRow dr2 = (DataSet2.dtReportRow)ds2.Tables[0].NewRow();
dr2.BeginEdit();
for (int iColIdx = 0; iColIdx < ds.Tables[0].Columns.Count; iColIdx++)
{
dr2[iColIdx] = dr[iColIdx];
}
dr2.EndEdit();

ds2.dtReport.AdddtReportRow(dr2);
}
cReport.SetDataSource(ds2);
CrystalReportViewer1.ReportSource = cReport;




◆CrystalReport上で定義したパラメータフィールドに値をセットしたい場合(方式は2通りあります)

@厳密なコーディングを行う方式

CrystalDecisions.Shared.ParameterField paramField = new CrystalDecisions.Shared.ParameterField();
CrystalDecisions.Shared.ParameterFields paramFields = new CrystalDecisions.Shared.ParameterFields();
CrystalDecisions.Shared.ParameterDiscreteValue paramDiscreateValue = new CrystalDecisions.Shared.ParameterDiscreteValue();

paramField = new CrystalDecisions.Shared.ParameterField();
paramDiscreateValue = new CrystalDecisions.Shared.ParameterDiscreteValue();
paramField.Name = "[CrystalReport上で定義したパラメータフィールド名称]";
paramDiscreateValue.Value = "[パラメータフィールド値]";
paramField.CurrentValues.Add(paramDiscreateValue);
paramFields.Add(paramField);

//(2つ目以降のパラメータ値をセットする場合)
paramField = new CrystalDecisions.Shared.ParameterField();
paramDiscreateValue = new CrystalDecisions.Shared.ParameterDiscreteValue();
paramField.Name = "[CrystalReport上で定義したパラメータフィールド2名称]";
paramDiscreateValue.Value = "[パラメータフィールド2値]";
paramField.CurrentValues.Add(paramDiscreateValue);
paramFields.Add(paramField);

CrystalReportViewer1.ParameterFieldInfo = paramFields;

※パラメータ値は、CrystalReportViewer に DataBind された後にセットしないと適用されません


A簡素なコーディングを行う方式(SetParameterValue メソッドの中身は@かも?)

CrystalDecisions.CrystalReports.Engine.ReportDocument cReport = new CrystalDecisions.CrystalReports.Engine.ReportDocument();
cReport.SetParameterValue("[CrystalReport上で定義したパラメータフィールド1名称]", "[パラメータフィールド1値]");
cReport.SetParameterValue("[CrystalReport上で定義したパラメータフィールド2名称]", "[パラメータフィールド2値]");
CrystalReportViewer1.ReportSource = cReport;

※パラメータ値は、CrystalReportViewer に DataBind された後にセットしないと適用されません
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2008-06-26 21:56
引用:

kutaさんの書き込み (2008-06-25 17:31) より:

追加した厳密な型指定のDataSetのDataTableに直接、System.Data.DataTableをセットできないのか?(foreachの処理を簡素化したい)


DataTable 以上の層で手動の値変更はできないです。 アンバウンド レポートは多くの場合 DataAdapter を使って DataSet に Fill することでデータを生成することが多いです。 つまり SQL レベルで解決すべき問題かそうでないかですね。

引用:

CrystalReports に関する技術情報を公開している箇所が少ないので、本件に至るまでに得た情報も含め、まとめとして投稿しておきます。


おまとめありがとうございます。 Bind はやはり面倒くさいので (ログオンもしなくてはいけないですし) 避けたいところですね。

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
1

スキルアップ/キャリアアップ(JOB@IT)