大規模データの解析などで注目を集める「NoSQL」。海外のActiveReportsのお客様からは、すでにNoSQLデータベースとの連携方法についていくつか問い合わせをいただいており、今後は日本国内でも需要の増加が予想されます。
今回はMicrosoft AzureのNoSQLデータベース「Azure Cosmos DB」とActiveReportsの連携方法の一例をご紹介します。
- Azure Cosmos DBとは
- 実装方法
- Azure Cosmos DBの作成
- アプリケーションへのライブラリの追加
- レポートファイルの作成
- Azure Cosmos DBとの連携処理の実装
- 実行結果
Azure Cosmos DBとは
Azure Cosmos DB は、Microsoft Azure が提供するNoSQL データベースのPaaSです。詳細は公式ブログの記事が参考になります。
Cosmos DB ことはじめ – Microsoft Japan Data Platform Tech Sales Team Blog
かつては同様のサービスとしてAzure DocumentDBがありましたが、2017年5月より名称がAzure Cosmos DBに変更され、DocumentDB以外にも「MongoDB API」、「Graph API」、「テーブル API」など複数のAPIをサポートしたマルチモデルの分散データベースになりました。今回はそのうちのDocumentDB APIとの連携方法を紹介します。
実装方法
Microsoft Azureのデータベースといえば、RDBMSの「Azure SQL Database」の方が有名かと思いますが、こちらにはActiveReportsが提供するネイティブの「Microsoft SQL Client Provider」を使用して接続できます。
一方、Azure Cosmos DBとの接続用のドライバーは現在提供しておりませんが、DocumentDBのデータ(ドキュメント)はJSON形式なので、JSONデータさえ取得してしまえば、あとは先日公開した記事でも紹介した「JSONデータソース」の機能を応用し、実行時にLocateDataSourceイベントを経由して、レポートにデータを供給できます。
全体の流れを簡単にまとめると以下のようになります。
- Azure Cosmos DBへの接続用クライアントのインスタンスを作成する
- クライアントのインスタンスからDBへクエリを実行し、JSONデータを取得する
- 取得したJSONデータを、ActiveReportsのJSONデータソースが読み込めるよう、1つのJSONデータに成型する
- LocateDataSourceイベントから、成型したJSONデータをレポートのデータソースのデータとして供給する
※LocateDataSourceイベントは、レポートの生成時に、使用するデータが見つからない場合に発生するイベントです。アンバウンドレポート(レコードを取得するためにデータソースを必要としないレポートのこと)において、実行時に外部のデータと接続する場合に使用します。
<参考情報>
実行時のレポートとデータソースの連結
JSONデータを使ったレポート
Azure Cosmos DBの作成
まずはAzure Cosmos DBを作成します。Azureのポータルから「Azure Cosmos DB」を選択し、「Azure Cosmos DBの作成」をクリックします。サービスの一覧に表示されない場合は、「その他のサービス」から検索できます。
次にIDやAPIの設定などを行っていきます。「ID」にはユニークなIDを(今回は「ActiveReports-cosmosdb」としています)。「API」には「SQL (Document)」を。リソースグループは、既存のものがあればそれを指定してもいいですが、今回は「cosmosdb-group」というリソースグループを新規作成します。そのほか、「サブスクリプション」や「場所」は、自身の環境にあわせて設定してください。最後に「作成」をクリックするとデプロイメントが始まります。
デプロイメントが完了すると、以下のようにCosmos DBのアカウントが作成されるので、「コレクションの追加」をクリックして、コレクションの作成に進みます。
「コレクション ID」、「スループット」、「データベース」の入力項目を埋め(今回はそれぞれ、「TestCollection」、「400」、「TestDB」としています。)、「作成」をクリックします。
「データ エクスプローラー」を開いて、登録されたコレクションを確認します。先ほど登録したデータベースとコレクションは以下のような階層構造になります。これらにさらにドキュメント(データ)がぶら下がる形になります。まだドキュメントは登録されていないので、「New Document」をクリックして、GUIからデータの登録を行っていきます。(なぜかデータ エクスプローラーのUIは英語です。)(実運用では、ドキュメントはAPIなどを使って登録するのがよいでしょう。)
ドキュメントはJSON形式で保存されます。各ドキュメントには「id」を設定する必要があります。(設定しない場合は自動で採番されます) 今回は以下のような売上データをJSON化したものを登録してみます。
[ { "id": "1", "CustomerID": "1", "Products": "コーヒー 250 ml", "Number": 100, "UnitPrice": 100, "BillNo": "WS-DF502", "Date": "2003-09-05T00:00:00", "SlipNo": "GB465", "EndDate": "2003-09-30T00:00:00", "CustomerName": "長崎カントリーフーズ" }, { "id": "2", "CustomerID": "1", "Products": "紅茶 350 ml", "Number": 300, "UnitPrice": 120, "BillNo": "WS-DF502", "Date": "2003-09-05T00:00:00", "SlipNo": "GB465", "EndDate": "2003-09-30T00:00:00", "CustomerName": "長崎カントリーフーズ" }, { "id": "3", "CustomerID": "1", "Products": "炭酸飲料 (オレンジ) 350 ml", "Number": 200, "UnitPrice": 120, "BillNo": "WS-DF502", "Date": "2003-09-05T00:00:00", "SlipNo": "DK055", "EndDate": "2003-09-30T00:00:00", "CustomerName": "長崎カントリーフーズ" }, { "id": "4", "CustomerID": "2", "Products": "ボールペン (赤)", "Number": 50, "UnitPrice": 100, "BillNo": "WA-GJ419", "Date": "2003-09-04T00:00:00", "SlipNo": "PI198", "EndDate": "2003-09-30T00:00:00", "CustomerName": "(有)デジタルノロシネット" }, { "id": "5", "CustomerID": "2", "Products": "ボールペン (青)", "Number": 100, "UnitPrice": 100, "BillNo": "WA-GJ419", "Date": "2003-09-13T00:00:00", "SlipNo": "TA471", "EndDate": "2003-09-30T00:00:00", "CustomerName": "(有)デジタルノロシネット" } ]
以下のようにJSONデータを入力します。ポータルからのドキュメントの登録は1件ずつ行うことになるので、「id」が「1」のJSONデータだけを入力し、「Save」をクリックして保存します。
同様に「id」が「2」~「5」のJSONデータも登録します。登録したデータは「ドキュメント エクスプローラー」や「クエリエクスプローラー」で確認できます。
以上でAzure Cosmos DB側の設定は完了です。
アプリケーションへのライブラリの追加
次にAzure Cosmos DBから取得したデータを、ActiveReports の帳票上に表示するアプリケーションを作成してみたいと思いますが、まずはプロジェクトを作成し、接続に必要なライブラリを追加します。
Visual Studio 2017を開き、「Visual C#」⇒「Reporting」のテンプレートから「ActiveReports 11.0J ページレポートアプリケーション」を選択します。プロジェクト名は「AzureCosmosTest」とします。
ソリューションエクスプローラーで、プロジェクトを右クリックし、[NuGet パッケージの管理] をクリックします。
NuGet パッケージマネージャーのウィンドウが開いたら、 [参照] をクリックし、検索ボックスに「azure documentdb」と入力し、「Microsoft Azure DocumentDB」を選択し、[インストール] をクリックします。
ソリューションの変更に関する確認と、ライセンスの同意に関する確認が表示されるので、それぞれ「OK」と「同意する」を をクリックします。以上で必要なライブラリがプロジェクトに追加されますが、この時追加される「Newtonsoft.Json」のバージョンが「6.0.8」になります。
ActiveReportsのdllも内部で「Newtonsoft.Json」を参照しているのですが、そちらは「7.0.1」を参照しているため、実行時にエラーが発生します。問題を回避するため、NuGet パッケージマネージャーから「インストール済み」をクリックし、「Newtonsoft.Json」のバージョンを「7.0.1」に更新してください。
※最新のバージョンをインストールすることもできますが、その場合はApp.configの中で、使用するバージョンに合わせてbindingRedirectの設定が更新されていることを確認してください。
<dependentAssembly> <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" /> <bindingRedirect oldVersion="0.0.0.0-10.0.0.3" newVersion="10.0.0.3" /> </dependentAssembly>
レポートファイルの作成
次にレポートファイルの作成を行います。プロジェクトを作成したときに自動生成されたPageReport1.rdlxを開き、「レポートエクスプローラ 11.0J」から「データソース」を右クリックし、「データソースの追加」を選択します。 (レポートエクスプローラが表示されていない場合は、「表示」-「その他のウィンドウ」-「ActiveReports 11.0J レポートエクスプローラ」のメニューから開けます。)
「レポートデータソース」ダイアログで、「種類」に「Json Provider」、「JSONスキーマのソースの選択」に「埋め込み」を選択し、以下のJSONスキーマを入力し、「OK」をクリックすると「DataSource1」というデータソースが作成されます。 (本来であればここでJSONデータの設定も行うのですが、後ほどアプリケーション側でCosmosDBから取得したJSONデータを渡すので、今は省略します。)
{ "definitions": {}, "$schema": "http://json-schema.org/draft-06/schema#", "type": "array", "$id": "http://example.com/example.json", "items": { "type": "object", "$id": "http://example.com/example.json/items", "properties": { "id": { "type": "string", "$id": "http://example.com/example.json/items/properties/id" }, "CustomerID": { "type": "string", "$id": "http://example.com/example.json/items/properties/CustomerID" }, "Products": { "type": "string", "$id": "http://example.com/example.json/items/properties/Products" }, "Number": { "type": "integer", "$id": "http://example.com/example.json/items/properties/Number" }, "UnitPrice": { "type": "integer", "$id": "http://example.com/example.json/items/properties/UnitPrice" }, "BillNo": { "type": "string", "$id": "http://example.com/example.json/items/properties/BillNo" }, "Date": { "type": "string", "$id": "http://example.com/example.json/items/properties/Date" }, "SlipNo": { "type": "string", "$id": "http://example.com/example.json/items/properties/SlipNo" }, "EndDate": { "type": "string", "$id": "http://example.com/example.json/items/properties/EndDate" }, "CustomerName": { "type": "string", "$id": "http://example.com/example.json/items/properties/CustomerName" } } } }
次に「レポートエクスプローラ 11.0J」から「DataSource1」を右クリックし、「データセットの追加」を選択します。
「データセット」ダイアログで、「クエリ」ページからJSONクエリデザイナの編集ボタンをクリックし、「JSONクエリデザイナ」を開きます。[*]にカーソルを合わせダブルクリックし、「$.[*]」というクエリが作成されたら、「OK」をクリックしてダイアログを閉じます。
完了するとデータセットにフィールドが追加されます。
あとはデザイナ上にコントロールを配置して、レポートをデザインしていきます。データ連結する項目には先ほど作成したデータセットのフィールドを設定します。今回は以下のような請求書のレイアウトを作成しました。(本記事の最後で、作成したサンプルプロジェクトを公開しています。)
Azure Cosmos DBとの連携処理の実装
Form1.csを開き、先頭に以下の参照を追加します。
using System.Linq; using Microsoft.Azure.Documents.Client; using Newtonsoft.Json;
次にForm1のコンストラクタの上に、以下の定数/変数を定義します。「EndpointUrl」と「PrimaryKey」には、それぞれの環境のエンドポイントURLとプライマリキーを設定してください。これらはAzureのポータルから作成したAzure Cosmos DBのアカウントを開き、「キー」のページから確認できます。
private const string EndpointUrl = "https://activereports-cosmosdb.documents.azure.com:443/"; private const string PrimaryKey = "<primary key>"; private DocumentClient client;
Form1.csにAzure Cosmos DBに格納したオブジェクトを扱うためのクラスを追加します。
public class SalesData { [JsonProperty(PropertyName = "id")] public string Id { get; set; } public string CustomerID { get; set; } public string Products { get; set; } public int Number { get; set; } public int UnitPrice { get; set; } public string BillNo { get; set; } public DateTime Date { get; set; } public string SlipNo { get; set; } public DateTime EndDate { get; set; } public string CustomerName { get; set; } public override string ToString() { return JsonConvert.SerializeObject(this); } }
Form1.csにクエリの実行およびデータ成型の処理と、LocateDataSourceイベント発生時のイベントハンドラを追加します。
private string GetData(string databaseName, string collectionName) { this.client = new DocumentClient(new Uri(EndpointUrl), PrimaryKey); IQueryable<SalesData> SalesDataQuery = this.client.CreateDocumentQuery<SalesData>( UriFactory.CreateDocumentCollectionUri(databaseName, collectionName), null); // クエリの実行 // 取得したJSONデータを、ActiveReportsのJSONデータソースに読み込めるように成型する string AllData = ""; foreach (SalesData Data in SalesDataQuery) { AllData = (AllData != "") ? AllData = AllData + ",": AllData; AllData = AllData + Data.ToString(); } AllData = "[" + AllData + "]"; return AllData; } private void OnLocateDataSource(object sender, GrapeCity.ActiveReports.LocateDataSourceEventArgs args) { object data = null; var dataSourceName = args.DataSourceName; if (dataSourceName == "DataSource1") { data = GetData("TestDB", "TestCollection"); } args.Data = data; }
最後にForm1_Loadイベントの中身を以下のように書き換えます。
private void Form1_Load(object sender, EventArgs e) { var rptPath = new System.IO.FileInfo(Application.StartupPath + @"\..\..\PageReport1.rdlx"); var definition = new GrapeCity.ActiveReports.PageReport(rptPath); // LocateDataSourceイベントにイベントハンドラを関連付けします。 definition.Document.LocateDataSource += OnLocateDataSource; viewer1.LoadDocument(definition.Document); }
実行結果
プロジェクトを実行すると、ActiveReportsのビューワ上にレポートが表示されます。一覧に表示されているデータはAzure Cosmos DBから取得したものです。また今回実装方法の説明は省略していますが、データの読み取り先のリージョンの情報を赤字でレポートのヘッダに表示しています。もしレプリケーションを行っていれば、ConnectionPolicy.PreferredLocationsプロパティから読み取り先のリージョンを指定するこも可能です。もし興味がありましたらサンプルの中のソースコードで説明しているのでご覧ください。
記事で作成したプロジェクトはこちらで公開しています。 実行前にNuGetパッケージの復元と、DBへの接続情報の変更を行ってください。