LINQ to SQLite で共通カラム部分をジェネリックで運用する

LINQ to SQLite を使っている中で、複数のテーブルに共通するカラム(列)がある場合、ヘルパー関数などをそれぞれのテーブルごとに手書きするのは大変だしメンテナンス性も悪い。ひとまとめにできないだろうか、というのを試行錯誤した結果、インターフェース+ジェネリックでいけることが分かったので整理しておく。

なお、LINQ to SQLite の基本的な事柄については「C# で SQLite を便利に使うサンプルコード(LINQ to SQLite)」を参照。

テーブル構造

フルーツの一覧を格納するフルーツテーブルと、肉の一覧を格納する肉テーブルがあるとする。フルーツテーブルと肉テーブルそれぞれのカラムのうち、ID と名前については両者共にカラムがあるものとする。

この場合、テーブル構造を定義するクラスは以下のようにする。

まず、共通カラム部分をインターフェースとしてまとめる。
public interface IFoodData
{
    // ID
    Int32 Id { get; set; }

    // 名前
    String Name { get; set; }
}

そのうえで、テーブル構造を定義するクラスにインターフェースを実装するようにする。例えばフルーツテーブルなら
[Table(Name = "t_fruit")]
public class TFruitData : IFoodData
{
    // --------------------------------------------------------------------
    // IFoodData 実装
    // --------------------------------------------------------------------

    // ID
    [Column(Name = "fruit_id", DbType = LinqUtils.DB_TYPE_INT32, CanBeNull = false, IsPrimaryKey = true)]
    public Int32 Id { get; set; }

    // 名前
    [Column(Name = "fruit_name", DbType = LinqUtils.DB_TYPE_STRING, CanBeNull = false)]
    public String Name { get; set; }

    // --------------------------------------------------------------------
    // TFruitData 独自項目
    // --------------------------------------------------------------------

    // 色
    [Column(Name = "fruit_color", DbType = LinqUtils.DB_TYPE_STRING, CanBeNull = true)]
    public String Color { get; set; }
}

のようにする。

共通カラムの操作

フルーツテーブルと肉テーブルに共通するカラム(ID、名前)について、操作をジェネリックでまとめることができる。例えば、名前でレコードを検索・表示する関数は以下のようになる。
private void QueryFoodByName<T>(String oKeyword) where T : class, IFoodData
{
    Console.WriteLine(LinqUtils.TableName(typeof(T)) + " 内で名前に「" + oKeyword + "」を含むレコードを検索");
    using (SQLiteConnection aConnection = CreateDatabaseConnection(DB_NAME_GENERIC))
    using (DataContext aContext = new DataContext(aConnection))
    {
        Table<T> aTableTest = aContext.GetTable<T>();
        IQueryable<T> aQueryResult =
                from x in aTableTest
                where x.Name.Contains(oKeyword)
                select x;
        Console.WriteLine("検索結果:" + aQueryResult.Count() + " 件");
        foreach (T aRecord in aQueryResult)
        {
            Console.WriteLine(aRecord.Name);
        }
    }
}

関数を呼びだす際は、
QueryFoodByName<TFruitData>("hoge");
QueryFoodByName<TMeatData>("fuga");

のようにする。

以上により、テーブル名が異なる複数のテーブルに共通するカラムの操作を、1 つのコードにまとめることができた。

継承でやってはどうか?

テーブル構造を定義するクラスを、インターフェースではなく継承で作るのはどうだろうか。

つまり、IFoodData をインターフェースではなく通常のクラスとして宣言してそれを基底クラスとし、TFruitData や TMeatData をそこから派生させる形にする。

しかし残念ながらそれはうまくいかなかった。

データベース内にテーブルを作成する段階で、「型 'TestLinqToSqlite.IFoodData' のデータ メンバー 'Int32 Id' は型 'TFruitData' のマッピングの一部ではありません。メンバーは継承階層のルートより上のメンバーですか?」というようなエラーが発生してしまう。

サンプルコード

以上をまとめたものを、サンプルコードとして公開する。

サンプルコードアプリの使い方

  • TestLinqToSqlite_Genericジェネリックの「DB 作成」ボタンをクリックすると、フルーツテーブルと肉テーブルを持つデータベースが作成される。
  • 「検索」ボタンをクリックすると、フルーツテーブルと肉テーブルそれぞれから検索が行われ、結果がコンソールに表示される。なお、検索はジェネリックを使用した 1 つのコードで行われている。
なお、サンプルコードアプリには基本操作の欄もあるが、こちらについては「C# で SQLite を便利に使うサンプルコード(LINQ to SQLite)」を参照。

参考資料

更新履歴

  • 2019/04/09 初版。






















ゆかりすたー METEOR Ver 1.50 β 公開

Meteorゆかりすたー METEOR(メテオ)の新バージョン、Ver 1.50 β を公開しました。

ゆかりすたー METEOR はニコカラ動画ファイルを整理し、「ゆかり」(持ち込みカラオケ用のブラウザリクエストツール)から検索できるようにするツールです。データベースを活用することにより、タイアップしている番組名や歌手名などの付加情報を含めて整理するので、単なるファイル名検索にとどまらない高い検索性を提供することができるようになります。

ゆかりすたー METEOR は、ニコカラりすたーおよび初代ゆかりすたーの後継ソフトとして開発しています。ニコカラりすたーは一時点でのリスト化機能のみを提供していましたが、ゆかりすたー METEOR は、ゆかりと連携した高度な検索性の提供を目的に、リアルタイムでのリスト化機能と検索用データベース構築機能を提供します。

更新内容

HTML 系リストの利便性を強化しました。上部のディレクトリーナビゲーションを改善し、また、下部には隣のリストへのリンクを付けました。さらに、ゆかり用リストには、予約一覧ページへのリンクも付けました。

ファイル一覧ウィンドウでの検索ウィンドウに関する挙動も改善しています。

その他、細かい改善をしています。今回の更新内容を含む課題対応履歴についてはこちらをご覧ください。

Windows Defender について

Windows Defender がゆかりすたー METEOR の動作に悪影響を及ぼす場合があり、エラーが発生したり、処理速度が異常に遅くなったりする例が報告されています。

ゆかりすたー METEOR を使う際は、Windows Defender を使わないことをお薦めします。

詳細についてはこちらをご覧ください。

更新・新規インストール方法

ゆかりすたー METEOR は自動更新機能を搭載しています。既にゆかりすたー METEOR をお使いの方は、ゆかりすたー METEOR を起動すると、3 日以内に更新のアナウンスが表示されます。

すぐにアップデートしたい場合は、環境設定ウィンドウのメンテナンスタブを開き、「今すぐ最新情報を確認する」ボタンをクリックすることで、アップデートを開始することができます。

Ver150to168右のようなダイアログが表示されますので、「はい。今すぐ更新します」をクリックしてください。

ゆかりすたー更新版インストール画面に案内が表示されますので、案内に従って操作をして下さい。

ゆかりすたー更新完了ほどなくして、ゆかりすたー METEOR の更新が完了します。

これから初めてゆかりすたー METEOR を使う方(新規の方)や、手動でゆかりすたー METEOR を更新したい方は、下記サイトからどうぞ。

旧作について

ニコカラりすたーおよびゆかりすたー(初代)は開発を終了しました。

今後はゆかりすたー METEOR をご利用下さい。

フォームから WPF に移行して分かったメリット・デメリット

.NET Framework(C#)での開発のベースとなるフォーム(Windows Forms)と WPF(Windows Presentation Foundation)。後発の WPF の方が優れていてしかるべきなのに、登場からずいぶん経ったわりにはイマイチ普及が進んでないようにも見受けられる。使いづらいの?

というわけで、実際に 1 つのプロジェクト(ゆかりすたー METEOR)をフォームから WPF に移行したり、色々実験したりして分かった、フォームと WPF それぞれの良いところを整理してみた。

ゆかりすたー METEOR のフォームと WPF でのソースコード上の差分は GitHub の diff で確認できる。

WPF のほうが良いところ

フォームのほうが良いところ

まとめ

UI コントロールのフロー配置

まずは WPF の良いところから。

WPF では、ウィンドウにボタンなどのコントロールを配置する際の考え方が根本的にフォームとは違う。フォームではマウスでポチポチコントロールを置いていく(手動で位置決めをする)が、WPF は「流し込む」ようなイメージに近い。

Buttons例えばボタンを 3 つ配置する場合、右の図のように、1 つ目のボタンはウィンドウの上に自動的に吸い付く(もちろんマージン(隙間)は自由に設定できる)。2 つ目のボタンは 1 つ目のボタンに吸い付き、3 つ目のボタンは 2 つ目のボタンに吸い付く。

ボタンのサイズは自動調整される。ラベルの長さに合わせて良い感じのサイズになるのだが、そのままだと 2 つ目のボタンだけ横幅が広くて格好悪い。しかし、2 つ目のボタンに合わせて、1 つ目と 3 つ目のボタンの横幅が自動的に広がってくれるので、良い感じのレイアウトになる。

例えば多言語対応したとして、日本語だと 2 が幅広だけど英語だと 1 が幅広、なんて場合でも、言語に関わらず 3 つともサイズが揃ってくれるので便利。WPF は高 DPI 環境でもレイアウトが崩れないと言われるのも、この自動調整機能をうまく使った場合だと思う。

この考え方は非常に良いと感じた。……考え方「は」。

現実はかなり不便。WPF もフォーム同様ビジュアル開発ができるのだが、マウスでポチポチコントロールを置いても、上記は実現されない。XML(風の XAML)を手打ちしてコントロールを作っていかなければならない。ビジュアル部分はプレビュー用途で使うのが関の山。しかもエディタが重い。

グリッドへの配置をしようものなら、グリッドの何マス目なのかを地道に手打ちしていくという地獄のような作業が待っている。

タブコントロールでは、アクティブなタブページに合わせてタブコントロールのサイズが変わるので、ページを切り替えるごとにウィンドウサイズも変わるという妙な動きになってしまう。ウィンドウサイズ固定にもできるが、そうすると自動調整の恩恵を受けられず、Windows 10 では良い感じのレイアウトなのに Windows 7 だとコントロールがはみ出したりする、なんていう事態になる。

また、考え方についても、CSS でいう Flexbox に近いのではないかと思うが、Flexbox ほどオプションが豊富でもなく(均等割り付けとかはできない)、発展途上の印象がある(しかも発展が止まってる)。

テーマで見た目を変えられる

ある意味一番分かりやすいメリットがこれ。

Placeデフォルトではフォームと見た目はほとんど同じだが、例えば MaterialDesignInXamlToolkit を使えば、今風のマテリアルデザインになる。テキストボックスにプレースホルダー(入力欄に事前に表示する灰色のヒント)を入れたりとか、フォーカスが当たった際の境界線のアニメーションとか、お手軽に実現できる。

データと UI の分離と関連付け

リストボックスやコンボボックスのような選択系のコントロールにおいて、フォームではリストのアイテムを 1 つ 1 つ追加していき、リストボックスそのものがデータの塊のようになっていた。

一方で WPF では、バックデータとなるデータ群(例えば List<String>)を予め用意しておき、リストボックスに丸投げすると、全データを一気に投入できる。さらに、List<String> の内容を変更(追加・削除・入れ替え等)すると、それがちゃんとリストボックスに反映される(Items.Refresh() 関数を呼ぶ)。

データはデータ、UI は UI と分けた上でそれらを関連付けることで、考え方がすっきりする。

データグリッドがスマート

前項とも密接に関わるが、データグリッドコントロール(System.Windows.Controls.DataGrid)がフォームの時(System.Windows.Forms.DataGridView)よりもスマートになっている。

フォームの時は、行数が多いと空行を追加するだけでものすごく時間がかかっていた。それを回避するには CellValueNeeded イベントなどを駆使して必要な時にだけデータを表示する仕掛けを組まねばならなかった。

WPF では、全データを投入しておいても、行が無駄に生成されることはなく、CellValueNeeded に相当する作業を自動でやってくれる。また、条件によって行の色を自動的に変えることも可能。

ただし、フォームより大幅に後退した部分もある。代表格が「クリックされたセルの位置が(簡単には)分からない」。フォームの時は DataGridViewCellEventArgs で行列位置を知れたが、WPF ではかなり複雑な手続き(こちらの GetDataGridCellPosition() 参照)を経ないと知ることができず、まったく直感的ではない。絶対必要な事なのに、なぜこんな仕組みにしたし……。

動画系の機能が強化されている

動画からサムネイル画像を作成することが比較的簡単に行える。こちらの CreateThumb() は 100 行くらいのコード。動画のコンテナやコーデックに関わらず、扱えるものなら何でもこれでいける。

WPF の描画関連の基本思想をまだ理解できておらず(分かりやすくまとめてあるところが見当たらず……)、また、動画から画像への転写が非同期に行われるようで、その捕捉に無駄なコードを書いてしまっているので、できれば改善したい。

UI コントールの配置が簡単・速い

ここからはフォームの良いところ。

フォームは UI を作るのが簡単で速い。先に述べたように、WPF は実質 XML 手打ちなのに比べて、マウスでどんどんポチポチするだけでいい。

EditSongWindowまた、例えば右のようなウィンドウを作るとして、WPF では「どのように流し込むか」完成形を予めイメージして(もしくはどこかに書いて)から考えて、それからでないと UI を作り始められないが、フォームはもっと気軽だ。「あ、これも追加しなきゃ」と場当たり的に追加しても、後からタブオーダーを簡単に変更できたりする。

また、ラベルにアクセラレータキー(&A とか)を設定しておけば、Alt+A を押したときに隣のテキストボックスにフォーカスがちゃんと当たるなど、長年の作り込みが素晴らしい。WPF はそんなことしてくれない。

非ビジュアルコントロールもマウスで配置可能

タイマーや各種ダイアログボックスなど、ウィンドウ上に配置されるわけではないコントロール(非ビジュアルコントロール)も、フォームはマウスでポチポチ配置したり、ダブルクリックでイベントハンドラーを作ったりできる。WPF はできない。

基本的な機能がきちんと揃っている

当たり前のことが当たり前にできる。そう、フォームならね。

しかし、WPF には基本的な機能すら欠けている。

例えば、フォルダー選択ダイアログが WPF には無い。かなり高頻度で使うパーツであるが、無いものは無い。仕方が無いので、別途ライブラリを使ったりしてしのぐことになる。

また、ウィンドウの右上のボタン群のうち、最小化だけさせない、というのも、フォームならプロパティー 1 つで簡単にできる。一方で WPF は、P/Invoke で Windows API を直接叩かなくてはならない。

マイナーな機能も結構揃ってる

フォームは、マイナーめな機能も意外と揃っている。

例えば、アプリケーション独自のメッセージを処理するための機構。フォームの場合、Form.WndProc() をオーバーライドするだけで良い。一方で WPF の Window クラスにはその仕組みはないため、いくつかのパーツを組み合わせて実現する必要がある。

マルチディスプレイ環境で、ディスプレイごとの領域もフォームなら取得できる。WPF はできない(全領域なら WPF でも取得できる)。例えば、ウィンドウが 2 枚目のディスプレイにいる場合、そのディスプレイの左端に吸い付く、というような動作を、WPF ではどうやって実現するのだろうか?

勉強量が WPF より少なくて済む

シンプルに考えて、WPF でアプリケーションを作ろうとする場合、プログラミング言語である C# に加えて、画面を作るための XML である XAML を勉強する必要がある。フォームは C# だけでいい。

日本語の情報が豊富

フォームに関する日本語の情報は豊富で、DOBON.NET などのウェブサイトを見れば多くの疑問は解決する。

一方で WPF のまとまった日本語情報というのは少ない。網羅的なウェブサイトが無いのが痛い。Tips も散在はしているが数が少ないのと、せっかく見つけても「とりあえずやってみたら動いた」というような感じで汎用性に疑問のあるページも多い。一番困るのは、WPF の考え方や概念について分かりやすくまとまった情報が無いこと。一番最初に挙げた「流し込む」ような UI 配置も理解するのに時間がかかったし、描画の仕組みなどはまだまったく理解できていない。

WPF では 1 つのことをやるために C# でコードを書くやり方と XAML でコードを書くやり方の 2 通りの実装方法があるが、片方しか掲載されていないこともしばしば。

WPF は英語含めても情報が見当たらない

フォームは日本語の世界で充足するが、日本語情報の少ない WPF は海外サイトも探す必要がある。……が、海外の情報もちゃんと見つけられていない……。

まとめ

後発の WPF は、フォームよりも洗練された考え方を元に設計されていると思う。そしてその「見どころ」には確かに、WPF を使いたくなるものである。

しかし、設計が煮詰まっていないのか、あるいは実装が追いついていないのか、実装する気が失せたのかは分からないが、「見どころ」以外の部分は実用レベルに達していないと言っても過言では無い。

現状は、「見どころ」を味わうために WPF を使って地獄を見るか、それとも堅実にフォームを使って「見どころ」を楽しめない残念さをかみしめるか、の 2 択になっている気がする。

しっかりと WPF の基本思想が周知されたうえで、細部にわたり WPF の実用性が高まると良いのだが……。10 年以上前に登場したのに今がこのような状況と言うことは、今後も改善しない可能性が高いのかもしれない……。

いろんな意味で手軽・スムーズに開発を進められるのは、フォームのほうだと思う。

ゆかりすたー METEOR のソースコードを公開

ニコカラ動画ファイルを番組名ごとなどで整理してリスト化し、ゆかり(持ち込みカラオケ用のブラウザリクエストツール)で検索しやすくするツール「ゆかりすたー METEOR」について、ソースコードを GitHub で公開しました。
ビルドには、別途公開している「SHINTA 共通 C# ライブラリー」なども必要です。詳しくは、ゆかりすたー METEOR ソースコードのリードミー(YukaLister_Src_ReadMe_JPN.txt)をご覧ください。

併せて、SHINTA 共通 C# ライブラリーも最新版のソースコードを公開しました。


ゆかりすたー METEOR Ver 1.35 β 公開

Meteorゆかりすたー METEOR(メテオ)の新バージョン、Ver 1.35 β を公開しました。

ゆかりすたー METEOR はニコカラ動画ファイルを整理し、「ゆかり」(持ち込みカラオケ用のブラウザリクエストツール)から検索できるようにするツールです。データベースを活用することにより、タイアップしている番組名や歌手名などの付加情報を含めて整理するので、単なるファイル名検索にとどまらない高い検索性を提供することができるようになります。

ゆかりすたー METEOR は、ニコカラりすたーおよび初代ゆかりすたーの後継ソフトとして開発しています。ニコカラりすたーは一時点でのリスト化機能のみを提供していましたが、ゆかりすたー METEOR は、ゆかりと連携した高度な検索性の提供を目的に、リアルタイムでのリスト化機能と検索用データベース構築機能を提供します。

更新内容

サムネイル作成機能を搭載しました。今後のゆかりでは、検索結果にサムネイルを表示する構想があるためです。

併せて、サーバー機能の変更・強化を行いました。

その他、細かい改善をしています。今回の更新内容を含む課題対応履歴についてはこちらをご覧ください。

Windows Defender について

Windows Defender がゆかりすたー METEOR の動作に悪影響を及ぼす場合があり、エラーが発生したり、処理速度が異常に遅くなったりする例が報告されています。

ゆかりすたー METEOR を使う際は、Windows Defender を使わないことをお薦めします。

詳細についてはこちらをご覧ください。

更新・新規インストール方法

ゆかりすたー METEOR は自動更新機能を搭載しています。既にゆかりすたー METEOR をお使いの方は、ゆかりすたー METEOR を起動すると、3 日以内に更新のアナウンスが表示されます。

すぐにアップデートしたい場合は、環境設定ウィンドウのメンテナンスタブを開き、「今すぐ最新情報を確認する」ボタンをクリックすることで、アップデートを開始することができます。

Ver150to168右のようなダイアログが表示されますので、「はい。今すぐ更新します」をクリックしてください。

ゆかりすたー更新版インストール画面に案内が表示されますので、案内に従って操作をして下さい。

ゆかりすたー更新完了ほどなくして、ゆかりすたー METEOR の更新が完了します。

これから初めてゆかりすたー METEOR を使う方(新規の方)や、手動でゆかりすたー METEOR を更新したい方は、下記サイトからどうぞ。

旧作について

ニコカラりすたーおよびゆかりすたー(初代)は開発を終了しました。

今後はゆかりすたー METEOR をご利用下さい。
カウンター


カンパのお願い
Amazon でお買い物の際は、下記で検索して頂けたら幸いです。
記事検索
最新コメント
  • ライブドアブログ