redwarrior’s diary

C#, ASP.NET, WEB, G*などの雑多な情報

ASP.NET MVCでjQuery DataTablesを使用する

何番煎じなのかわかりませんが、jQuery DataTablesを使ってみたので、メモを残しておきます。試したバージョンは、1.10.12。

公式サイト:

datatables.net

ASP.NET MVCでは、NuGetを使用して導入します。jQueryはバージョン2系でも問題ありませんでした。バージョン3系は試していません。

www.nuget.org

基本的な使い方

thead、tbodyタグで作成したテーブルのtableタグにid属性(mytable)を設定し、画面上もしくは外部のjsファイルで、以下のようにidを指定してDataTableメソッド呼び出すだけです。

$(function () {
    $('#mytable').DataTable();
});

ASP.NET MVCでは、jsファイルやcssファイルはバンドル機能を使って配布されるので、BundleConfig.csに追記しないと参照できません。

bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include(
          "~/Scripts/bootstrap.js",
          "~/Scripts/respond.js",
          "~/Scripts/DataTables/jquery.dataTables.js",      //←追加
          "~/Scripts/DataTables/dataTables.bootstrap.js")); //←追加

bundles.Add(new StyleBundle("~/Content/css").Include(
          "~/Content/bootstrap.css",
          "~/Content/DataTables/css/dataTables.bootstrap.css", //←追加
          "~/Content/site.css"));

日本語化

CDN上のファイルを参照する方法が良く紹介されていますが、社内システム等で外部へのアクセスを避けたい場合もあるので、CDNを使わない方法で行きます。

先ほどのDataTableメソッドの前に以下を記述することで、デフォルトメッセージを日本語で上書きします。

    // デフォルトの設定を変更
    $.extend($.fn.dataTable.defaults, {
        language: {
            "sEmptyTable": "テーブルにデータがありません",
            "sInfo": " _TOTAL_ 件中 _START_ から _END_ まで表示",
            "sInfoEmpty": " 0 件中 0 から 0 まで表示",
            "sInfoFiltered": "(全 _MAX_ 件より抽出)",
            "sInfoPostFix": "",
            "sInfoThousands": ",",
            "sLengthMenu": "_MENU_ 件表示",
            "sLoadingRecords": "読み込み中...",
            "sProcessing": "処理中...",
            "sSearch": "検索:",
            "sZeroRecords": "一致するレコードがありません",
            "oPaginate": {
                "sFirst": "先頭",
                "sLast": "最終",
                "sNext": "次",
                "sPrevious": "前"
            },
            "oAria": {
                "sSortAscending": ": 列を昇順に並べ替えるにはアクティブにする",
                "sSortDescending": ": 列を降順に並べ替えるにはアクティブにする"
            }
        }
    });
    $('#mytable').DataTable();

sSearchの値が、検索テキストボックスの左側の文字列ですが、画面よって変えたい場合もあると思います。その場合は、DataTableメソッド呼び出し時の引数で指定することが出来ます。

    $('#mytable').DataTable({
        language: {
            "sSearch": "絞り込み:"
        }
    });

列の設定

特定の列を検索対象から外したり、ソートできないようにしたり、非表示にしたりしたい場合は、columnDefsというプロパティに設定します。

    $('#mytable').DataTable({
        language: {
            "sSearch": "絞り込み:"
        },
        columnDefs: [
            //targetsは0始まり
            { targets: 0, width: 43, searchable: false, orderable: false }, //1列目 検索対象外、ソート不可
            { targets: 1, width: 85, orderable: false }, //2列目 検索対象、ソート不可
            { targets: 2, visible: false }, //3列目 非表示
        ]
    });

パフォーマンスについて

HTMLを全て読み込んだ後、JavaScriptでページネーションや検索の制御をしているため、表示するレコード数が多いほど遅くなります。

試してみたところ12列の表で、1000行くらいまでがストレスなく表示できる感じでした。

以上です。

SQL ServerのCHECK制約の設定方法

簡単な入力制限であれば、テーブルにCHECK制約をつける手もあるかなと思い、SQL ServerのCHECK制約の設定方法について調査しました。

SSDT(サーバーエクスプローラー)
  • SSDTは、テーブル定義画面でCHECK 制約を追加できる。
  • CHECK制約の対象カラムは、カラムを選択した時に、CHECK制約がハイライトされる。
  • CHECK制約は、CREATE TABLEのCONSTRAINT句で記述する。
    SQLにALTER TABLEを書いても実行できたが、テーブル定義画面を閉じて開くとCREATE TABLE文に戻ってしまった。
SSDT(オブジェクトエクスプローラー)
  • テーブル定義画面を開く前に、制約だけを開くと、ALTER TABLE形式のSQLが表示される。
SSMS
  • デザイン画面では、CHECK制約は表示されない。
  • 制約を開くと、制約編集用の画面が表示される。
  • 「テーブルをスクリプト化」で、ALTER TABLE形式のSQLが表示される。
  • 制約に対して「制約をスクリプト化」をしてもALTER TABLE形式のSQLが表示される。
Code First(Entity Framework 6.2)
  • CHECK 制約を記述出来ないため、DBを再作成するとCHECK 制約は消える。
  • CHECK 制約を設定したい場合は、DBInitilizerクラスで、DB再作成後にALTER TABLE形式のSQLを実行する必要がある。

以上

(まとめ)Redmineチケットの帳票出力にSSRSを使用する

これまで書いてきた記事を読めば、Redmineチケットの帳票出力にSQL Server Report Services(SSRS)を使用する事が出来ます。

出来る事ならRedmineのワークフローを使用して、Web上(Redmine上)で完結する事が望ましいのでしょうが、そうも行かない事もあると思います。

そんな時に、Redmineを使用するのをあきらめてしまうのではなく、紙と併用して使っても良いのではないかと思いました。

RedmineのPDF作成機能や、ブラウザによる印刷では、レイアウトの調整は出来ないので(view customize pluginで印刷用にゴリゴリ画面を書き換えたくは無いですよね?)、何か良い方法はないかと思いたどり着きました。

後から参照しやすいように、各記事へのリンクをまとめます。

  1. SQL Server Reporting Services(SSRS)のデータソースで外部サービスを設定する - redwarrior’s diary

  2. SSRSのデータセットにRedmineのチケット情報を読み込む - redwarrior’s diary

  3. SSRSのコンポーネントで条件を指定して、同じデータセットからレコード別の値を取得する - redwarrior’s diary

チケット内容の出力であれば、テキストボックスが主になるので上記で済むと思いますが、一覧を使用したい場合は以下を参照してください。

SSRSで表や、一覧を使用してデータセットの内容を一覧表示する - redwarrior’s diary

以上。

SSRSで表や、一覧を使用してデータセットの内容を一覧表示する

前回の記事で、テキストボックスにデータセットの値を表示しました。

今回は、データセットのレコードを繰り返し表示する方法として、SQL Server Reporting Services(SSRS)のコンポーネントである表(テーブル)と一覧の 使い方を紹介します。

公式サイトは以下の通りです。

docs.microsoft.com

上記を既に読んでいるのであれば、ここから先を読んでもあまり得るものはないでしょう。ただ公式は情報量が多くて読み通すのに時間がかかるため、最低限のざっくりした内容を書きたいと思います。

SSRSの表(テーブル)の使い方について

表(テーブル)は、データセットのレコードを最も簡単に繰り返し表示できるコンポーネントです。

表(テーブル)を配置したらセルの右上のアイコンをクリックして、データソース、データセット、カラムを順番に選択します。列を追加した場合は、データセットのカラムを選択するだけです。

f:id:redwarrior:20190712114159p:plain
コンポーネント

列の挿入・削除、見出し行(ヘッダー)や行の挿入・削除も右クリックメニューで行う事ができます。

これでデータセットのレコード数だけ行が表示されます。

SSRSの一覧の使い方について

名前だけで考えると表よりも一覧の方が単純そうに感じますが、SSRSではそうでもありません。配置しただけでは、表コンポーネントのようにカラムを選択するアイコンは出てきません。

一覧は、繰り返し表示する中身を自由にレイアウトする事ができるコンポーネントです。一覧で表示されたエリアに、テキストボックスや表を自由に配置した後、テキストボックス/表の値としてデータセットのカラムの選択ができます。

f:id:redwarrior:20190712120110p:plain
一覧コンポーネント

選択したデータセットのレコード数だけレイアウトした内容で行が表示されます。

まとめ

データセットのレコードを繰り返し表示する方法として、「表」と「一覧」を紹介しました。 集計機能が不要で、一覧形式で表示したいだけであれば「表」と「一覧」だけで十分なので、「マトリックス」は使用していません。

以上です。

(追伸)記事を書くために調べた所、「表」のセル内に「表」や「一覧」や「テキストボックス」を埋め込んで自由にレイアウトができる事がわかりました。

SSRSのコンポーネントで条件を指定して、同じデータセットからレコード別の値を取得する

前回の記事では、データセットのフィルターを使用してカスタムフィールドを絞り込むという方法を紹介しましたが、

カスタムフィールドの値を表示するテキストボックスを複数用意して、それぞれ別のカスタムフィールドの値を表示したい

f:id:redwarrior:20190629113135p:plain
複数カスタムフィールド

という場合は、カスタムフィールドの数だけデータセットが必要になってしまいます。

そしてデータセット毎にデータを取得するため、データセットが外部サービスを参照している場合、データセットの数だけリクエストが発生します

これは出来れば避けたい。どうすれば良いでしょうか?

データセットでフィルターを使用せず(複数レコードのまま)に、コンポーネントで式を使用し、条件を指定して値を取得すると良いです。

具体例

例えばテキストボックスの場合、テキストボックスの中ではなく、テキストボックス全体を選択すると右クリックメニューに式が表示されます。そこで式を選択すると式の入力画面になります。*1

式では関数を使用して、レコードを絞り込むことが出来ます。主に使うのは、First関数とLookup関数。

First関数

データセットにレコードが1件しか含まれていない場合や、先頭のレコードだけで良い場合は、First関数を使用します。

=First(Fields!value.Value, "データセット名")

第1引数=値に使用するカラム(value)、第2引数=対象のデータセット

Lookup関数

条件を指定してレコードを取得するのには、LookUp関数を使用します。カスタムフィールドをidで絞り込み、入力値(value)を表示したい場合は、以下のように記述します。

=Lookup("1",Fields!id.Value,Fields!value.Value, "データセット名")

第1引数=条件値(idカラムの値)、第2引数=条件に使用するカラム(id)、第3引数=値に使用するカラム(value)、第4引数=対象のデータセット

データセット名を同じ値にして、テキストボックスごとにidの値を変更することで、同じデータセットを使用しつつ、それぞれ別のカスタムフィールド値を表示することが出来ました。

以上。

*1:テキストが既に入力されていると式を入力する事が出来ないのでテキストは空にしておきます。

SSRSのデータセットにRedmineのチケット情報を読み込む

前の記事で、データソースにRedmine Rest Api を指定したので、これを使用して、データセットにチケット情報を読み込む方法を調査しました。Visual Studio上でプレビューして動作を確認しています。

検証環境

データセットの読み込み

実は、データソースに指定したURLが、チケット番号を指定して情報を取得するAPIのURLなので、データセットではデータソースを選択するだけで、いくらかの情報は取得できます。

しかし、余分な情報はデータセットの時点で削っておきたい!XMLデータの場合は、SQLの代わりに要素パス構文というのを使用します。

docs.microsoft.com

詳しい内容は、リンク先を読んでもらうとして、今回は「カスタムフィールドの一覧を取得する」データセットと「チケットのステータスを取得する」データセットの二つを作成しました。

カスタムフィールドの一覧を取得する

要素パス構文で記述したクエリ

issue {}/custom_fields {}/custom_field {@id,@name}/value

実行結果(カスタムフィールド数分表示される)

id name value
1 カスタムフィールド名A カスタムフィールド値1
2 カスタムフィールド名B カスタムフィールド値2
チケットのステータスを取得する

要素パス構文で記述したクエリ

issue {id,subject,created_on,updated_on}/status {@name}

実行結果

id subject created_on updated_on name
100 チケット名1 チケット作成日時 チケット更新日時 ステータス値

データの絞り込み

チケットのステータスを取得するクエリは、1レコードしか返ってこないけれど、カスタムフィールドの一覧を取得するクエリは複数レコード返ってきます。1つのカスタムフィールドの値を取得したい場合もあるでしょう。

要素パス構文には、条件による絞り込みの機能は無さそうなので、この場合、データセットのフィルターを使用します。データセットのプロパティからフィルターを開いて「id = 数値」のように指定して絞り込む事が出来ます。

以上です。

.NET CoreのコンソールアプリケーションでEntity Framework Coreを使用しSQL Serverに接続する

Visual Studio 2019 も出てきて、これからは.NET Coreでの開発が進んで行くと思うのでキャッチアップのために.NET Coreプロジェクトを使い始めています。

.NET CoreプロジェクトでDBを扱うとなったら、当然Entity Framework Coreを使います。公式サイトはそれなりに充実しています。

docs.microsoft.com

しかし、コンソールアプリケーションでEntity Framework Coreを使用して新しいデータベースを作成する方法が、SQLiteを使った例になっているため、.NET CoreのコンソールアプリケーションでEntity Framework Coreを使用し、SQL Server LocalDBに接続する方法を調べました。

色々と参照しながら試したので、参考サイトはまとめていません。

パッケージのインストール

まずは、NuGetパッケージのインストールです。Entity Framework CoreでSQL Serverを使用するには、Microsoft.EntityFrameworkCore.SqlServerをインストールします。SQL Server LocalDBもこのパッケージで対応しています。

必要なクラスの作成

次に、DbContextクラスを継承したクラス(コンテキストクラス)と、EntityとなるPOCOクラスを作成します。これは公式の例と一緒です。
コンテキストクラスでOnConfiguringメソッドをオーバーライドして、パラメータとして受け取ったDbContextOptionsBuilderクラスのUseSqlServerメソッドを呼び出し、パラメータとしてDBへの接続文字列を渡します。

SQL Server LocalDBへの接続文字列

Entity Frameworkとは接続文字列の書式が異なっていて、Server, Database, Trusted_Connectionを設定するようです。以下は、SQL Server LocalDBへの接続文字列の例です。

Server=(localdb)\mssqllocaldb;Database=(データベース名);Trusted_Connection=True

Entity Frameworkで使えたAttachDbFilenameは、Entity Framework Coreでも使えるようです。

Server=(localdb)\mssqllocaldb;Database=(データベース名);Trusted_Connection=True;AttachDbFilename=(mdfファイルを作成するパス)
データベースの新規作成

今回はマイグレーションを使用して、データベースを作成します。公式の例はコマンドプロンプト?で作業をしていますが、ここではVisual Studioを使います。
Visual Studioを使うと言っても、GUIなメニューはないため、パッケージマネージャーコンソールを開いてコマンドを実行します。

Microsoft.EntityFrameworkCore.ToolsをNuGetでインストールします。これによってパッケージマネージャーコンソールで必要なコマンドが追加されます。

以下のコマンドを実行すると、マイグレーション用のクラスが作成されます。

Add-Migration InitialCreate

以下のコマンドを実行すると、データベースが作成されます。

PM> Update-Database
データベースに接続する

ここまで来れば、Entity Frameworkと同じように使うことが出来ます。公式の例そのままで動きます。

以上です。