2014年5月15日木曜日

WPF で使うデータベース技術について

※ Entity Framework 6 + INotifyPropertyChanged の悩みでしたらこちらへ。

様々な方向性から検討した結果、次の構成に決めました:
  • データベースは、PostgreSQL 9.2を利用。
  • 画面・フロントエンドの構築は、WPFを利用。
  • データベースとの接続には、Npgsqlと、型指定の無いDataSet技術を利用。

Entity Frameworkとの決別

DataSet技術を使う前は、Entity Frameworkを使っていました。しかし、止めました。

Entity Frameworkを止めた理由とは:
  • テーブルの主キーを後から変更することができない
    『後から担当者IDを変更できないのは困る…』
  • 外部キー制約の制限。主キー以外でリレーションを構築できない。改善の要望が上がっています。
    『serial型の主キーを別途追加し、担当者IDはUnique制約にしておいて、それでリレーションを組もうか、ってできない!?』

そこで、Entity Frameworkの利用を断念致しました。

その後の模索等

VS Express版で開発しています。無条件に、金銭コストが掛からない方法を選んでいました。

どうしても手抜きがしたくて、SELECT/UPDATE/INSERT/DELETEの生成を自動化してくださるORMの手が欠かせません。

dapperも試しました。これはDBの更新ができないので、断念致しました。

VSのDataSet Designerも試しました。これは、DBの更新が簡略化できます。しかし、nullの扱いに難があるので、断念致しました。(Generatorが、Nullableを使ったコードを生成できないので、意図的にIsNull/SetNullを呼び出す必要が有る為)

DataSetとの邂逅

Visual Studioが如何様なコードを出力するのか、興味が有りました。DataSetとWPFがバインディングする際に。

すると、非常に気の利いたコードが生成されたのです。

こういう感じの事を実現するコードが生成されます。

(DataContext = CollectionViewSource)⇔DataTable

具体的には、次のコードが生成されました。
    <Window.Resources>
        <local:DataSet1 x:Key="dataSet1"/>
        <CollectionViewSource x:Key="dataTable1ViewSource" Source="{Binding DataTable1, Source={StaticResource dataSet1}}"/>
    </Window.Resources>

    <Grid DataContext="{StaticResource dataTable1ViewSource}">

    </Grid>

今回出現しましたCollectionViewSourceは、ナビゲーション機能付きです!

DataViewの、
  • 先頭(MoveCurrentToFirst)
  • 前(MoveCurrentToPrevious)
  • 次(MoveCurrentToNext)
  • 最後(MoveCurrentToLast)
  • 所定のDataRowViewに移動(MoveCurrentToPosition)
移動する機能が付いています。

これはいい!

具体的に、良いと思った点:
  • DataContextを変更しなくても良い。
    • ナビゲーション機能を実装しようとすると、DataContextを変更することを考えがちです。しかし、それをしなくても良い。
    • ずっと同じCollectionViewSourceを指して置くだけで良いのです。
  • 双方向Bindingができる。
    • MoveCurrentXXXした後、{Binding 担当者ID}と書いている部分は自動で更新されます。
    • TextBoxで、Text="{Binding 担当者ID}"にしている場合、Textを変更したらデータソース側も自動で更新されます。

※途中からDataTable系→DataView系に変化しています。そのような動きをしているので、そのように書いています ^^

という訳で、DataSet技術CollectionViewSourceの組み合わせて乗り切ることに決めました。

しかし、CollectionViewSource.Viewには、考慮が必要な難点もあります。ついでに:
  • 先頭よりも前に行くことができる。IsCurrentBeforeFirstで判定。
  • 最後よりも後に行くことができる。IsCurrentAfterLastで判定。
  • 先頭かどうかは、CurrentPosition == 0 で判定できるが、
  • 最後かどうかは、CurrentPosition == cvsItems.View.Cast<Object>().Count() 等、列挙してみないと数を勘定できない。

0 件のコメント:

コメントを投稿