そのため、省コストであるとか短納期であるとかいうところに力点が置かれ始めると、必ずしも帳票である必要はなく、レポートでいいのではないかということになります。でも、本当にレポートでいいと思っているのでしょうか。そこには「コストがかかったり納期が延びてしまうなら仕方がない」というあきらめが存在するのではないかと考えます。
Webアプリでの印刷も状況は同じでしょう。一種の諦めが、レポートで表現できる印刷結果で仕方がないという判断になっているのではないでしょうか。
では、こう問われたらどうでしょう。「レポートと大きく変わらない納期で帳票出力できますが、レポートと帳票のどちらがよろしいでしょうか」と。
そこで実際にどのような形で帳票が印刷できるのか、「ActiveReports for .NET 9.0J」と「CData ADO.NET Provider for Salesforce 4J」(以下、ActiveReports + CData)を使って、大企業向けSaaSのトップランナーであるSalesforceから帳票を印刷して確認してみたいと思います。
Salesforceの準備(おさらい)
今回の内容の説明に入る前に、Salesfoceの準備をおさらいしてみましょう。
Salesforceの利用開始
CDataでSalesforceに接続するためには、SalesforceのエディションとしてEnterprise EditionまたはUnlimited Editionが必要です。無料トライアルはそれ以外のエディションになるので、無料のDeveloper Editionに申し込みます。
[サインアップ]ボタンをクリックすると「無料のDeveloper Edition環境にサインアップ」画面が表示されるので、姓名やメールアドレスなどの必要事項を登録します。数分後に登録したメールアドレス宛にSalesforceからメールが届くので、そこに記載されたURLにアクセスすればDeveloper Editionの利用を開始できます。
セキュリティトークンの入手
手元にセキュリティトークンがあるのならばそれを使用します。ないようであればセキュリティトークンを入手します。入手方法は次の手順になります。
- Salesforceにログインし、ヘッダに表示されている自分の名前のドロップダウンメニューを開いて[私の設定]メニューを選択します。
- [私の設定]画面が開いたら、サイドメニューから[個人用]メニューを選択、[私のセキュリティトークンのリセット]メニューを選択します。
- [セキュリティトークンのリセット]ボタンをクリックします。
これでセキュリティトークンが登録してあるメールアドレスにメールで届きます。
システム構成
今回のサンプルで想定しているシステム構成は次のようになります。
![図1 WPFアプリのシステム構成](http://cz-cdn.shoeisha.jp/static/images/article/8597/8597_01.gif)
WPFアプリではなくWebアプリでということであれば次のような構成も考えられます。
![図2 Webアプリのシステム構成](http://cz-cdn.shoeisha.jp/static/images/article/8597/8597_02.gif)
CDataの準備
CDataのインストールが完了していれば、あとはプロジェクトで参照設定を行えばコードから使うことができます。
また、サーバーエクスプローラーでデータ接続先に指定しておくと、認証情報の確認やSalesforce上のテーブルの参照が行えるのでお勧めです。
![図3 サーバーエクスプローラーにデータ接続追加](http://cz-cdn.shoeisha.jp/static/images/article/8597/8597_03.gif)
今回のサンプルではCampaignテーブルを使います。
データ取得ロジックの作成
CDataを使ってテーブルの内容を取得するコードを作成します。
Imports System.Data.CData.Salesforce Imports System.Data Namespace Models Public Class ReportModel Private _DatasetData As New System.Data.DataSet Public ReadOnly Property DataSetData() As System.Data.DataSet '……(1) Get Return _DatasetData End Get End Property Public Sub GetRecords() Dim sb = New SalesforceConnectionStringBuilder() With { .User = "mailaddress", .Password = "password", .SecurityToken = "JX55LjThc8A5IUcjtAdEqbsf"} '……(2) _DatasetData.Clear() Using conn = New SalesforceConnection(sb.ConnectionString) Using da = New SalesforceDataAdapter("SELECT * FROM Campaign", conn) da.Fill(_DatasetData, "Campaign") '……(3) End Using End Using End Sub End Class End Namespace
- 取得結果を参照するためのDataSetを定義
- Salesforceとの接続文字列を設定
- SELECT文の実行結果をDataSetに設定
CDataはADO.NET準拠の外部仕様をもっているので、ADO.NETの知識でコードが作成できます。
ActiveReportsの準備
RDLレポートの追加
ソリューションエクスプローラーでプロジェクトを右クリックして[追加]-[新しい項目の追加]メニューをクリックします。[新しい項目の追加]ダイアログで「ActiveReports 9.0J RDLレポート(XML)」を選択します。名前は「CZ1503rdl.rdlx」とします。
ActiveRepots 9.0J レポートエクスプローラの利用
RDLレポートにデータセットを定義し、データセット上の項目と印字位置を対応付けます。そのためには、まず「ActiveRepots 9.0J レポートエクスプローラ」を起動してデータセットを定義しましょう。
ActiveRepots 9.0J レポートエクスプローラは、[表示]-[その他のウィンドウ]-[ActiveRepots 9.0J レポートエクスプローラ]メニューから起動します。
Dataset Providerの追加
レポートエクスプローラで「データソース」を右クリックして[データソースの追加]メニューをクリックします。ダイアログで[構成]に「Dataset Provider」を選択して[OK]ボタンをクリックし、データソースを追加します。
データセットの追加
レポートエクスプローラで追加したデータソースを右クリックして[データセットの追加]メニューをクリックします。
サーバーエクスプローラーでCampaignテーブルの項目を見ながら必要な項目をフィールドとして定義していきます。
今回のサンプルでは、Id、Name、Type、Status、StartDate、EndDateの6つの項目を抜き出してみました。先ほどのCDataが「SELECT * FROM Campaign」として全項目抜き出していたこととの差異を覚えておいてください。
帳票定義
準備ができたら帳票定義を行います。RDLレポートにはTableコントロールがあり手軽に一覧表が作成できます。
Tableコントロールをレポートデザイナーにドラッグ&ドロップするとヘッダ、詳細、フッターの3行から構成されたグリッドが表示されます。この詳細部分にDataSetに定義したフィールドを割り当てます。
詳細にフィールドを割り当てると自動的にヘッダにフィールド名が入ります。またセル同士を繋げて一つにしたり、詳細を複数行で定義したりすることもできます。今回のサンプルでは、最終的に詳細を2段にして次のような定義を行いました。
これにTableのコントロール罫線やLineコントロールを使用して罫線を引いてあげると、より帳票っぽくなるでしょう。
Viewerコンポーネントの設置
いきなり印刷してしまってもいいのですが、プリンターが手元にない時にも確認ができるように、MainWindowにビューアーを設置してプレビュー表示できるようにしましょう。
そのためには、まずツールボックスにViewerコンポーネントを追加します。
追加できたらWPFデザイナーでWPFウィンドウを表示しておき、ドラッグ&ドロップでViewerコンポーネントを配置してから微調整します。
Imports GrapeCity.ActiveReports Namespace Views Public Class MainWindow Private Runt As GrapeCity.ActiveReports.Document.PageDocument Public Sub New() ' この呼び出しはデザイナーで必要です。 InitializeComponent() ' InitializeComponent() 呼び出しの後で初期化を追加します。 Me.DataContext = Application.MainVM SetReports() '……(1) AddHandler Application.MainVM.PropertyChanged, AddressOf MainVM_PropertyChanged '……(2) End Sub Private Sub SetReports() Dim fi As New System.IO.FileInfo("CZ1503rdl.rdlx") Dim repDef As New GrapeCity.ActiveReports.PageReport(fi) Me.Runt = New GrapeCity.ActiveReports.Document.PageDocument(repDef) AddHandler Me.Runt.LocateDataSource, AddressOf runt_LocateDataSource End Sub Private Sub MainVM_PropertyChanged(sender As Object, e As ComponentModel.PropertyChangedEventArgs) If e.PropertyName = "DataSetData" Then Me.CZ1503Viewer.LoadDocument(Me.Runt) '……(3) End If End Sub Private Sub Runt_LocateDataSource(ByVal sender As Object, ByVal args As LocateDataSourceEventArgs) args.Data = Application.MainVM.DataSetData.Tables("Campaign") '……(4) End Sub End Class End Namespace
- ActiveReports用の設定を実施
- ReportModelが提供するデータが変化した時に発生するイベントを登録
- データが取得できたら帳票定義体をローディング
- ActiveReportsがデータを必要としたときに呼び出されるプロシージャの中でReportModelが作成したデータを設定
「args.Data = Application.MainVM.DataSetData.Tables("Campaign")」は、CDataで取得した全項目が入ったDataSetを6つの項目しか定義してなかったRDLレポートのDataSetに代入しています。これによりRDLレポートのDataSetは全項目を持つことになります。
その状態でも帳票定義体に指定したフィールド名と同一のものを印字します。
今回は意図的にCData側で全項目を取得しましたが、メモリ使用効率やデータ転送効率を考えるとCData側でも必要な項目だけを取得するようにしましょう。
まとめ
もしかしたら、海外では帳票というものの存在を知らないのでレポートで満足していたりしないでしょうか。例えば、お客様の手元に届く請求書や納品書は、日本品質の帳票出力の方がより満足いただける可能性があると考えます。もし、そういった可能性を今まで除外していたとしたら、レポートではなく帳票の可否を検討してみるとよいでしょう。